summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>1997-11-18 15:06:00 +0100
committerWerner Koch <wk@gnupg.org>1997-11-18 15:06:00 +0100
commit5393dd53c5e06f0458949217317601b2eaed8350 (patch)
treec4b8d021851c32a611165c5fc215ad88604b5a94
parentNew repository initialized by cvs2svn. (diff)
downloadgnupg2-5393dd53c5e06f0458949217317601b2eaed8350.tar.xz
gnupg2-5393dd53c5e06f0458949217317601b2eaed8350.zip
initially checkin
-rw-r--r--AUTHORS0
-rw-r--r--COPYING340
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL0
-rw-r--r--Makefile.am12
-rw-r--r--Makefile.in261
-rw-r--r--NEWS0
-rw-r--r--README0
-rw-r--r--acconfig.h32
-rw-r--r--cipher/Makefile.am28
-rw-r--r--cipher/Makefile.in264
-rw-r--r--cipher/blowfish.c522
-rw-r--r--cipher/blowfish.h51
-rw-r--r--cipher/elgamal.c61
-rw-r--r--cipher/elgamal.h45
-rw-r--r--cipher/gost.c309
-rw-r--r--cipher/gost.h46
-rw-r--r--cipher/idea.c352
-rw-r--r--cipher/idea.h51
-rw-r--r--cipher/md5.c420
-rw-r--r--cipher/md5.h44
-rw-r--r--cipher/primegen.c152
-rw-r--r--cipher/random.c67
-rw-r--r--cipher/rmd.h51
-rw-r--r--cipher/rmd160.c375
-rw-r--r--cipher/rmd160test.c63
-rw-r--r--cipher/rsa.c191
-rw-r--r--cipher/rsa.h53
-rw-r--r--cipher/smallprime.c114
-rw-r--r--config.h.in60
-rw-r--r--configure.in54
-rw-r--r--g10/Makefile.am33
-rw-r--r--g10/Makefile.in285
-rw-r--r--g10/build-packet.c386
-rw-r--r--g10/checksig.c96
-rw-r--r--g10/compressed.c114
-rw-r--r--g10/encode.c470
-rw-r--r--g10/encr-data.c122
-rw-r--r--g10/filter.h35
-rw-r--r--g10/free-packet.c198
-rw-r--r--g10/g10.c219
-rw-r--r--g10/getkey.c475
-rw-r--r--g10/keydb.h45
-rw-r--r--g10/keygen.c253
-rw-r--r--g10/main.h35
-rw-r--r--g10/mainproc.c275
-rw-r--r--g10/mdfilter.c70
-rw-r--r--g10/options.h68
-rw-r--r--g10/overwrite.c79
-rw-r--r--g10/packet.h214
-rw-r--r--g10/parse-packet.c662
-rw-r--r--g10/passphrase.c126
-rw-r--r--g10/plaintext.c114
-rw-r--r--g10/pubkey-enc.c130
-rw-r--r--g10/seckey-cert.c157
-rw-r--r--g10/seskey.c101
-rw-r--r--g10/sig-check.c213
-rw-r--r--include/cipher.h87
-rw-r--r--include/errors.h52
-rw-r--r--include/iobuf.h120
-rw-r--r--include/memory.h64
-rw-r--r--include/mpi.h147
-rw-r--r--include/ttyio.h29
-rw-r--r--include/types.h76
-rw-r--r--include/util.h100
-rw-r--r--mpi/Makefile.am27
-rw-r--r--mpi/Makefile.in271
-rw-r--r--mpi/longlong.h1398
-rw-r--r--mpi/mpi-add.c221
-rw-r--r--mpi/mpi-bit.c133
-rw-r--r--mpi/mpi-cmp.c72
-rw-r--r--mpi/mpi-div.c282
-rw-r--r--mpi/mpi-gcd.c54
-rw-r--r--mpi/mpi-internal.h198
-rw-r--r--mpi/mpi-inv.c127
-rw-r--r--mpi/mpi-mul.c178
-rw-r--r--mpi/mpi-pow.c247
-rw-r--r--mpi/mpi-scan.c88
-rw-r--r--mpi/mpicoder.c392
-rw-r--r--mpi/mpih-add.c109
-rw-r--r--mpi/mpih-cmp.c53
-rw-r--r--mpi/mpih-div.c528
-rw-r--r--mpi/mpih-mul.c557
-rw-r--r--mpi/mpih-shift.c94
-rw-r--r--mpi/mpih-sub.c106
-rw-r--r--mpi/mpiutil.c326
-rwxr-xr-xscripts/install-sh250
-rwxr-xr-xscripts/mkinstalldirs40
-rw-r--r--stamp-h.in1
-rw-r--r--tools/Makefile.am12
-rw-r--r--tools/Makefile.in252
-rw-r--r--tools/bftest.c85
-rw-r--r--tools/mpicalc.c341
-rw-r--r--tools/primes.scm31
-rw-r--r--util/Makefile.am13
-rw-r--r--util/Makefile.in248
-rw-r--r--util/argparse.c653
-rw-r--r--util/errors.c69
-rw-r--r--util/fileutil.c31
-rw-r--r--util/iobuf.c762
-rw-r--r--util/logger.c139
-rw-r--r--util/memory.c460
-rw-r--r--util/miscutil.c33
-rw-r--r--util/strgutil.c63
-rw-r--r--util/ttyio.c114
105 files changed, 18726 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/AUTHORS
diff --git a/COPYING b/COPYING
new file mode 100644
index 000000000..2b7b643ff
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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) 19yy <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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) 19yy 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 Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/INSTALL
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 000000000..cfa9abb47
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,12 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = util mpi cipher tools g10
+EXTRA_DIST =
+
+
+
+tar: clean
+ cd ..; tar czvf ~/bkup/g10-`date +%d%m`.tar.gz src
+
+
+
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 000000000..934efce84
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,261 @@
+# Makefile.in generated automatically by automake 1.0 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+SUBDIRS = util mpi cipher tools g10
+EXTRA_DIST =
+ACCONFIG = acconfig.h
+CONFIG_HEADER_IN = config.h.in
+mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
+CONFIG_HEADER = ./config.h
+DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \
+Makefile.in NEWS README acconfig.h config.h.in configure configure.in \
+stamp-h.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA)
+DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA)
+
+TAR = tar
+default: all
+
+
+$(srcdir)/Makefile.in: Makefile.am configure.in
+ cd $(srcdir) && automake Makefile
+
+# For an explanation of the following Makefile rules, see node
+# `Automatic Remaking' in GNU Autoconf documentation.
+Makefile: Makefile.in config.status
+ CONFIG_FILES=$@ CONFIG_HEADERS= ./config.status
+config.status: configure
+ ./config.status --recheck
+$(srcdir)/configure: configure.in $(ACLOCAL) $(CONFIGURE_DEPENDENCIES)
+ cd $(srcdir) && autoconf
+
+$(CONFIG_HEADER): stamp-h
+stamp-h: $(CONFIG_HEADER_IN) config.status
+ CONFIG_FILES= CONFIG_HEADERS=$(CONFIG_HEADER) ./config.status
+ @echo timestamp > stamp-h
+$(srcdir)/$(CONFIG_HEADER_IN): stamp-h.in
+$(srcdir)/stamp-h.in: configure.in $(ACLOCAL) $(ACCONFIG) $(CONFIG_TOP) $(CONFIG_BOT)
+ cd $(srcdir) && autoheader
+ echo timestamp > $(srcdir)/stamp-h.in
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive \
+check-recursive installcheck-recursive info-recursive dvi-recursive \
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ for subdir in $(SUBDIRS); do \
+ target=`echo $@ | sed s/-recursive//`; \
+ echo making $$target in $$subdir; \
+ (cd $$subdir && $(MAKE) $$target) \
+ || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+
+tags: TAGS
+
+tags-recursive:
+ list="$(SUBDIRS)"; for subdir in $$list; do \
+ (cd $$subdir && $(MAKE) tags); \
+ done
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(CONFIG_HEADER) \
+ $(TAGS_DEPENDENCIES)
+ tags=; \
+ here=`pwd`; \
+ for subdir in $(SUBDIRS); do \
+ test -f $$subdir/TAGS && { \
+ tags="$$tags -i $$here/$$subdir/TAGS"; \
+ }; \
+ done; \
+ test -z "$(ETAGS_ARGS)$(CONFIG_HEADER)$(SOURCES)$(HEADERS)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $(CONFIG_HEADER) $(SOURCES) $(HEADERS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ rm -rf $(distdir)
+ $(TAR) zxf $(distdir).tar.gz
+ mkdir $(distdir)/=build
+ mkdir $(distdir)/=inst
+ dc_install_base=`cd $(distdir)/=inst && pwd`; \
+ cd $(distdir)/=build \
+ && ../configure --srcdir=.. --prefix=$$dc_install_base \
+ && $(MAKE) \
+ && $(MAKE) check \
+ && $(MAKE) install \
+ && $(MAKE) installcheck \
+ && $(MAKE) dist
+ rm -rf $(distdir)
+ @echo "========================"; \
+ echo "$(distdir).tar.gz is ready for distribution"; \
+ echo "========================"
+dist: distdir
+ chmod -R a+r $(distdir)
+ $(TAR) chozf $(distdir).tar.gz $(distdir)
+ rm -rf $(distdir)
+distdir: $(DEP_DISTFILES)
+ rm -rf $(distdir)
+ mkdir $(distdir)
+ chmod 777 $(distdir)
+ distdir=`cd $(distdir) && pwd` \
+ && cd $(srcdir) \
+ && automake --include-deps --output-dir=$$distdir --strictness=gnu
+ @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \
+ test -f $(distdir)/$$file \
+ || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $(srcdir)/$$file $(distdir)/$$file; \
+ done
+ for subdir in $(SUBDIRS); do \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ chmod 777 $(distdir)/$$subdir; \
+ (cd $$subdir && $(MAKE) distdir=../$(distdir)/$$subdir distdir) \
+ || exit 1; \
+ done
+info: info-recursive
+
+dvi: dvi-recursive
+
+check: check-recursive
+
+installcheck: installcheck-recursive
+
+all-recursive-hack: $(CONFIG_HEADER)
+ $(MAKE) all-recursive
+
+all-am: Makefile config.h
+
+install-exec: install-exec-recursive
+
+install-data: install-data-recursive
+
+install: install-recursive
+ @:
+
+uninstall: uninstall-recursive
+
+all: all-recursive-hack all-am
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
+installdirs: installdirs-recursive
+
+
+mostlyclean-generic:
+ test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ rm -f Makefile $(DISTCLEANFILES)
+ rm -f config.cache config.log $(CONFIG_HEADER) stamp-h
+
+maintainer-clean-generic:
+ test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean-am: mostlyclean-tags mostlyclean-generic
+
+clean-am: clean-tags clean-generic mostlyclean-am
+
+distclean-am: distclean-tags distclean-generic clean-am
+
+maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \
+ distclean-am
+
+mostlyclean: mostlyclean-am mostlyclean-recursive
+
+clean: clean-am clean-recursive
+
+distclean: distclean-am distclean-recursive
+ rm -f config.status
+
+maintainer-clean: maintainer-clean-am maintainer-clean-recursive
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+ rm -f config.status
+
+.PHONY: default install-data-recursive uninstall-data-recursive \
+install-exec-recursive uninstall-exec-recursive installdirs-recursive \
+uninstalldirs-recursive all-recursive check-recursive \
+installcheck-recursive info-recursive dvi-recursive \
+mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info dvi check \
+installcheck all-recursive-hack all-am install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+tar: clean
+ cd ..; tar czvf ~/bkup/g10-`date +%d%m`.tar.gz src
+.SUFFIXES:
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/README
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 000000000..01aab2a6a
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,32 @@
+/* acconfig.h - used by autoheader to make config.h.in
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_CONFIG_H
+#define G10_CONFIG_H
+
+
+@@TOP@@
+
+#undef M_DEBUG
+#undef VERSION
+#undef PACKAGE
+
+@@BOTTOM@@
+
+#endif /*G10_CONFIG_H*/
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
new file mode 100644
index 000000000..8a543e380
--- /dev/null
+++ b/cipher/Makefile.am
@@ -0,0 +1,28 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LIBRARIES = cipher
+
+
+cipher_SOURCES = blowfish.c \
+ blowfish.h \
+ elgamal.c \
+ elgamal.h \
+ gost.c \
+ gost.h \
+ idea.c \
+ idea.h \
+ md5.c \
+ md5.h \
+ primegen.c \
+ random.c \
+ ripemd.h \
+ rmd.h \
+ rmd160.c \
+ rsa.c \
+ rsa.h \
+ smallprime.c
+
+
+
diff --git a/cipher/Makefile.in b/cipher/Makefile.in
new file mode 100644
index 000000000..faee770be
--- /dev/null
+++ b/cipher/Makefile.in
@@ -0,0 +1,264 @@
+# Makefile.in generated automatically by automake 1.0 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LIBRARIES = cipher
+
+cipher_SOURCES = blowfish.c \
+ blowfish.h \
+ elgamal.c \
+ elgamal.h \
+ gost.c \
+ gost.h \
+ idea.c \
+ idea.h \
+ md5.c \
+ md5.h \
+ primegen.c \
+ random.c \
+ ripemd.h \
+ rmd.h \
+ rmd160.c \
+ rsa.c \
+ rsa.h \
+ smallprime.c
+mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
+CONFIG_HEADER = ../config.h
+LIBRARIES = $(noinst_LIBRARIES)
+
+noinst_LIBFILES = libcipher.a
+
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+cipher_LIBADD =
+cipher_OBJECTS = blowfish.o elgamal.o gost.o idea.o md5.o primegen.o \
+random.o rmd160.o rsa.o smallprime.o
+EXTRA_cipher_SOURCES =
+LIBFILES = libcipher.a
+AR = ar
+RANLIB = @RANLIB@
+DIST_COMMON = Makefile.am Makefile.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA)
+DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA)
+
+TAR = tar
+DEP_FILES = $(srcdir)/.deps/blowfish.P $(srcdir)/.deps/elgamal.P \
+$(srcdir)/.deps/gost.P $(srcdir)/.deps/idea.P $(srcdir)/.deps/md5.P \
+$(srcdir)/.deps/primegen.P $(srcdir)/.deps/random.P \
+$(srcdir)/.deps/rmd160.P $(srcdir)/.deps/rsa.P \
+$(srcdir)/.deps/smallprime.P
+SOURCES = $(cipher_SOURCES)
+OBJECTS = $(cipher_OBJECTS)
+
+default: all
+
+
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+ cd $(top_srcdir) && automake $(subdir)/Makefile
+
+Makefile: $(top_builddir)/config.status Makefile.in
+ cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+ rm -f $(noinst_LIBFILES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+ $(COMPILE) $<
+
+mostlyclean-compile:
+ rm -f *.o core
+
+clean-compile:
+
+distclean-compile:
+ rm -f *.tab.c
+
+maintainer-clean-compile:
+$(cipher_OBJECTS): ../config.h
+
+libcipher.a: $(cipher_OBJECTS) $(cipher_LIBADD)
+ rm -f libcipher.a
+ $(AR) cru libcipher.a $(cipher_OBJECTS) $(cipher_LIBADD)
+ $(RANLIB) libcipher.a
+
+ID: $(HEADERS) $(SOURCES)
+ here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
+
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
+ here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ rm -f TAGS ID
+
+maintainer-clean-tags:
+
+subdir = cipher
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+distdir: $(DEP_DISTFILES)
+ @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \
+ test -f $(distdir)/$$file \
+ || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $(srcdir)/$$file $(distdir)/$$file; \
+ done
+
+# This fragment is probably only useful for maintainers. It relies on
+# GNU make and gcc. It is only included in the generated Makefile.in
+# if `automake' is not passed the `--include-deps' flag.
+
+MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+-include $(srcdir)/.deps/.P
+$(srcdir)/.deps/.P: $(BUILT_SOURCES)
+ cd $(srcdir) && test -d .deps || mkdir .deps
+ echo > $@
+
+-include $(DEP_FILES)
+$(DEP_FILES): $(srcdir)/.deps/.P
+
+$(srcdir)/.deps/%.P: $(srcdir)/%.c
+ @echo "mkdeps $< > $@"
+ @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \
+ $(MKDEP) $< | sed "$$re" > $@-tmp
+ @if test -n "$o"; then \
+ sed 's/\.o:/$$o:/' $@-tmp > $@; \
+ rm $@-tmp; \
+ else \
+ mv $@-tmp $@; \
+ fi
+
+# End of maintainer-only section
+info:
+
+dvi:
+
+check: all
+
+installcheck:
+
+install-exec:
+
+install-data:
+
+install: install-exec install-data all
+ @:
+
+uninstall:
+
+all: $(LIBFILES) Makefile
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
+installdirs:
+
+
+mostlyclean-generic:
+ test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ rm -f Makefile $(DISTCLEANFILES)
+ rm -f config.cache config.log $(CONFIG_HEADER) stamp-h
+
+maintainer-clean-generic:
+ test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+ mostlyclean
+
+distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \
+ distclean-generic clean
+ rm -f config.status
+
+maintainer-clean: maintainer-clean-noinstLIBRARIES \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info dvi check installcheck \
+install-exec install-data install uninstall all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/cipher/blowfish.c b/cipher/blowfish.c
new file mode 100644
index 000000000..59f1afa8c
--- /dev/null
+++ b/cipher/blowfish.c
@@ -0,0 +1,522 @@
+/* blowfish.c - Blowfish encryption
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * For a description of the algorithm, see:
+ * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
+ * ISBN 0-471-11709-9. Pages 336 ff.
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "types.h"
+#include "blowfish.h"
+
+/* precomputed S boxes */
+static const u32 ks0[256] = {
+ 0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96,
+ 0xBA7C9045,0xF12C7F99,0x24A19947,0xB3916CF7,0x0801F2E2,0x858EFC16,
+ 0x636920D8,0x71574E69,0xA458FEA3,0xF4933D7E,0x0D95748F,0x728EB658,
+ 0x718BCD58,0x82154AEE,0x7B54A41D,0xC25A59B5,0x9C30D539,0x2AF26013,
+ 0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E,
+ 0x6C9E0E8B,0xB01E8A3E,0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60,
+ 0xE65525F3,0xAA55AB94,0x57489862,0x63E81440,0x55CA396A,0x2AAB10B6,
+ 0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993,0xB3EE1411,0x636FBC2A,
+ 0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C,
+ 0x7A325381,0x28958677,0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193,
+ 0x61D809CC,0xFB21A991,0x487CAC60,0x5DEC8032,0xEF845D5D,0xE98575B1,
+ 0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5,0x0F6D6FF3,0x83F44239,
+ 0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A,
+ 0x670C9C61,0xABD388F0,0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3,
+ 0x6EEF0B6C,0x137A3BE4,0xBA3BF050,0x7EFB2A98,0xA1F1651D,0x39AF0176,
+ 0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4,0x7D84A5C3,0x3B8B5EBE,
+ 0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706,
+ 0x1BFEDF72,0x429B023D,0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B,
+ 0x075372C9,0x80991B7B,0x25D479D8,0xF6E8DEF7,0xE3FE501A,0xB6794C3B,
+ 0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4,0x5E5C9EC2,0x196A2463,
+ 0x68FB6FAF,0x3E6C53B5,0x1339B2EB,0x3B52EC6F,0x6DFC511F,0x9B30952C,
+ 0xCC814544,0xAF5EBD09,0xBEE3D004,0xDE334AFD,0x660F2807,0x192E4BB3,
+ 0xC0CBA857,0x45C8740F,0xD20B5F39,0xB9D3FBDB,0x5579C0BD,0x1A60320A,
+ 0xD6A100C6,0x402C7279,0x679F25FE,0xFB1FA3CC,0x8EA5E9F8,0xDB3222F8,
+ 0x3C7516DF,0xFD616B15,0x2F501EC8,0xAD0552AB,0x323DB5FA,0xFD238760,
+ 0x53317B48,0x3E00DF82,0x9E5C57BB,0xCA6F8CA0,0x1A87562E,0xDF1769DB,
+ 0xD542A8F6,0x287EFFC3,0xAC6732C6,0x8C4F5573,0x695B27B0,0xBBCA58C8,
+ 0xE1FFA35D,0xB8F011A0,0x10FA3D98,0xFD2183B8,0x4AFCB56C,0x2DD1D35B,
+ 0x9A53E479,0xB6F84565,0xD28E49BC,0x4BFB9790,0xE1DDF2DA,0xA4CB7E33,
+ 0x62FB1341,0xCEE4C6E8,0xEF20CADA,0x36774C01,0xD07E9EFE,0x2BF11FB4,
+ 0x95DBDA4D,0xAE909198,0xEAAD8E71,0x6B93D5A0,0xD08ED1D0,0xAFC725E0,
+ 0x8E3C5B2F,0x8E7594B7,0x8FF6E2FB,0xF2122B64,0x8888B812,0x900DF01C,
+ 0x4FAD5EA0,0x688FC31C,0xD1CFF191,0xB3A8C1AD,0x2F2F2218,0xBE0E1777,
+ 0xEA752DFE,0x8B021FA1,0xE5A0CC0F,0xB56F74E8,0x18ACF3D6,0xCE89E299,
+ 0xB4A84FE0,0xFD13E0B7,0x7CC43B81,0xD2ADA8D9,0x165FA266,0x80957705,
+ 0x93CC7314,0x211A1477,0xE6AD2065,0x77B5FA86,0xC75442F5,0xFB9D35CF,
+ 0xEBCDAF0C,0x7B3E89A0,0xD6411BD3,0xAE1E7E49,0x00250E2D,0x2071B35E,
+ 0x226800BB,0x57B8E0AF,0x2464369B,0xF009B91E,0x5563911D,0x59DFA6AA,
+ 0x78C14389,0xD95A537F,0x207D5BA2,0x02E5B9C5,0x83260376,0x6295CFA9,
+ 0x11C81968,0x4E734A41,0xB3472DCA,0x7B14A94A,0x1B510052,0x9A532915,
+ 0xD60F573F,0xBC9BC6E4,0x2B60A476,0x81E67400,0x08BA6FB5,0x571BE91F,
+ 0xF296EC6B,0x2A0DD915,0xB6636521,0xE7B9F9B6,0xFF34052E,0xC5855664,
+ 0x53B02D5D,0xA99F8FA1,0x08BA4799,0x6E85076A };
+
+static const u32 ks1[256] = {
+ 0x4B7A70E9,0xB5B32944,0xDB75092E,0xC4192623,0xAD6EA6B0,0x49A7DF7D,
+ 0x9CEE60B8,0x8FEDB266,0xECAA8C71,0x699A17FF,0x5664526C,0xC2B19EE1,
+ 0x193602A5,0x75094C29,0xA0591340,0xE4183A3E,0x3F54989A,0x5B429D65,
+ 0x6B8FE4D6,0x99F73FD6,0xA1D29C07,0xEFE830F5,0x4D2D38E6,0xF0255DC1,
+ 0x4CDD2086,0x8470EB26,0x6382E9C6,0x021ECC5E,0x09686B3F,0x3EBAEFC9,
+ 0x3C971814,0x6B6A70A1,0x687F3584,0x52A0E286,0xB79C5305,0xAA500737,
+ 0x3E07841C,0x7FDEAE5C,0x8E7D44EC,0x5716F2B8,0xB03ADA37,0xF0500C0D,
+ 0xF01C1F04,0x0200B3FF,0xAE0CF51A,0x3CB574B2,0x25837A58,0xDC0921BD,
+ 0xD19113F9,0x7CA92FF6,0x94324773,0x22F54701,0x3AE5E581,0x37C2DADC,
+ 0xC8B57634,0x9AF3DDA7,0xA9446146,0x0FD0030E,0xECC8C73E,0xA4751E41,
+ 0xE238CD99,0x3BEA0E2F,0x3280BBA1,0x183EB331,0x4E548B38,0x4F6DB908,
+ 0x6F420D03,0xF60A04BF,0x2CB81290,0x24977C79,0x5679B072,0xBCAF89AF,
+ 0xDE9A771F,0xD9930810,0xB38BAE12,0xDCCF3F2E,0x5512721F,0x2E6B7124,
+ 0x501ADDE6,0x9F84CD87,0x7A584718,0x7408DA17,0xBC9F9ABC,0xE94B7D8C,
+ 0xEC7AEC3A,0xDB851DFA,0x63094366,0xC464C3D2,0xEF1C1847,0x3215D908,
+ 0xDD433B37,0x24C2BA16,0x12A14D43,0x2A65C451,0x50940002,0x133AE4DD,
+ 0x71DFF89E,0x10314E55,0x81AC77D6,0x5F11199B,0x043556F1,0xD7A3C76B,
+ 0x3C11183B,0x5924A509,0xF28FE6ED,0x97F1FBFA,0x9EBABF2C,0x1E153C6E,
+ 0x86E34570,0xEAE96FB1,0x860E5E0A,0x5A3E2AB3,0x771FE71C,0x4E3D06FA,
+ 0x2965DCB9,0x99E71D0F,0x803E89D6,0x5266C825,0x2E4CC978,0x9C10B36A,
+ 0xC6150EBA,0x94E2EA78,0xA5FC3C53,0x1E0A2DF4,0xF2F74EA7,0x361D2B3D,
+ 0x1939260F,0x19C27960,0x5223A708,0xF71312B6,0xEBADFE6E,0xEAC31F66,
+ 0xE3BC4595,0xA67BC883,0xB17F37D1,0x018CFF28,0xC332DDEF,0xBE6C5AA5,
+ 0x65582185,0x68AB9802,0xEECEA50F,0xDB2F953B,0x2AEF7DAD,0x5B6E2F84,
+ 0x1521B628,0x29076170,0xECDD4775,0x619F1510,0x13CCA830,0xEB61BD96,
+ 0x0334FE1E,0xAA0363CF,0xB5735C90,0x4C70A239,0xD59E9E0B,0xCBAADE14,
+ 0xEECC86BC,0x60622CA7,0x9CAB5CAB,0xB2F3846E,0x648B1EAF,0x19BDF0CA,
+ 0xA02369B9,0x655ABB50,0x40685A32,0x3C2AB4B3,0x319EE9D5,0xC021B8F7,
+ 0x9B540B19,0x875FA099,0x95F7997E,0x623D7DA8,0xF837889A,0x97E32D77,
+ 0x11ED935F,0x16681281,0x0E358829,0xC7E61FD6,0x96DEDFA1,0x7858BA99,
+ 0x57F584A5,0x1B227263,0x9B83C3FF,0x1AC24696,0xCDB30AEB,0x532E3054,
+ 0x8FD948E4,0x6DBC3128,0x58EBF2EF,0x34C6FFEA,0xFE28ED61,0xEE7C3C73,
+ 0x5D4A14D9,0xE864B7E3,0x42105D14,0x203E13E0,0x45EEE2B6,0xA3AAABEA,
+ 0xDB6C4F15,0xFACB4FD0,0xC742F442,0xEF6ABBB5,0x654F3B1D,0x41CD2105,
+ 0xD81E799E,0x86854DC7,0xE44B476A,0x3D816250,0xCF62A1F2,0x5B8D2646,
+ 0xFC8883A0,0xC1C7B6A3,0x7F1524C3,0x69CB7492,0x47848A0B,0x5692B285,
+ 0x095BBF00,0xAD19489D,0x1462B174,0x23820E00,0x58428D2A,0x0C55F5EA,
+ 0x1DADF43E,0x233F7061,0x3372F092,0x8D937E41,0xD65FECF1,0x6C223BDB,
+ 0x7CDE3759,0xCBEE7460,0x4085F2A7,0xCE77326E,0xA6078084,0x19F8509E,
+ 0xE8EFD855,0x61D99735,0xA969A7AA,0xC50C06C2,0x5A04ABFC,0x800BCADC,
+ 0x9E447A2E,0xC3453484,0xFDD56705,0x0E1E9EC9,0xDB73DBD3,0x105588CD,
+ 0x675FDA79,0xE3674340,0xC5C43465,0x713E38D8,0x3D28F89E,0xF16DFF20,
+ 0x153E21E7,0x8FB03D4A,0xE6E39F2B,0xDB83ADF7 };
+
+static const u32 ks2[256] = {
+ 0xE93D5A68,0x948140F7,0xF64C261C,0x94692934,0x411520F7,0x7602D4F7,
+ 0xBCF46B2E,0xD4A20068,0xD4082471,0x3320F46A,0x43B7D4B7,0x500061AF,
+ 0x1E39F62E,0x97244546,0x14214F74,0xBF8B8840,0x4D95FC1D,0x96B591AF,
+ 0x70F4DDD3,0x66A02F45,0xBFBC09EC,0x03BD9785,0x7FAC6DD0,0x31CB8504,
+ 0x96EB27B3,0x55FD3941,0xDA2547E6,0xABCA0A9A,0x28507825,0x530429F4,
+ 0x0A2C86DA,0xE9B66DFB,0x68DC1462,0xD7486900,0x680EC0A4,0x27A18DEE,
+ 0x4F3FFEA2,0xE887AD8C,0xB58CE006,0x7AF4D6B6,0xAACE1E7C,0xD3375FEC,
+ 0xCE78A399,0x406B2A42,0x20FE9E35,0xD9F385B9,0xEE39D7AB,0x3B124E8B,
+ 0x1DC9FAF7,0x4B6D1856,0x26A36631,0xEAE397B2,0x3A6EFA74,0xDD5B4332,
+ 0x6841E7F7,0xCA7820FB,0xFB0AF54E,0xD8FEB397,0x454056AC,0xBA489527,
+ 0x55533A3A,0x20838D87,0xFE6BA9B7,0xD096954B,0x55A867BC,0xA1159A58,
+ 0xCCA92963,0x99E1DB33,0xA62A4A56,0x3F3125F9,0x5EF47E1C,0x9029317C,
+ 0xFDF8E802,0x04272F70,0x80BB155C,0x05282CE3,0x95C11548,0xE4C66D22,
+ 0x48C1133F,0xC70F86DC,0x07F9C9EE,0x41041F0F,0x404779A4,0x5D886E17,
+ 0x325F51EB,0xD59BC0D1,0xF2BCC18F,0x41113564,0x257B7834,0x602A9C60,
+ 0xDFF8E8A3,0x1F636C1B,0x0E12B4C2,0x02E1329E,0xAF664FD1,0xCAD18115,
+ 0x6B2395E0,0x333E92E1,0x3B240B62,0xEEBEB922,0x85B2A20E,0xE6BA0D99,
+ 0xDE720C8C,0x2DA2F728,0xD0127845,0x95B794FD,0x647D0862,0xE7CCF5F0,
+ 0x5449A36F,0x877D48FA,0xC39DFD27,0xF33E8D1E,0x0A476341,0x992EFF74,
+ 0x3A6F6EAB,0xF4F8FD37,0xA812DC60,0xA1EBDDF8,0x991BE14C,0xDB6E6B0D,
+ 0xC67B5510,0x6D672C37,0x2765D43B,0xDCD0E804,0xF1290DC7,0xCC00FFA3,
+ 0xB5390F92,0x690FED0B,0x667B9FFB,0xCEDB7D9C,0xA091CF0B,0xD9155EA3,
+ 0xBB132F88,0x515BAD24,0x7B9479BF,0x763BD6EB,0x37392EB3,0xCC115979,
+ 0x8026E297,0xF42E312D,0x6842ADA7,0xC66A2B3B,0x12754CCC,0x782EF11C,
+ 0x6A124237,0xB79251E7,0x06A1BBE6,0x4BFB6350,0x1A6B1018,0x11CAEDFA,
+ 0x3D25BDD8,0xE2E1C3C9,0x44421659,0x0A121386,0xD90CEC6E,0xD5ABEA2A,
+ 0x64AF674E,0xDA86A85F,0xBEBFE988,0x64E4C3FE,0x9DBC8057,0xF0F7C086,
+ 0x60787BF8,0x6003604D,0xD1FD8346,0xF6381FB0,0x7745AE04,0xD736FCCC,
+ 0x83426B33,0xF01EAB71,0xB0804187,0x3C005E5F,0x77A057BE,0xBDE8AE24,
+ 0x55464299,0xBF582E61,0x4E58F48F,0xF2DDFDA2,0xF474EF38,0x8789BDC2,
+ 0x5366F9C3,0xC8B38E74,0xB475F255,0x46FCD9B9,0x7AEB2661,0x8B1DDF84,
+ 0x846A0E79,0x915F95E2,0x466E598E,0x20B45770,0x8CD55591,0xC902DE4C,
+ 0xB90BACE1,0xBB8205D0,0x11A86248,0x7574A99E,0xB77F19B6,0xE0A9DC09,
+ 0x662D09A1,0xC4324633,0xE85A1F02,0x09F0BE8C,0x4A99A025,0x1D6EFE10,
+ 0x1AB93D1D,0x0BA5A4DF,0xA186F20F,0x2868F169,0xDCB7DA83,0x573906FE,
+ 0xA1E2CE9B,0x4FCD7F52,0x50115E01,0xA70683FA,0xA002B5C4,0x0DE6D027,
+ 0x9AF88C27,0x773F8641,0xC3604C06,0x61A806B5,0xF0177A28,0xC0F586E0,
+ 0x006058AA,0x30DC7D62,0x11E69ED7,0x2338EA63,0x53C2DD94,0xC2C21634,
+ 0xBBCBEE56,0x90BCB6DE,0xEBFC7DA1,0xCE591D76,0x6F05E409,0x4B7C0188,
+ 0x39720A3D,0x7C927C24,0x86E3725F,0x724D9DB9,0x1AC15BB4,0xD39EB8FC,
+ 0xED545578,0x08FCA5B5,0xD83D7CD3,0x4DAD0FC4,0x1E50EF5E,0xB161E6F8,
+ 0xA28514D9,0x6C51133C,0x6FD5C7E7,0x56E14EC4,0x362ABFCE,0xDDC6C837,
+ 0xD79A3234,0x92638212,0x670EFA8E,0x406000E0 };
+
+static const u32 ks3[256] = {
+ 0x3A39CE37,0xD3FAF5CF,0xABC27737,0x5AC52D1B,0x5CB0679E,0x4FA33742,
+ 0xD3822740,0x99BC9BBE,0xD5118E9D,0xBF0F7315,0xD62D1C7E,0xC700C47B,
+ 0xB78C1B6B,0x21A19045,0xB26EB1BE,0x6A366EB4,0x5748AB2F,0xBC946E79,
+ 0xC6A376D2,0x6549C2C8,0x530FF8EE,0x468DDE7D,0xD5730A1D,0x4CD04DC6,
+ 0x2939BBDB,0xA9BA4650,0xAC9526E8,0xBE5EE304,0xA1FAD5F0,0x6A2D519A,
+ 0x63EF8CE2,0x9A86EE22,0xC089C2B8,0x43242EF6,0xA51E03AA,0x9CF2D0A4,
+ 0x83C061BA,0x9BE96A4D,0x8FE51550,0xBA645BD6,0x2826A2F9,0xA73A3AE1,
+ 0x4BA99586,0xEF5562E9,0xC72FEFD3,0xF752F7DA,0x3F046F69,0x77FA0A59,
+ 0x80E4A915,0x87B08601,0x9B09E6AD,0x3B3EE593,0xE990FD5A,0x9E34D797,
+ 0x2CF0B7D9,0x022B8B51,0x96D5AC3A,0x017DA67D,0xD1CF3ED6,0x7C7D2D28,
+ 0x1F9F25CF,0xADF2B89B,0x5AD6B472,0x5A88F54C,0xE029AC71,0xE019A5E6,
+ 0x47B0ACFD,0xED93FA9B,0xE8D3C48D,0x283B57CC,0xF8D56629,0x79132E28,
+ 0x785F0191,0xED756055,0xF7960E44,0xE3D35E8C,0x15056DD4,0x88F46DBA,
+ 0x03A16125,0x0564F0BD,0xC3EB9E15,0x3C9057A2,0x97271AEC,0xA93A072A,
+ 0x1B3F6D9B,0x1E6321F5,0xF59C66FB,0x26DCF319,0x7533D928,0xB155FDF5,
+ 0x03563482,0x8ABA3CBB,0x28517711,0xC20AD9F8,0xABCC5167,0xCCAD925F,
+ 0x4DE81751,0x3830DC8E,0x379D5862,0x9320F991,0xEA7A90C2,0xFB3E7BCE,
+ 0x5121CE64,0x774FBE32,0xA8B6E37E,0xC3293D46,0x48DE5369,0x6413E680,
+ 0xA2AE0810,0xDD6DB224,0x69852DFD,0x09072166,0xB39A460A,0x6445C0DD,
+ 0x586CDECF,0x1C20C8AE,0x5BBEF7DD,0x1B588D40,0xCCD2017F,0x6BB4E3BB,
+ 0xDDA26A7E,0x3A59FF45,0x3E350A44,0xBCB4CDD5,0x72EACEA8,0xFA6484BB,
+ 0x8D6612AE,0xBF3C6F47,0xD29BE463,0x542F5D9E,0xAEC2771B,0xF64E6370,
+ 0x740E0D8D,0xE75B1357,0xF8721671,0xAF537D5D,0x4040CB08,0x4EB4E2CC,
+ 0x34D2466A,0x0115AF84,0xE1B00428,0x95983A1D,0x06B89FB4,0xCE6EA048,
+ 0x6F3F3B82,0x3520AB82,0x011A1D4B,0x277227F8,0x611560B1,0xE7933FDC,
+ 0xBB3A792B,0x344525BD,0xA08839E1,0x51CE794B,0x2F32C9B7,0xA01FBAC9,
+ 0xE01CC87E,0xBCC7D1F6,0xCF0111C3,0xA1E8AAC7,0x1A908749,0xD44FBD9A,
+ 0xD0DADECB,0xD50ADA38,0x0339C32A,0xC6913667,0x8DF9317C,0xE0B12B4F,
+ 0xF79E59B7,0x43F5BB3A,0xF2D519FF,0x27D9459C,0xBF97222C,0x15E6FC2A,
+ 0x0F91FC71,0x9B941525,0xFAE59361,0xCEB69CEB,0xC2A86459,0x12BAA8D1,
+ 0xB6C1075E,0xE3056A0C,0x10D25065,0xCB03A442,0xE0EC6E0E,0x1698DB3B,
+ 0x4C98A0BE,0x3278E964,0x9F1F9532,0xE0D392DF,0xD3A0342B,0x8971F21E,
+ 0x1B0A7441,0x4BA3348C,0xC5BE7120,0xC37632D8,0xDF359F8D,0x9B992F2E,
+ 0xE60B6F47,0x0FE3F11D,0xE54CDA54,0x1EDAD891,0xCE6279CF,0xCD3E7E6F,
+ 0x1618B166,0xFD2C1D05,0x848FD2C5,0xF6FB2299,0xF523F357,0xA6327623,
+ 0x93A83531,0x56CCCD02,0xACF08162,0x5A75EBB5,0x6E163697,0x88D273CC,
+ 0xDE966292,0x81B949D0,0x4C50901B,0x71C65614,0xE6C6C7BD,0x327A140A,
+ 0x45E1D006,0xC3F27B9A,0xC9AA53FD,0x62A80F00,0xBB25BFE2,0x35BDD2F6,
+ 0x71126905,0xB2040222,0xB6CBCF7C,0xCD769C2B,0x53113EC0,0x1640E3D3,
+ 0x38ABBD60,0x2547ADF0,0xBA38209C,0xF746CE76,0x77AFA1C5,0x20756060,
+ 0x85CBFE4E,0x8AE88DD8,0x7AAAF9B0,0x4CF9AA7E,0x1948C25C,0x02FB8A8C,
+ 0x01C36AE4,0xD6EBE1F9,0x90D4F869,0xA65CDEA0,0x3F09252D,0xC208E69F,
+ 0xB74E6132,0xCE77E25B,0x578FDFE3,0x3AC372E6 };
+
+static const u32 ps[BLOWFISH_ROUNDS+2] = {
+ 0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0,
+ 0x082EFA98,0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C,
+ 0xC0AC29B7,0xC97C50DD,0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B };
+
+
+
+
+
+static u32
+function_F( BLOWFISH_context *bc, u32 x )
+{
+ u16 a, b, c, d, y;
+
+ d = x & 0x00ff;
+ x >>= 8;
+ c = x & 0x00ff;
+ x >>= 8;
+ b = x & 0x00ff;
+ x >>= 8;
+ a = x & 0x00ff;
+ y = bc->s0[a] + bc->s1[b];
+ y ^= bc->s2[c];
+ y += bc->s3[d];
+
+ return y;
+}
+
+
+static void
+encipher( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
+{
+ u32 xl, xr, temp;
+ int i;
+
+ xl = *ret_xl;
+ xr = *ret_xr;
+
+ for(i=0; i < BLOWFISH_ROUNDS; i++ ) {
+ xl ^= bc->p[i];
+ xr ^= function_F(bc, xl);
+ temp = xl;
+ xl = xr;
+ xr = temp;
+ }
+
+ temp = xl;
+ xl = xr;
+ xr = temp;
+
+ xr ^= bc->p[BLOWFISH_ROUNDS];
+ xl ^= bc->p[BLOWFISH_ROUNDS+1];
+
+ *ret_xl = xl;
+ *ret_xr = xr;
+}
+
+static void
+decipher( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
+{
+ u32 xl, xr, temp;
+ int i;
+
+ xl = *ret_xl;
+ xr = *ret_xr;
+
+ for(i=BLOWFISH_ROUNDS+1; i > 1; i-- ) {
+ xl ^= bc->p[i];
+ xr ^= function_F(bc, xl);
+ temp = xl;
+ xl = xr;
+ xr = temp;
+ }
+
+ temp = xl;
+ xl = xr;
+ xr = temp;
+
+ xr ^= bc->p[1];
+ xl ^= bc->p[0];
+
+ *ret_xl = xl;
+ *ret_xr = xr;
+}
+
+static void
+encipher_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
+{
+ u32 d1, d2;
+
+ d1 = ((u32*)inbuf)[0];
+ d2 = ((u32*)inbuf)[1];
+ encipher( bc, &d1, &d2 );
+ ((u32*)outbuf)[0] = d1;
+ ((u32*)outbuf)[1] = d2;
+}
+
+static void
+decipher_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
+{
+ u32 d1, d2;
+
+ d1 = ((u32*)inbuf)[0];
+ d2 = ((u32*)inbuf)[1];
+ decipher( bc, &d1, &d2 );
+ ((u32*)outbuf)[0] = d1;
+ ((u32*)outbuf)[1] = d2;
+}
+
+
+void
+blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
+{
+ int i, j, k;
+ u32 data, datal, datar;
+
+ for(i=0; i < BLOWFISH_ROUNDS+2; i++ )
+ c->p[i] = ps[i];
+ for(i=0; i < 256; i++ ) {
+ c->s0[i] = ks0[i];
+ c->s1[i] = ks1[i];
+ c->s2[i] = ks2[i];
+ c->s3[i] = ks3[i];
+ }
+
+ for(i=j=0; i < BLOWFISH_ROUNDS+2; i++ ) {
+ data = 0;
+ for(k=0; k < 4; k++) {
+ data = (data << 8) | key[j];
+ if( ++j >= keylen )
+ j = 0;
+ }
+ c->p[i] ^= data;
+ }
+
+ datal = datar = 0;
+ for(i=0; i < BLOWFISH_ROUNDS+2; i += 2 ) {
+ encipher( c, &datal, &datar );
+ c->p[i] = datal;
+ c->p[i+1] = datar;
+ }
+ for(i=0; i < 256; i += 2 ) {
+ encipher( c, &datal, &datar );
+ c->s0[i] = datal;
+ c->s0[i+1] = datar;
+ }
+ for(i=0; i < 256; i += 2 ) {
+ encipher( c, &datal, &datar );
+ c->s1[i] = datal;
+ c->s1[i+1] = datar;
+ }
+ for(i=0; i < 256; i += 2 ) {
+ encipher( c, &datal, &datar );
+ c->s2[i] = datal;
+ c->s2[i+1] = datar;
+ }
+ for(i=0; i < 256; i += 2 ) {
+ encipher( c, &datal, &datar );
+ c->s3[i] = datal;
+ c->s3[i+1] = datar;
+ }
+}
+
+
+void
+blowfish_setiv( BLOWFISH_context *c, byte *iv )
+{
+ if( iv )
+ memcpy( c->iv, iv, BLOWFISH_BLOCKSIZE );
+ else
+ memset( c->iv, 0, BLOWFISH_BLOCKSIZE );
+ c->count = 0;
+ encipher_block( c, c->eniv, c->iv );
+}
+
+
+void
+blowfish_encode( BLOWFISH_context *c, byte *outbuf, byte *inbuf,
+ unsigned nblocks )
+{
+ unsigned n;
+
+ for(n=0; n < nblocks; n++ ) {
+ encipher_block( c, outbuf, inbuf );
+ inbuf += BLOWFISH_BLOCKSIZE;;
+ outbuf += BLOWFISH_BLOCKSIZE;
+ }
+}
+
+void
+blowfish_decode( BLOWFISH_context *c, byte *outbuf, byte *inbuf,
+ unsigned nblocks )
+{
+ unsigned n;
+
+ for(n=0; n < nblocks; n++ ) {
+ decipher_block( c, outbuf, inbuf );
+ inbuf += BLOWFISH_BLOCKSIZE;;
+ outbuf += BLOWFISH_BLOCKSIZE;
+ }
+}
+
+
+
+/****************
+ * FIXME: Make use of bigger chunks
+ * (out may overlap with a or b)
+ */
+static void
+xorblock( byte *out, byte *a, byte *b, unsigned count )
+{
+ for( ; count ; count--, a++, b++ )
+ *out++ = *a ^ *b ;
+}
+
+
+
+/****************
+ * Encode buffer in CFB mode. nbytes can be an arbitrary value.
+ */
+void
+blowfish_encode_cfb( BLOWFISH_context *c, byte *outbuf,
+ byte *inbuf, unsigned nbytes)
+{
+ unsigned n;
+
+ if( c->count ) { /* must make a full block first */
+ assert( c->count < BLOWFISH_BLOCKSIZE );
+ n = BLOWFISH_BLOCKSIZE - c->count;
+ if( n > nbytes )
+ n = nbytes;
+ xorblock( outbuf, c->eniv+c->count, inbuf, n);
+ memcpy( c->iv+c->count, outbuf, n);
+ c->count += n;
+ nbytes -= n;
+ inbuf += n;
+ outbuf += n;
+ assert( c->count <= BLOWFISH_BLOCKSIZE);
+ if( c->count == BLOWFISH_BLOCKSIZE ) {
+ encipher_block( c, c->eniv, c->iv );
+ c->count = 0;
+ }
+ else
+ return;
+ }
+ assert(!c->count);
+ while( nbytes >= BLOWFISH_BLOCKSIZE ) {
+ xorblock( outbuf, c->eniv, inbuf, BLOWFISH_BLOCKSIZE);
+ memcpy( c->iv, outbuf, BLOWFISH_BLOCKSIZE);
+ encipher_block( c, c->eniv, c->iv );
+ nbytes -= BLOWFISH_BLOCKSIZE;
+ inbuf += BLOWFISH_BLOCKSIZE;
+ outbuf += BLOWFISH_BLOCKSIZE;
+ }
+
+ if( nbytes ) {
+ xorblock( outbuf, c->eniv, inbuf, nbytes );
+ memcpy( c->iv, outbuf, nbytes );
+ c->count = nbytes;
+ }
+
+}
+
+
+void
+blowfish_decode_cfb( BLOWFISH_context *c, byte *outbuf,
+ byte *inbuf, unsigned nbytes)
+{
+ unsigned n;
+
+ if( c->count ) { /* must make a full block first */
+ assert( c->count < BLOWFISH_BLOCKSIZE );
+ n = BLOWFISH_BLOCKSIZE - c->count;
+ if( n > nbytes )
+ n = nbytes;
+ memcpy( c->iv+c->count, inbuf, n);
+ xorblock( outbuf, c->eniv+c->count, inbuf, n);
+ c->count += n;
+ nbytes -= n;
+ inbuf += n;
+ outbuf += n;
+ assert( c->count <= BLOWFISH_BLOCKSIZE);
+ if( c->count == BLOWFISH_BLOCKSIZE ) {
+ encipher_block( c, c->eniv, c->iv );
+ c->count = 0;
+ }
+ else
+ return;
+ }
+
+ assert(!c->count);
+ while( nbytes >= BLOWFISH_BLOCKSIZE ) {
+ memcpy( c->iv, inbuf, BLOWFISH_BLOCKSIZE);
+ xorblock( outbuf, c->eniv, inbuf, BLOWFISH_BLOCKSIZE);
+ encipher_block( c, c->eniv, c->iv );
+ nbytes -= BLOWFISH_BLOCKSIZE;
+ inbuf += BLOWFISH_BLOCKSIZE;
+ outbuf += BLOWFISH_BLOCKSIZE;
+ }
+
+ if( nbytes ) {
+ memcpy( c->iv, inbuf, nbytes );
+ xorblock( outbuf, c->eniv, inbuf, nbytes );
+ c->count = nbytes;
+ }
+
+}
+
diff --git a/cipher/blowfish.h b/cipher/blowfish.h
new file mode 100644
index 000000000..3b01f5263
--- /dev/null
+++ b/cipher/blowfish.h
@@ -0,0 +1,51 @@
+/* blowfish.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_BLOWFISH_H
+#define G10_BLOWFISH_H
+
+#include "types.h"
+
+#define BLOWFISH_BLOCKSIZE 8
+#define BLOWFISH_ROUNDS 16
+
+typedef struct {
+ u32 s0[256];
+ u32 s1[256];
+ u32 s2[256];
+ u32 s3[256];
+ u32 p[BLOWFISH_ROUNDS+2];
+ byte iv[BLOWFISH_BLOCKSIZE];
+ byte eniv[BLOWFISH_BLOCKSIZE];
+ int count;
+} BLOWFISH_context;
+
+void blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen );
+void blowfish_setiv( BLOWFISH_context *c, byte *iv );
+void blowfish_encode( BLOWFISH_context *c, byte *outbuf, byte *inbuf,
+ unsigned nblocks );
+void blowfish_decode( BLOWFISH_context *c, byte *outbuf, byte *inbuf,
+ unsigned nblocks );
+void blowfish_encode_cfb( BLOWFISH_context *c, byte *outbuf,
+ byte *inbuf, unsigned nbytes);
+void blowfish_decode_cfb( BLOWFISH_context *c, byte *outbuf,
+ byte *inbuf, unsigned nbytes);
+
+
+#endif /*G10_BLOWFISH_H*/
diff --git a/cipher/elgamal.c b/cipher/elgamal.c
new file mode 100644
index 000000000..305e1db92
--- /dev/null
+++ b/cipher/elgamal.c
@@ -0,0 +1,61 @@
+/* elgamal.c - ElGamal Public Key encryption
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * For a description of the algorithm, see:
+ * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
+ * ISBN 0-471-11709-9. Pages 476 ff.
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "util.h"
+#include "mpi.h"
+#include "elgamal.h"
+
+
+/****************
+ * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT.
+ *
+ *
+ *
+ * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY.
+ */
+void
+elg_public(MPI output, MPI input, ELG_public_key *pkey )
+{
+
+}
+
+/****************
+ * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT.
+ *
+ *
+ *
+ * Where m is OUTPUT, c is INPUT and d,n are elements of PKEY.
+ */
+void
+elg_secret(MPI output, MPI input, ELG_secret_key *skey )
+{
+
+}
+
+
+
diff --git a/cipher/elgamal.h b/cipher/elgamal.h
new file mode 100644
index 000000000..3b6317599
--- /dev/null
+++ b/cipher/elgamal.h
@@ -0,0 +1,45 @@
+/* elgamal.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_ELGAMAL_H
+#define G10_ELGAMAL_H
+
+#include "mpi.h"
+
+typedef struct {
+ MPI e; /* exponent */
+ MPI n; /* modulus */
+} ELG_public_key;
+
+
+typedef struct {
+ MPI e; /* public exponent */
+ MPI n; /* public modulus */
+ MPI p; /* prime p. */
+ MPI q; /* prime q. */
+ MPI d; /* exponent */
+ MPI u; /* inverse of p mod q. */
+} ELG_secret_key;
+
+
+void elg_public(MPI output, MPI input, ELG_public_key *skey );
+void elg_secret(MPI output, MPI input, ELG_secret_key *skey );
+
+
+#endif /*G10_ELGAMAL_H*/
diff --git a/cipher/gost.c b/cipher/gost.c
new file mode 100644
index 000000000..21b63cbc9
--- /dev/null
+++ b/cipher/gost.c
@@ -0,0 +1,309 @@
+/* gost.c - GOST encryption
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * The description of GOST (and the used S-boxes) are taken from:
+ * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
+ * ISBN 0-471-11709-9. .
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "util.h"
+#include "types.h"
+#include "gost.h"
+
+
+
+static u16
+mul_inv( u16 x )
+{
+ u16 t0, t1;
+ u16 q, y;
+
+ if( x < 2 )
+ return x;
+ t1 = 0x10001L / x;
+ y = 0x10001L % x;
+ if( y == 1 )
+ return (1-t1) & 0xffff;
+
+ t0 = 1;
+ do {
+ q = x / y;
+ x = x % y;
+ t0 += q * t1;
+ if( x == 1 )
+ return t0;
+ q = y / x;
+ y = y % x;
+ t1 += q * t0;
+ } while( y != 1 );
+ return (1-t1) & 0xffff;
+}
+
+
+
+static void
+expand_key( byte *userkey, u16 *ek )
+{
+ int i,j;
+
+ for(j=0; j < 8; j++ ) {
+ ek[j] = (*userkey << 8) + userkey[1];
+ userkey += 2;
+ }
+ for(i=0; j < GOST_KEYLEN; j++ ) {
+ i++;
+ ek[i+7] = ek[i&7] << 9 | ek[(i+1)&7] >> 7;
+ ek += i & 8;
+ i &= 7;
+ }
+}
+
+
+static void
+invert_key( u16 *ek, u16 dk[GOST_KEYLEN] )
+{
+ int i;
+ u16 t1, t2, t3;
+ u16 temp[GOST_KEYLEN];
+ u16 *p = temp + GOST_KEYLEN;
+
+ t1 = mul_inv( *ek++ );
+ t2 = -*ek++;
+ t3 = -*ek++;
+ *--p = mul_inv( *ek++ );
+ *--p = t3;
+ *--p = t2;
+ *--p = t1;
+
+ for(i=0; i < GOST_ROUNDS-1; i++ ) {
+ t1 = *ek++;
+ *--p = *ek++;
+ *--p = t1;
+
+ t1 = mul_inv( *ek++ );
+ t2 = -*ek++;
+ t3 = -*ek++;
+ *--p = mul_inv( *ek++ );
+ *--p = t3;
+ *--p = t2;
+ *--p = t1;
+ }
+ t1 = *ek++;
+ *--p = *ek++;
+ *--p = t1;
+
+ t1 = mul_inv( *ek++ );
+ t2 = -*ek++;
+ t3 = -*ek++;
+ *--p = mul_inv( *ek++ );
+ *--p = t3;
+ *--p = t2;
+ *--p = t1;
+ memcpy(dk, temp, sizeof(temp) );
+ memset(temp, 0, sizeof(temp) ); /* burn temp */
+}
+
+
+static void
+cipher( byte *inbuf, byte *outbuf, u16 *key )
+{
+ u16 x1, x2, x3,x4, s2, s3;
+ u16 *in, *out;
+ int r = GOST_ROUNDS;
+ #define MUL(x,y) \
+ do {u16 _t16; u32 _t32; \
+ if( (_t16 = (y)) ) { \
+ if( (x = (x)&0xffff) ) { \
+ _t32 = (u32)x * _t16; \
+ x = _t32 & 0xffff; \
+ _t16 = _t32 >> 16; \
+ x = ((x)-_t16) + (x<_t16?1:0); \
+ } \
+ else { \
+ x = 1 - _t16; \
+ } \
+ } \
+ else { \
+ x = 1 - x; \
+ } \
+ } while(0)
+
+ in = (u16*)inbuf;
+ x1 = *in++;
+ x2 = *in++;
+ x3 = *in++;
+ x4 = *in;
+ #ifdef HAVE_LITTLE_ENDIAN
+ x1 = (x1>>8) | (x1<<8);
+ x2 = (x2>>8) | (x2<<8);
+ x3 = (x3>>8) | (x3<<8);
+ x4 = (x4>>8) | (x4<<8);
+ #endif
+ do {
+ MUL(x1, *key++);
+ x2 += *key++;
+ x3 += *key++;
+ MUL(x4, *key++ );
+
+ s3 = x3;
+ x3 ^= x1;
+ MUL(x3, *key++);
+ s2 = x2;
+ x2 ^=x4;
+ x2 += x3;
+ MUL(x2, *key++);
+ x3 += x2;
+
+ x1 ^= x2;
+ x4 ^= x3;
+
+ x2 ^= s3;
+ x3 ^= s2;
+ } while( --r );
+ MUL(x1, *key++);
+ x3 += *key++;
+ x2 += *key++;
+ MUL(x4, *key);
+
+ out = (u16*)outbuf;
+ #ifdef HAVE_LITTLE_ENDIAN
+ *out++ = (x1>>8) | (x1<<8);
+ *out++ = (x3>>8) | (x3<<8);
+ *out++ = (x2>>8) | (x2<<8);
+ *out = (x4>>8) | (x4<<8);
+ #else
+ *out++ = x1;
+ *out++ = x3;
+ *out++ = x2;
+ *out = x4;
+ #endif
+ #undef MUL
+}
+
+
+void
+gost_setkey( GOST_context *c, byte *key )
+{
+ expand_key( key, c->ek );
+ invert_key( c->ek, c->dk );
+}
+
+void
+gost_setiv( GOST_context *c, byte *iv )
+{
+ memcpy( c->iv, iv, GOST_BLOCKSIZE );
+}
+
+
+void
+gost_encode( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nblocks )
+{
+ unsigned n;
+
+ for(n=0; n < nblocks; n++ ) {
+ cipher( inbuf, outbuf, c->ek );
+ inbuf += 8;
+ outbuf += 8;
+ }
+}
+
+
+void
+gost_decode( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nblocks )
+{
+ unsigned n;
+
+ for(n=0; n < nblocks; n++ ) {
+ cipher( inbuf, outbuf, c->dk );
+ inbuf += 8;
+ outbuf += 8;
+ }
+}
+
+
+static void
+cfbshift( byte *iv, byte *buf, unsigned count)
+{
+ unsigned n;
+
+ if( count ) {
+ for( n = GOST_BLOCKSIZE - count; n; n--, iv++ )
+ *iv = iv[count];
+ for( ; count; count-- )
+ *iv++ = *buf++;
+ }
+}
+
+
+/****************
+ * FIXME: Make use of bigger chunks
+ */
+static void
+xorblock( byte *out, byte *a, byte *b, unsigned count )
+{
+ for( ; count ; count--, a++, b++ )
+ *out++ = *a ^ *b ;
+}
+
+
+void
+gost_encode_cfb( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nbytes)
+{
+ byte temp[GOST_BLOCKSIZE];
+
+ while( nbytes >= GOST_BLOCKSIZE ) {
+ cipher( c->iv, temp, c->ek );
+ xorblock( outbuf, inbuf, temp, GOST_BLOCKSIZE);
+ cfbshift( c->iv, outbuf, GOST_BLOCKSIZE );
+ nbytes -= GOST_BLOCKSIZE;
+ inbuf += GOST_BLOCKSIZE;
+ outbuf += GOST_BLOCKSIZE;
+ }
+ if( nbytes ) {
+ cipher( c->iv, temp, c->ek );
+ xorblock( outbuf, inbuf, temp, nbytes );
+ cfbshift( c->iv, outbuf, nbytes );
+ }
+}
+
+
+void
+gost_decode_cfb( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nbytes)
+{
+ byte temp[GOST_BLOCKSIZE];
+
+ while( nbytes >= GOST_BLOCKSIZE ) {
+ cipher( c->iv, temp, c->ek );
+ cfbshift( c->iv, inbuf, GOST_BLOCKSIZE );
+ xorblock( outbuf, inbuf, temp, GOST_BLOCKSIZE);
+ nbytes -= GOST_BLOCKSIZE;
+ inbuf += GOST_BLOCKSIZE;
+ outbuf += GOST_BLOCKSIZE;
+ }
+ if( nbytes ) {
+ cipher( c->iv, temp, c->ek );
+ cfbshift( c->iv, inbuf, nbytes );
+ xorblock( outbuf, inbuf, temp, nbytes );
+ }
+}
+
diff --git a/cipher/gost.h b/cipher/gost.h
new file mode 100644
index 000000000..d0f4186e3
--- /dev/null
+++ b/cipher/gost.h
@@ -0,0 +1,46 @@
+/* gost.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_GOST_H
+#define G10_GOST_H
+
+#include "types.h"
+
+#define GOST_KEYSIZE 16
+#define GOST_BLOCKSIZE 8
+#define GOST_ROUNDS 8
+#define GOST_KEYLEN (6*GOST_ROUNDS+4)
+
+typedef struct {
+ u16 ek[GOST_KEYLEN];
+ u16 dk[GOST_KEYLEN];
+ byte iv[GOST_BLOCKSIZE];
+} GOST_context;
+
+void gost_setkey( GOST_context *c, byte *key );
+void gost_setiv( GOST_context *c, byte *iv );
+void gost_encode( GOST_context *c, byte *out, byte *in, unsigned nblocks );
+void gost_decode( GOST_context *c, byte *out, byte *in, unsigned nblocks );
+void gost_encode_cfb( GOST_context *c, byte *outbuf,
+ byte *inbuf, unsigned nbytes);
+void gost_decode_cfb( GOST_context *c, byte *outbuf,
+ byte *inbuf, unsigned nbytes);
+
+
+#endif /*G10_GOST_H*/
diff --git a/cipher/idea.c b/cipher/idea.c
new file mode 100644
index 000000000..3d1b01a98
--- /dev/null
+++ b/cipher/idea.c
@@ -0,0 +1,352 @@
+/* idea.c - IDEA function
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * ATTENTION: This code patented and needs a license for any commercial use.
+ *
+ * The code herin is take from:
+ * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
+ * ISBN 0-471-11709-9. .
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "util.h"
+#include "types.h"
+#include "idea.h"
+
+
+
+static u16
+mul_inv( u16 x )
+{
+ u16 t0, t1;
+ u16 q, y;
+
+ if( x < 2 )
+ return x;
+ t1 = 0x10001L / x;
+ y = 0x10001L % x;
+ if( y == 1 )
+ return (1-t1) & 0xffff;
+
+ t0 = 1;
+ do {
+ q = x / y;
+ x = x % y;
+ t0 += q * t1;
+ if( x == 1 )
+ return t0;
+ q = y / x;
+ y = y % x;
+ t1 += q * t0;
+ } while( y != 1 );
+ return (1-t1) & 0xffff;
+}
+
+
+
+static void
+expand_key( byte *userkey, u16 *ek )
+{
+ int i,j;
+
+ for(j=0; j < 8; j++ ) {
+ ek[j] = (*userkey << 8) + userkey[1];
+ userkey += 2;
+ }
+ for(i=0; j < IDEA_KEYLEN; j++ ) {
+ i++;
+ ek[i+7] = ek[i&7] << 9 | ek[(i+1)&7] >> 7;
+ ek += i & 8;
+ i &= 7;
+ }
+}
+
+
+static void
+invert_key( u16 *ek, u16 dk[IDEA_KEYLEN] )
+{
+ int i;
+ u16 t1, t2, t3;
+ u16 temp[IDEA_KEYLEN];
+ u16 *p = temp + IDEA_KEYLEN;
+
+ t1 = mul_inv( *ek++ );
+ t2 = -*ek++;
+ t3 = -*ek++;
+ *--p = mul_inv( *ek++ );
+ *--p = t3;
+ *--p = t2;
+ *--p = t1;
+
+ for(i=0; i < IDEA_ROUNDS-1; i++ ) {
+ t1 = *ek++;
+ *--p = *ek++;
+ *--p = t1;
+
+ t1 = mul_inv( *ek++ );
+ t2 = -*ek++;
+ t3 = -*ek++;
+ *--p = mul_inv( *ek++ );
+ *--p = t3;
+ *--p = t2;
+ *--p = t1;
+ }
+ t1 = *ek++;
+ *--p = *ek++;
+ *--p = t1;
+
+ t1 = mul_inv( *ek++ );
+ t2 = -*ek++;
+ t3 = -*ek++;
+ *--p = mul_inv( *ek++ );
+ *--p = t3;
+ *--p = t2;
+ *--p = t1;
+ memcpy(dk, temp, sizeof(temp) );
+ memset(temp, 0, sizeof(temp) ); /* burn temp */
+}
+
+
+static void
+cipher( byte *outbuf, byte *inbuf, u16 *key )
+{
+ u16 x1, x2, x3,x4, s2, s3;
+ u16 *in, *out;
+ int r = IDEA_ROUNDS;
+ #define MUL(x,y) \
+ do {u16 _t16; u32 _t32; \
+ if( (_t16 = (y)) ) { \
+ if( (x = (x)&0xffff) ) { \
+ _t32 = (u32)x * _t16; \
+ x = _t32 & 0xffff; \
+ _t16 = _t32 >> 16; \
+ x = ((x)-_t16) + (x<_t16?1:0); \
+ } \
+ else { \
+ x = 1 - _t16; \
+ } \
+ } \
+ else { \
+ x = 1 - x; \
+ } \
+ } while(0)
+
+ in = (u16*)inbuf;
+ x1 = *in++;
+ x2 = *in++;
+ x3 = *in++;
+ x4 = *in;
+ #ifdef HAVE_LITTLE_ENDIAN
+ x1 = (x1>>8) | (x1<<8);
+ x2 = (x2>>8) | (x2<<8);
+ x3 = (x3>>8) | (x3<<8);
+ x4 = (x4>>8) | (x4<<8);
+ #endif
+ do {
+ MUL(x1, *key++);
+ x2 += *key++;
+ x3 += *key++;
+ MUL(x4, *key++ );
+
+ s3 = x3;
+ x3 ^= x1;
+ MUL(x3, *key++);
+ s2 = x2;
+ x2 ^=x4;
+ x2 += x3;
+ MUL(x2, *key++);
+ x3 += x2;
+
+ x1 ^= x2;
+ x4 ^= x3;
+
+ x2 ^= s3;
+ x3 ^= s2;
+ } while( --r );
+ MUL(x1, *key++);
+ x3 += *key++;
+ x2 += *key++;
+ MUL(x4, *key);
+
+ out = (u16*)outbuf;
+ #ifdef HAVE_LITTLE_ENDIAN
+ *out++ = (x1>>8) | (x1<<8);
+ *out++ = (x3>>8) | (x3<<8);
+ *out++ = (x2>>8) | (x2<<8);
+ *out = (x4>>8) | (x4<<8);
+ #else
+ *out++ = x1;
+ *out++ = x3;
+ *out++ = x2;
+ *out = x4;
+ #endif
+ #undef MUL
+}
+
+
+void
+idea_setkey( IDEA_context *c, byte *key )
+{
+ expand_key( key, c->ek );
+ invert_key( c->ek, c->dk );
+}
+
+void
+idea_setiv( IDEA_context *c, byte *iv )
+{
+ if( iv )
+ memcpy( c->iv, iv, IDEA_BLOCKSIZE );
+ else
+ memset( c->iv, 0, IDEA_BLOCKSIZE );
+ c->nleft = 0;
+}
+
+
+void
+idea_encode( IDEA_context *c, byte *outbuf, byte *inbuf, unsigned nblocks )
+{
+ unsigned n;
+
+ for(n=0; n < nblocks; n++ ) {
+ cipher( outbuf, inbuf, c->ek );
+ inbuf += 8;
+ outbuf += 8;
+ }
+}
+
+
+void
+idea_decode( IDEA_context *c, byte *outbuf, byte *inbuf, unsigned nblocks )
+{
+ unsigned n;
+
+ for(n=0; n < nblocks; n++ ) {
+ cipher( outbuf, inbuf, c->dk );
+ inbuf += 8;
+ outbuf += 8;
+ }
+}
+
+
+static void
+cfbshift( byte *iv, byte *buf, unsigned count)
+{
+ unsigned n;
+
+ if( count ) {
+ for( n = IDEA_BLOCKSIZE - count; n; n-- )
+ *iv++ = iv[count];
+ for( ; count; count-- )
+ *iv++ = *buf++;
+ }
+}
+
+
+/****************
+ * FIXME: Make use of bigger chunks
+ */
+static void
+xorblock( byte *out, byte *a, byte *b, unsigned count )
+{
+ for( ; count ; count--, a++, b++ )
+ *out++ = *a ^ *b ;
+}
+
+
+void
+idea_encode_cfb( IDEA_context *c, byte *outbuf, byte *inbuf, unsigned nbytes)
+{
+ byte temp[IDEA_BLOCKSIZE];
+
+ while( nbytes >= IDEA_BLOCKSIZE ) {
+ cipher( temp, c->iv, c->ek );
+ xorblock( outbuf, inbuf, temp, IDEA_BLOCKSIZE);
+ cfbshift( c->iv, outbuf, IDEA_BLOCKSIZE );
+ nbytes -= IDEA_BLOCKSIZE;
+ inbuf += IDEA_BLOCKSIZE;
+ outbuf += IDEA_BLOCKSIZE;
+ }
+ if( nbytes ) {
+ cipher( temp, c->iv, c->ek );
+ xorblock( outbuf, inbuf, temp, nbytes );
+ cfbshift( c->iv, outbuf, nbytes );
+ }
+}
+
+
+void
+idea_decode_cfb( IDEA_context *c, byte *outbuf, byte *inbuf, unsigned nbytes)
+{
+ byte t, *ivptr;
+
+ ivptr = c->iv + IDEA_BLOCKSIZE - c->nleft;
+ if( nbytes <= c->nleft ) {
+ c->nleft -= nbytes;
+ for( ; nbytes ; nbytes--, ivptr++, inbuf++ ) {
+ t = *ivptr;
+ *outbuf++ = t ^ (*ivptr = *inbuf) ;
+ }
+ return;
+ }
+
+ nbytes -= c->nleft;
+ for( ; c->nleft ; c->nleft--, ivptr++, inbuf++ ) {
+ t = *ivptr;
+ *outbuf++ = t ^ (*ivptr = *inbuf) ;
+ }
+
+ while( nbytes >= IDEA_BLOCKSIZE ) {
+ memcpy(c->lastcipher, c->iv, IDEA_BLOCKSIZE);
+ cipher( c->iv, c->iv, c->ek );
+ c->nleft = IDEA_BLOCKSIZE;
+ nbytes -= IDEA_BLOCKSIZE;
+ ivptr = c->iv;
+ for( ; c->nleft; c->nleft--, ivptr++, inbuf++ ) {
+ t = *ivptr;
+ *outbuf++ = t ^ (*ivptr = *inbuf) ;
+ }
+ }
+ memcpy(c->lastcipher, c->iv, IDEA_BLOCKSIZE);
+ cipher( c->iv, c->iv, c->ek );
+ c->nleft = IDEA_BLOCKSIZE - nbytes;
+ ivptr = c->iv;
+ for( ; nbytes; nbytes--, ivptr++, inbuf++ ) {
+ t = *ivptr;
+ *outbuf++ = t ^ (*ivptr = *inbuf) ;
+ }
+}
+
+
+/****************
+ * This is used for the special way IDEA CFB is used in PGP
+ */
+void
+idea_sync_cfb( IDEA_context *c )
+{
+ if( c->nleft ) {
+ memmove(c->iv + c->nleft, c->iv, IDEA_BLOCKSIZE - c->nleft );
+ memcpy(c->iv, c->lastcipher + IDEA_BLOCKSIZE - c->nleft, c->nleft);
+ c->nleft = 0;
+ }
+}
+
+
diff --git a/cipher/idea.h b/cipher/idea.h
new file mode 100644
index 000000000..efebf5a56
--- /dev/null
+++ b/cipher/idea.h
@@ -0,0 +1,51 @@
+/* idea.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * ATTENTION: This code patented and needs a license for any commercial use.
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_IDEA_H
+#define G10_IDEA_H
+
+#include "types.h"
+
+#define IDEA_KEYSIZE 16
+#define IDEA_BLOCKSIZE 8
+#define IDEA_ROUNDS 8
+#define IDEA_KEYLEN (6*IDEA_ROUNDS+4)
+
+typedef struct {
+ u16 ek[IDEA_KEYLEN];
+ u16 dk[IDEA_KEYLEN];
+ byte iv[IDEA_BLOCKSIZE];
+ byte lastcipher[IDEA_BLOCKSIZE];
+ int nleft;
+} IDEA_context;
+
+void idea_setkey( IDEA_context *c, byte *key );
+void idea_setiv( IDEA_context *c, byte *iv );
+void idea_encode( IDEA_context *c, byte *out, byte *in, unsigned nblocks );
+void idea_decode( IDEA_context *c, byte *out, byte *in, unsigned nblocks );
+void idea_encode_cfb( IDEA_context *c, byte *outbuf,
+ byte *inbuf, unsigned nbytes);
+void idea_decode_cfb( IDEA_context *c, byte *outbuf,
+ byte *inbuf, unsigned nbytes);
+void idea_sync_cfb( IDEA_context *c );
+
+
+#endif /*G10_IDEA_H*/
diff --git a/cipher/md5.c b/cipher/md5.c
new file mode 100644
index 000000000..98429ab77
--- /dev/null
+++ b/cipher/md5.c
@@ -0,0 +1,420 @@
+/* md5.c - MD5 Message-Digest Algorithm
+ * Copyright (c) 1994 by Werner Koch (dd9jn)
+ *
+ * This is a hacked version from WkLib
+ *
+ * This file is part of WkLib.
+ *
+ * WkLib 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.
+ *
+ * WkLib 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ *
+ * History:
+ * 16.01.95 wk now uses generic base-64 support
+ * 24.01.95 wk changed back to original base-64 coding, because
+ * the generic base-64 support was changed to go conform
+ * with RFC1113 !
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "md5.h"
+#include "memory.h"
+
+
+#if __WATCOMC__ && defined(M_I86)
+ /* 16-Bit Compiler breaks Code in Function Transform() */
+ /* (at least when compiling for windows) */
+ #ifndef __SW_OD
+ #error must be compiled without optimizations
+ #endif
+#endif
+
+
+static void Init( MD5HANDLE mdContext);
+static void Transform(u32 *buf,u32 *in);
+
+static byte PADDING[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+ {(a) += F ((b), (c), (d)) + (x) + (u32)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) \
+ {(a) += G ((b), (c), (d)) + (x) + (u32)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) \
+ {(a) += H ((b), (c), (d)) + (x) + (u32)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) \
+ {(a) += I ((b), (c), (d)) + (x) + (u32)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* The routine Init initializes the message-digest context
+ * mdContext. All fields are set to zero.
+ * mode should be zero is reserved for extensions.
+ */
+
+MD5HANDLE
+md5_open(int secure)
+{
+ MD5HANDLE mdContext;
+
+ mdContext = secure? m_alloc_secure( sizeof *mdContext )
+ : m_alloc( sizeof *mdContext );
+ Init(mdContext);
+ return mdContext;
+}
+
+
+MD5HANDLE
+md5_copy( MD5HANDLE a )
+{
+ MD5HANDLE mdContext;
+
+ assert(a);
+ mdContext = m_is_secure(a)? m_alloc_secure( sizeof *mdContext )
+ : m_alloc( sizeof *mdContext );
+ memcpy( mdContext, a, sizeof *a );
+ return mdContext;
+}
+
+void
+md5_close(MD5HANDLE hd)
+{
+ if( hd )
+ m_free(hd);
+}
+
+
+static void
+Init( MD5HANDLE mdContext)
+{
+ mdContext->i[0] = mdContext->i[1] = (u32)0;
+ /* Load magic initialization constants.
+ */
+ mdContext->buf[0] = (u32)0x67452301L;
+ mdContext->buf[1] = (u32)0xefcdab89L;
+ mdContext->buf[2] = (u32)0x98badcfeL;
+ mdContext->buf[3] = (u32)0x10325476L;
+ mdContext->bufcount = 0;
+}
+
+/* The routine Update updates the message-digest context to
+ * account for the presence of each of the characters inBuf[0..inLen-1]
+ * in the message whose digest is being computed.
+ */
+void
+md5_write( MD5HANDLE mdContext, byte *inBuf, size_t inLen)
+{
+ register int i, ii;
+ int mdi;
+ u32 in[16];
+
+ if(mdContext->bufcount) { /* flush the buffer */
+ i = mdContext->bufcount;
+ mdContext->bufcount = 0;
+ md5_write( mdContext, mdContext->digest, i);
+ }
+ if( !inBuf )
+ return;
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* update number of bits */
+ if((mdContext->i[0] + ((u32)inLen << 3)) < mdContext->i[0])
+ mdContext->i[1]++;
+ mdContext->i[0] += ((u32)inLen << 3);
+ mdContext->i[1] += ((u32)inLen >> 29);
+
+ while(inLen--) {
+ /* add new character to buffer, increment mdi */
+ mdContext->in[mdi++] = *inBuf++;
+
+ /* transform if necessary */
+ if( mdi == 0x40 ) {
+ for(i = 0, ii = 0; i < 16; i++, ii += 4)
+ in[i] = (((u32)mdContext->in[ii+3]) << 24) |
+ (((u32)mdContext->in[ii+2]) << 16) |
+ (((u32)mdContext->in[ii+1]) << 8) |
+ ((u32)mdContext->in[ii]);
+ Transform(mdContext->buf, in);
+ mdi = 0;
+ }
+ }
+}
+
+
+/****************
+ * Process a single character, this character will be buffered to
+ * increase performance. The digest-field is used as a buffer.
+ */
+
+void
+md5_putchar( MD5HANDLE mdContext, int c )
+{
+ if(mdContext->bufcount == 16)
+ md5_write( mdContext, NULL, 0 );
+ mdContext->digest[mdContext->bufcount++] = c & 0xff;
+}
+
+
+
+/* The routine final terminates the message-digest computation and
+ * ends with the desired message digest in mdContext->digest[0...15].
+ * The handle is prepared for a new MD5 cycle.
+ * Returns 16 bytes representing the digest.
+ */
+
+void
+md5_final(MD5HANDLE mdContext)
+{
+ u32 in[16];
+ int mdi;
+ unsigned int i, ii;
+ unsigned int padLen;
+
+ if(mdContext->bufcount) /* flush buffer */
+ md5_write(mdContext, NULL, 0 );
+ /* save number of bits */
+ in[14] = mdContext->i[0];
+ in[15] = mdContext->i[1];
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* pad out to 56 mod 64 */
+ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+ md5_write(mdContext, PADDING, padLen);
+
+ /* append length in bits and transform */
+ for(i = 0, ii = 0; i < 14; i++, ii += 4)
+ in[i] = (((u32)mdContext->in[ii+3]) << 24) |
+ (((u32)mdContext->in[ii+2]) << 16) |
+ (((u32)mdContext->in[ii+1]) << 8) |
+ ((u32)mdContext->in[ii]);
+ Transform(mdContext->buf, in);
+
+ /* store buffer in digest */
+ for(i = 0, ii = 0; i < 4; i++, ii += 4) {
+ mdContext->digest[ii] = (byte)(mdContext->buf[i] & 0xFF);
+ mdContext->digest[ii+1] = (byte)((mdContext->buf[i] >> 8) & 0xFF);
+ mdContext->digest[ii+2] = (byte)((mdContext->buf[i] >> 16) & 0xFF);
+ mdContext->digest[ii+3] = (byte)((mdContext->buf[i] >> 24) & 0xFF);
+ }
+ Init(mdContext);
+}
+
+/**********
+ * Returns 16 bytes representing the digest.
+ */
+byte *
+md5_read(MD5HANDLE mdContext)
+{
+ return mdContext->digest;
+}
+
+
+
+/****************
+ * Converts the result form Read into a printable representation.
+ * This should only be used direct after a md5_read(), because it uses
+ * In-Place conversion.
+ * Returns digest.
+ */
+
+char *
+md5_tostring( byte *digest )
+{
+ static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ."
+ "abcdefghijklmnopqrstuvwxyz_"
+ "0123456789";
+ int i;
+ byte *d, *s;
+
+ memmove(digest+8,digest, 16); /* make some room */
+ d = digest;
+ s = digest+8;
+ for(i=0; i < 5; i++, s += 3 ) {
+ *d++ = bintoasc[(*s >> 2) & 077];
+ *d++ = bintoasc[(((*s << 4) & 060) | ((s[1] >> 4) & 017)) & 077];
+ *d++ = bintoasc[(((s[1] << 2) & 074) | ((s[2] >> 6) & 03)) & 077];
+ *d++ = bintoasc[s[2] & 077];
+ }
+ *d++ = bintoasc[(*s >> 2) & 077];
+ *d++ = bintoasc[((*s << 4) & 060) & 077];
+ *d = 0;
+ return (char*)digest;
+}
+
+
+/* Basic MD5 step. Transforms buf based on in. Note that if the Mysterious
+ * Constants are arranged backwards in little-endian order and decrypted with
+ * the DES they produce OCCULT MESSAGES!
+ */
+static void
+Transform(register u32 *buf,register u32 *in)
+{
+ register u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF ( a, b, c, d, in[ 0], S11, 0xD76AA478L); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, 0xE8C7B756L); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, 0x242070DBL); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, 0xC1BDCEEEL); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, 0xF57C0FAFL); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, 0x4787C62AL); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, 0xA8304613L); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, 0xFD469501L); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, 0x698098D8L); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, 0x8B44F7AFL); /* 10 */
+ FF ( c, d, a, b, in[10], S13, 0xFFFF5BB1L); /* 11 */
+ FF ( b, c, d, a, in[11], S14, 0x895CD7BEL); /* 12 */
+ FF ( a, b, c, d, in[12], S11, 0x6B901122L); /* 13 */
+ FF ( d, a, b, c, in[13], S12, 0xFD987193L); /* 14 */
+ FF ( c, d, a, b, in[14], S13, 0xA679438EL); /* 15 */
+ FF ( b, c, d, a, in[15], S14, 0x49B40821L); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG ( a, b, c, d, in[ 1], S21, 0xF61E2562L); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, 0xC040B340L); /* 18 */
+ GG ( c, d, a, b, in[11], S23, 0x265E5A51L); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, 0xE9B6C7AAL); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, 0xD62F105DL); /* 21 */
+ GG ( d, a, b, c, in[10], S22, 0x02441453L); /* 22 */
+ GG ( c, d, a, b, in[15], S23, 0xD8A1E681L); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, 0xE7D3FBC8L); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, 0x21E1CDE6L); /* 25 */
+ GG ( d, a, b, c, in[14], S22, 0xC33707D6L); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, 0xF4D50D87L); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, 0x455A14EDL); /* 28 */
+ GG ( a, b, c, d, in[13], S21, 0xA9E3E905L); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, 0xFCEFA3F8L); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, 0x676F02D9L); /* 31 */
+ GG ( b, c, d, a, in[12], S24, 0x8D2A4C8AL); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH ( a, b, c, d, in[ 5], S31, 0xFFFA3942L); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, 0x8771F681L); /* 34 */
+ HH ( c, d, a, b, in[11], S33, 0x6D9D6122L); /* 35 */
+ HH ( b, c, d, a, in[14], S34, 0xFDE5380CL); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, 0xA4BEEA44L); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, 0x4BDECFA9L); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, 0xF6BB4B60L); /* 39 */
+ HH ( b, c, d, a, in[10], S34, 0xBEBFBC70L); /* 40 */
+ HH ( a, b, c, d, in[13], S31, 0x289B7EC6L); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, 0xEAA127FAL); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, 0xD4EF3085L); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, 0x04881D05L); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, 0xD9D4D039L); /* 45 */
+ HH ( d, a, b, c, in[12], S32, 0xE6DB99E5L); /* 46 */
+ HH ( c, d, a, b, in[15], S33, 0x1FA27CF8L); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, 0xC4AC5665L); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II ( a, b, c, d, in[ 0], S41, 0xF4292244L); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, 0x432AFF97L); /* 50 */
+ II ( c, d, a, b, in[14], S43, 0xAB9423A7L); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, 0xFC93A039L); /* 52 */
+ II ( a, b, c, d, in[12], S41, 0x655B59C3L); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, 0x8F0CCC92L); /* 54 */
+ II ( c, d, a, b, in[10], S43, 0xFFEFF47DL); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, 0x85845DD1L); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, 0x6FA87E4FL); /* 57 */
+ II ( d, a, b, c, in[15], S42, 0xFE2CE6E0L); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, 0xA3014314L); /* 59 */
+ II ( b, c, d, a, in[13], S44, 0x4E0811A1L); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, 0xF7537E82L); /* 61 */
+ II ( d, a, b, c, in[11], S42, 0xBD3AF235L); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, 0x2AD7D2BBL); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, 0xEB86D391L); /* 64 */
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+
+
+/* end of file */
diff --git a/cipher/md5.h b/cipher/md5.h
new file mode 100644
index 000000000..fa401a162
--- /dev/null
+++ b/cipher/md5.h
@@ -0,0 +1,44 @@
+/* md5.h - message digest 5
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_MD5_H
+#define G10_MD5_H
+
+#include "types.h"
+
+typedef struct {
+ u32 i[2]; /* number of _bits_ handled mod 2^64 */
+ u32 buf[4]; /* scratch buffer */
+ byte in[64]; /* input buffer */
+ byte digest[16+8+1]; /* actual digest after Final call */
+ byte bufcount; /* extra room for bintoascii */
+} *MD5HANDLE;
+
+/*-- md5.c --*/
+MD5HANDLE md5_open(int);
+MD5HANDLE md5_copy(MD5HANDLE a);
+void md5_write(MD5HANDLE hd, byte *inBuf, size_t inLen);
+void md5_putchar(MD5HANDLE hd, int c );
+void md5_final(MD5HANDLE hd);
+byte *md5_read(MD5HANDLE hd);
+char *md5_tostring( byte *digest );
+void md5_close(MD5HANDLE hd);
+
+
+#endif /*G10_MD5_H*/
diff --git a/cipher/primegen.c b/cipher/primegen.c
new file mode 100644
index 000000000..07d83d831
--- /dev/null
+++ b/cipher/primegen.c
@@ -0,0 +1,152 @@
+/* primegen.c - prime number generator
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "mpi.h"
+#include "cipher.h"
+
+static int no_of_small_prime_numbers;
+static int rabin_miller( MPI n );
+
+
+/****************
+ * Generate a prime number (stored in secure memory)
+ */
+MPI
+generate_random_prime( unsigned nbits )
+{
+
+ unsigned nlimbs;
+ MPI prime, val_2, val_3, result;
+ int i;
+ unsigned x, step;
+ unsigned count1, count2;
+ int *mods;
+
+ if( DBG_CIPHER )
+ log_debug("generate a prime of %u bits ", nbits );
+
+ if( !no_of_small_prime_numbers ) {
+ for(i=0; small_prime_numbers[i]; i++ )
+ no_of_small_prime_numbers++;
+ }
+ mods = m_alloc( no_of_small_prime_numbers * sizeof *mods );
+ /* make nbits fit into MPI implementation */
+ nlimbs = (nbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB;
+ assert( nlimbs );
+ val_2 = mpi_alloc( nlimbs );
+ mpi_set_ui(val_2, 2);
+ val_3 = mpi_alloc( nlimbs );
+ mpi_set_ui(val_3, 3);
+ result = mpi_alloc( nlimbs );
+ prime = mpi_alloc_secure( nlimbs );
+ count1 = count2 = 0;
+ /* enter (endless) loop */
+ for(;;) {
+ /* generate a random number */
+ mpi_set_bytes( prime, nbits, get_random_byte, 2 );
+ /* set high order bit to 1, set low order bit to 1 */
+ mpi_set_bit( prime, nbits-1 );
+ mpi_set_bit( prime, 0 );
+
+ /* calculate all remainders */
+ for(i=0; (x = small_prime_numbers[i]); i++ )
+ mods[i] = mpi_fdiv_r_ui(NULL, prime, x);
+
+ for(step=0; step < 20000; step += 2 ) {
+ /* check against all the small primes we have in mods */
+ count1++;
+ for(i=0; (x = small_prime_numbers[i]); i++ ) {
+ while( mods[i] + step >= x )
+ mods[i] -= x;
+ if( !(mods[i] + step) )
+ break;
+ }
+ if( x )
+ continue; /* found a multiple of a already known prime */
+ if( DBG_CIPHER )
+ fputc('.', stderr);
+
+ mpi_add_ui( prime, prime, step );
+
+ /* do a Fermat test */
+ count2++;
+ mpi_powm( result, val_2, prime, prime );
+ if( mpi_cmp_ui(result, 2) )
+ continue; /* stepping (fermat test failed) */
+ if( DBG_CIPHER )
+ fputc('+', stderr);
+ /* and a second one */
+ count2++;
+ mpi_powm( result, val_3, prime, prime );
+ if( mpi_cmp_ui(result, 3) )
+ continue; /* stepping (fermat test failed) */
+ if( DBG_CIPHER )
+ fputc('+', stderr);
+
+ /* perform Rabin-Miller tests */
+ for(i=5; i > 0; i-- ) {
+ if( DBG_CIPHER )
+ fputc('+', stderr);
+ if( rabin_miller(prime) )
+ break;
+ }
+ if( !i ) {
+ if( !mpi_test_bit( prime, nbits-1 ) ) {
+ if( DBG_CIPHER ) {
+ fputc('\n', stderr);
+ log_debug("overflow in prime generation\n");
+ break; /* step loop, cont with a new prime */
+ }
+ }
+ if( DBG_CIPHER ) {
+ fputc('\n', stderr);
+ log_debug("performed %u simple and %u Fermat/Rabin-Miller tests\n",
+ count1, count2 );
+ log_mpidump("found prime: ", prime );
+ }
+
+ mpi_free(val_2);
+ mpi_free(val_3);
+ mpi_free(result);
+ m_free(mods);
+ return prime;
+ }
+ }
+ if( DBG_CIPHER )
+ fputc(':', stderr); /* restart with a new random value */
+ }
+}
+
+
+/****************
+ * Return 1 if n is not a prime
+ */
+static int
+rabin_miller( MPI n )
+{
+ return 0;
+}
+
diff --git a/cipher/random.c b/cipher/random.c
new file mode 100644
index 000000000..73a9a3ebf
--- /dev/null
+++ b/cipher/random.c
@@ -0,0 +1,67 @@
+/* random.c - random number generator
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "util.h"
+#include "cipher.h"
+
+static struct {
+ int level;
+ int len;
+ byte buffer[100]; /* fixme: should this be allocated in secure space? */
+} cache;
+
+/****************
+ * Fill the buffer with LENGTH bytes of cryptologic strong
+ * random bytes. level 0 is not very strong, 1 is strong enough
+ * for most usage, 2 is good for key generation stuff but may be very slow.
+ */
+void
+randomize_buffer( byte *buffer, size_t length, int level )
+{
+ FILE *fp;
+
+ if( level == 2 )
+ level = 1; /* 2 is much too slow */
+ fp = fopen(level < 2? "/dev/urandom":"/dev/random", "r");
+ if( !fp )
+ log_fatal("can't open random device: %s\n", strerror(errno) );
+ for( ; length; length-- )
+ *buffer++ = getc(fp);
+ fclose(fp);
+}
+
+
+byte
+get_random_byte( int level )
+{
+ if( !cache.len || cache.level < level ) {
+ randomize_buffer(cache.buffer, DIM(cache.buffer), level );
+ cache.level = level;
+ cache.len = DIM(cache.buffer);
+ }
+
+ return cache.buffer[--cache.len];
+}
+
+
diff --git a/cipher/rmd.h b/cipher/rmd.h
new file mode 100644
index 000000000..3d260cdca
--- /dev/null
+++ b/cipher/rmd.h
@@ -0,0 +1,51 @@
+/* rmd.h - RIPE-MD hash functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_RMD_H
+#define G10_RMD_H
+
+#include "types.h"
+
+typedef struct {
+ u32 h0,h1,h2,h3,h4;
+ u32 nblocks;
+ byte buffer[64];
+ int bufcount;
+} *RMDHANDLE;
+
+
+/****************
+ * Process a single character, this character will be buffered to
+ * increase performance.
+ */
+#define rmd160_putchar(h,c) \
+ do { \
+ if( (h)->bufcount == 64 ) \
+ rmd160_write( (h), NULL, 0 ); \
+ (h)->buffer[(h)->bufcount++] = (c) & 0xff; \
+ } while(0)
+
+RMDHANDLE rmd160_open( int secure );
+RMDHANDLE rmd160_copy( RMDHANDLE a );
+void rmd160_close(RMDHANDLE hd);
+void rmd160_write( RMDHANDLE hd, byte *inbuf, size_t inlen);
+byte * rmd160_final(RMDHANDLE hd);
+
+
+#endif /*G10_RMD_H*/
diff --git a/cipher/rmd160.c b/cipher/rmd160.c
new file mode 100644
index 000000000..9a882fc5e
--- /dev/null
+++ b/cipher/rmd160.c
@@ -0,0 +1,375 @@
+/* rmd160.c - RIPE-MD160
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "memory.h"
+#include "rmd.h"
+
+/*********************************
+ * RIPEMD-160 is not patented, see (as of 25.10.97)
+ * http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
+ * Note that the code uses Little Endian byteorder, which is good for
+ * 386 etc, but we must add some conversion when used on a big endian box.
+ *
+ *
+ * Pseudo-code for RIPEMD-160
+ *
+ * RIPEMD-160 is an iterative hash function that operates on 32-bit words.
+ * The round function takes as input a 5-word chaining variable and a 16-word
+ * message block and maps this to a new chaining variable. All operations are
+ * defined on 32-bit words. Padding is identical to that of MD4.
+ *
+ *
+ * RIPEMD-160: definitions
+ *
+ *
+ * nonlinear functions at bit level: exor, mux, -, mux, -
+ *
+ * f(j, x, y, z) = x XOR y XOR z (0 <= j <= 15)
+ * f(j, x, y, z) = (x AND y) OR (NOT(x) AND z) (16 <= j <= 31)
+ * f(j, x, y, z) = (x OR NOT(y)) XOR z (32 <= j <= 47)
+ * f(j, x, y, z) = (x AND z) OR (y AND NOT(z)) (48 <= j <= 63)
+ * f(j, x, y, z) = x XOR (y OR NOT(z)) (64 <= j <= 79)
+ *
+ *
+ * added constants (hexadecimal)
+ *
+ * K(j) = 0x00000000 (0 <= j <= 15)
+ * K(j) = 0x5A827999 (16 <= j <= 31) int(2**30 x sqrt(2))
+ * K(j) = 0x6ED9EBA1 (32 <= j <= 47) int(2**30 x sqrt(3))
+ * K(j) = 0x8F1BBCDC (48 <= j <= 63) int(2**30 x sqrt(5))
+ * K(j) = 0xA953FD4E (64 <= j <= 79) int(2**30 x sqrt(7))
+ * K'(j) = 0x50A28BE6 (0 <= j <= 15) int(2**30 x cbrt(2))
+ * K'(j) = 0x5C4DD124 (16 <= j <= 31) int(2**30 x cbrt(3))
+ * K'(j) = 0x6D703EF3 (32 <= j <= 47) int(2**30 x cbrt(5))
+ * K'(j) = 0x7A6D76E9 (48 <= j <= 63) int(2**30 x cbrt(7))
+ * K'(j) = 0x00000000 (64 <= j <= 79)
+ *
+ *
+ * selection of message word
+ *
+ * r(j) = j (0 <= j <= 15)
+ * r(16..31) = 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8
+ * r(32..47) = 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12
+ * r(48..63) = 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2
+ * r(64..79) = 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
+ * r0(0..15) = 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12
+ * r0(16..31)= 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2
+ * r0(32..47)= 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13
+ * r0(48..63)= 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14
+ * r0(64..79)= 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
+ *
+ *
+ * amount for rotate left (rol)
+ *
+ * s(0..15) = 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8
+ * s(16..31) = 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12
+ * s(32..47) = 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5
+ * s(48..63) = 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12
+ * s(64..79) = 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
+ * s'(0..15) = 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6
+ * s'(16..31)= 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11
+ * s'(32..47)= 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5
+ * s'(48..63)= 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8
+ * s'(64..79)= 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
+ *
+ *
+ * initial value (hexadecimal)
+ *
+ * h0 = 0x67452301; h1 = 0xEFCDAB89; h2 = 0x98BADCFE; h3 = 0x10325476;
+ * h4 = 0xC3D2E1F0;
+ *
+ *
+ * RIPEMD-160: pseudo-code
+ *
+ * It is assumed that the message after padding consists of t 16-word blocks
+ * that will be denoted with X[i][j], with 0 <= i <= t-1 and 0 <= j <= 15.
+ * The symbol [+] denotes addition modulo 2**32 and rol_s denotes cyclic left
+ * shift (rotate) over s positions.
+ *
+ *
+ * for i := 0 to t-1 {
+ * A := h0; B := h1; C := h2; D = h3; E = h4;
+ * A' := h0; B' := h1; C' := h2; D' = h3; E' = h4;
+ * for j := 0 to 79 {
+ * T := rol_s(j)(A [+] f(j, B, C, D) [+] X[i][r(j)] [+] K(j)) [+] E;
+ * A := E; E := D; D := rol_10(C); C := B; B := T;
+ * T := rol_s'(j)(A' [+] f(79-j, B', C', D') [+] X[i][r'(j)]
+ [+] K'(j)) [+] E';
+ * A' := E'; E' := D'; D' := rol_10(C'); C' := B'; B' := T;
+ * }
+ * T := h1 [+] C [+] D'; h1 := h2 [+] D [+] E'; h2 := h3 [+] E [+] A';
+ * h3 := h4 [+] A [+] B'; h4 := h0 [+] B [+] C'; h0 := T;
+ * }
+ */
+
+/* Some examples:
+ * "" 9c1185a5c5e9fc54612808977ee8f548b2258d31
+ * "a" 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe
+ * "abc" 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
+ * "message digest" 5d0689ef49d2fae572b881b123a85ffa21595f36
+ * "a...z" f71c27109c692c1b56bbdceb5b9d2865b3708dbc
+ * "abcdbcde...nopq" 12a053384a9c0c88e405a06c27dcf49ada62eb2b
+ * "A...Za...z0...9" b0e20b6e3116640286ed3a87a5713079b21f5189
+ * 8 times "1234567890" 9b752e45573d4b39f4dbd3323cab82bf63326bfb
+ * 1 million times "a" 52783243c1697bdbe16d37f97f68f08325dc1528
+ */
+
+
+static void
+initialize( RMDHANDLE hd )
+{
+ hd->h0 = 0x67452301;
+ hd->h1 = 0xEFCDAB89;
+ hd->h2 = 0x98BADCFE;
+ hd->h3 = 0x10325476;
+ hd->h4 = 0xC3D2E1F0;
+ hd->bufcount = 0;
+ hd->nblocks = 0;
+}
+
+
+/****************
+ * Transform the message X which consists of 16 32-bit-words
+ */
+static void
+transform( RMDHANDLE hd, u32 *x )
+{
+ static int r[80] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 };
+ static int rr[80] = {
+ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 };
+ static int s[80] = {
+ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
+ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 };
+ static int ss[80] = {
+ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 };
+ u32 a,b,c,d,e,aa,bb,cc,dd,ee,t;
+ int rbits, j;
+
+#define K(a) ( (a) < 16 ? 0x00000000 : \
+ (a) < 32 ? 0x5A827999 : \
+ (a) < 48 ? 0x6ED9EBA1 : \
+ (a) < 64 ? 0x8F1BBCDC : 0xA953FD4E )
+#define KK(a) ( (a) < 16 ? 0x50A28BE6 : \
+ (a) < 32 ? 0x5C4DD124 : \
+ (a) < 48 ? 0x6D703EF3 : \
+ (a) < 64 ? 0x7A6D76E9 : 0x00000000 )
+
+#define F0(x,y,z) ( (x) ^ (y) ^ (z) )
+#define F1(x,y,z) ( ((x) & (y)) | (~(x) & (z)) )
+#define F2(x,y,z) ( ((x) | ~(y)) ^ (z) )
+#define F3(x,y,z) ( ((x) & (z)) | ((y) & ~(z)) )
+#define F4(x,y,z) ( (x) ^ ((y) | ~(z)) )
+#define F(a,x,y,z) ( (a) < 16 ? F0((x),(y),(z)) : \
+ (a) < 32 ? F1((x),(y),(z)) : \
+ (a) < 48 ? F2((x),(y),(z)) : \
+ (a) < 64 ? F3((x),(y),(z)) : \
+ F4((x),(y),(z)) )
+
+#define rol(n,x) ( ((x) << (n)) | ((x) >> (32-(n))) )
+
+ a = aa = hd->h0;
+ b = bb = hd->h1;
+ c = cc = hd->h2;
+ d = dd = hd->h3;
+ e = ee = hd->h4;
+
+ for(j=0; j < 80; j++ ) {
+ t = a + F( j, b, c, d ) + x[ r[j] ] + K(j);
+ rbits = s[j];
+ a = rol(rbits, t) + e;
+ c = rol(10,c);
+ t = a; a = e; e = d; d = c; c = b; b = t;
+
+ t = aa + F(79-j, bb, cc, dd ) + x[ rr[j] ] + KK(j);
+ rbits = ss[j];
+ aa = rol(rbits, t) + ee;
+ cc = rol(10,cc);
+ t = aa; aa = ee; ee = dd; dd = cc; cc = bb; bb = t;
+ }
+
+ t = hd->h1 + c + dd;
+ hd->h1 = hd->h2 + d + ee;
+ hd->h2 = hd->h3 + e + aa;
+ hd->h3 = hd->h4 + a + bb;
+ hd->h4 = hd->h0 + b + cc;
+ hd->h0 = t;
+}
+
+
+
+
+RMDHANDLE
+rmd160_open( int secure )
+{
+ RMDHANDLE hd;
+
+ hd = secure? m_alloc_secure( sizeof *hd )
+ : m_alloc( sizeof *hd );
+ initialize(hd);
+ return hd;
+}
+
+
+RMDHANDLE
+rmd160_copy( RMDHANDLE a )
+{
+ RMDHANDLE b;
+
+ assert(a);
+ b = m_is_secure(a)? m_alloc_secure( sizeof *b )
+ : m_alloc( sizeof *b );
+ memcpy( b, a, sizeof *a );
+ return b;
+}
+
+void
+rmd160_close(RMDHANDLE hd)
+{
+ if( hd )
+ m_free(hd);
+}
+
+
+
+/* Update the message digest with the contents
+ * of INBUF with length INLEN.
+ */
+void
+rmd160_write( RMDHANDLE hd, byte *inbuf, size_t inlen)
+{
+ if( hd->bufcount == 64 ) { /* flush the buffer */
+ transform( hd, (u32*)hd->buffer );
+ hd->bufcount = 0;
+ hd->nblocks++;
+ }
+ if( !inbuf )
+ return;
+ if( hd->bufcount ) {
+ for( ; inlen && hd->bufcount < 64; inlen-- )
+ hd->buffer[hd->bufcount++] = *inbuf++;
+ rmd160_write( hd, NULL, 0 );
+ if( !inlen )
+ return;
+ }
+
+ while( inlen >= 64 ) {
+ transform( hd, (u32*)inbuf );
+ hd->bufcount = 0;
+ hd->nblocks++;
+ inlen -= 64;
+ inbuf += 64;
+ }
+ for( ; inlen && hd->bufcount < 64; inlen-- )
+ hd->buffer[hd->bufcount++] = *inbuf++;
+}
+
+
+/* The routine final terminates the computation and
+ * returns the digest.
+ * The handle is prepared for a new cycle, but adding bytes to the
+ * handle will the destroy the returned buffer.
+ * Returns: 20 bytes representing the digest.
+ */
+
+byte *
+rmd160_final(RMDHANDLE hd)
+{
+ u32 t, msb, lsb;
+ byte *p;
+
+ rmd160_write(hd, NULL, 0); /* flush */;
+
+ msb = 0;
+ t = hd->nblocks;
+ if( (lsb = t << 6) < t ) /* multiply by 64 to make a byte count */
+ msb++;
+ msb += t >> 26;
+ t = lsb;
+ if( (lsb = t + hd->bufcount) < t ) /* add the bufcount */
+ msb++;
+ t = lsb;
+ if( (lsb = t << 3) < t ) /* multiply by 8 to make a bit count */
+ msb++;
+ msb += t >> 29;
+
+ if( hd->bufcount < 56 ) { /* enough room */
+ hd->buffer[hd->bufcount++] = 0x80; /* pad */
+ while( hd->bufcount < 56 )
+ hd->buffer[hd->bufcount++] = 0; /* pad */
+ }
+ else { /* need one extra block */
+ hd->buffer[hd->bufcount++] = 0x80; /* pad character */
+ while( hd->bufcount < 64 )
+ hd->buffer[hd->bufcount++] = 0;
+ rmd160_write(hd, NULL, 0); /* flush */;
+ memset(hd->buffer, 0, 56 ); /* fill next block with zeroes */
+ }
+ /* append the 64 bit count */
+ hd->buffer[56] = lsb ;
+ hd->buffer[57] = lsb >> 8;
+ hd->buffer[58] = lsb >> 16;
+ hd->buffer[59] = lsb >> 24;
+ hd->buffer[60] = msb ;
+ hd->buffer[61] = msb >> 8;
+ hd->buffer[62] = msb >> 16;
+ hd->buffer[63] = msb >> 24;
+ transform( hd, (u32*)hd->buffer );
+
+ p = hd->buffer;
+ #ifdef HAVE_BIG_ENDIAN
+ #define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \
+ *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0)
+ #else /* little endian */
+ #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+ #endif
+ X(0);
+ X(1);
+ X(2);
+ X(3);
+ X(4);
+ #undef X
+
+ initialize( hd ); /* prepare for next cycle */
+ return hd->buffer; /* now contains the digest */
+}
+
+
diff --git a/cipher/rmd160test.c b/cipher/rmd160test.c
new file mode 100644
index 000000000..365fde02c
--- /dev/null
+++ b/cipher/rmd160test.c
@@ -0,0 +1,63 @@
+/* rmd160test.c - ripe md 160 test program
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "rmd.h"
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: rmd160test\n");
+ exit(1);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ RMDHANDLE rmdhd;
+ int i, n;
+ byte buf[100], *p;
+
+ if( argc > 1 )
+ usage();
+
+ rmdhd = rmd160_open(0);
+ #if 1
+ while( (n = fread( buf, 1, 100, stdin )) > 0 )
+ rmd160_write(rmdhd, buf, n);
+ #else
+ for(i=0; i < 1000000; i++ )
+ rmd160_putchar(rmdhd, 'a');
+ #endif
+ p = rmd160_final(rmdhd);
+ for(i=0; i < 20; i++, p++ )
+ printf("%02x", *p );
+ putchar('\n');
+
+ rmd160_close(rmdhd);
+ return 0;
+}
+
diff --git a/cipher/rsa.c b/cipher/rsa.c
new file mode 100644
index 000000000..ec761a953
--- /dev/null
+++ b/cipher/rsa.c
@@ -0,0 +1,191 @@
+/* rsa.c - RSA function
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * ATTENTION: This code should not be exported from the United States
+ * nor should it be used their without a license agreement with PKP.
+ * The RSA alorithm is protected by U.S. Patent #4,405,829 which
+ * expires on September 20, 2000!
+ *
+ * For a description of the algorithm, see:
+ * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
+ * ISBN 0-471-11709-9. Pages 466 ff.
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "util.h"
+#include "mpi.h"
+#include "cipher.h"
+
+
+void
+rsa_free_public_key( RSA_public_key *pk )
+{
+ mpi_free( pk->n ); pk->n = NULL;
+ mpi_free( pk->e ); pk->e = NULL;
+}
+
+void
+rsa_free_secret_key( RSA_secret_key *sk )
+{
+ mpi_free( sk->e ); sk->e = NULL;
+ mpi_free( sk->n ); sk->n = NULL;
+ mpi_free( sk->p ); sk->p = NULL;
+ mpi_free( sk->q ); sk->q = NULL;
+ mpi_free( sk->d ); sk->d = NULL;
+ mpi_free( sk->u ); sk->u = NULL;
+}
+
+
+static void
+test_keys( RSA_public_key *pk, RSA_secret_key *sk, unsigned nbits )
+{
+ MPI test = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ MPI out1 = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ MPI out2 = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+
+ mpi_set_bytes( test, nbits, get_random_byte, 0 );
+
+ rsa_public( out1, test, pk );
+ rsa_secret( out2, out1, sk );
+ if( mpi_cmp( test, out2 ) )
+ log_fatal("RSA operation: public, secret failed\n");
+ rsa_secret( out1, test, sk );
+ rsa_public( out2, out1, pk );
+ if( mpi_cmp( test, out2 ) )
+ log_fatal("RSA operation: secret, public failed\n");
+ mpi_free( test );
+ mpi_free( out1 );
+ mpi_free( out2 );
+}
+
+/****************
+ * Generate a key pair with a key of size NBITS
+ * Returns: 2 structures filles with all needed values
+ */
+void
+rsa_generate( RSA_public_key *pk, RSA_secret_key *sk, unsigned nbits )
+{
+ MPI p, q; /* the two primes */
+ MPI d; /* the private key */
+ MPI u;
+ MPI t1, t2;
+ MPI n; /* the public key */
+ MPI e; /* the exponent */
+ MPI phi; /* helper: (p-a)(q-1) */
+
+ /* select two (very secret) primes */
+ p = generate_random_prime( nbits / 2 );
+ q = generate_random_prime( nbits / 2 );
+ if( mpi_cmp( p, q ) > 0 ) /* p shall be smaller than q */
+ mpi_swap(p,q);
+ /* calculate phi = (p-1)(q-1) */
+ t1 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+ t2 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+ phi = mpi_alloc_secure( nbits / BITS_PER_MPI_LIMB );
+ mpi_sub_ui( t1, p, 1 );
+ mpi_sub_ui( t2, q, 1 );
+ mpi_mul( phi, t1, t2 );
+ /* multiply them to make the private key */
+ n = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ mpi_mul( n, p, q );
+ /* find a public exponent */
+ e = mpi_alloc(1);
+ mpi_set_ui( e, 17); /* start with 17 */
+ while( !mpi_gcd(t1, e, phi) ) { /* (while gcd is not 1) */
+ if( DBG_CIPHER )
+ log_mpidump("trying e=", e);
+ mpi_add_ui( e, e, 2);
+ }
+ /* calculate the secret key d = e^1 mod phi */
+ d = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ mpi_inv_mod(d, e, phi );
+ /* calculate the inverse of p and q (used for chinese remainder theorem)*/
+ u = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ mpi_inv_mod(u, p, q );
+
+ if( DBG_CIPHER ) {
+ log_mpidump("p=", p );
+ log_mpidump("q=", q );
+ log_mpidump("phi=", phi );
+ log_mpidump("n=", n );
+ log_mpidump("e=", e );
+ log_mpidump("d=", d );
+ log_mpidump("u=", u );
+ }
+
+ mpi_free(t1);
+ mpi_free(t2);
+ mpi_free(phi);
+
+ pk->n = mpi_copy(n);
+ pk->e = mpi_copy(e);
+ sk->n = n;
+ sk->e = e;
+ sk->p = p;
+ sk->q = q;
+ sk->d = d;
+ sk->u = u;
+
+ /* now we can test our keys (this should never fail!) */
+ test_keys( pk, sk, nbits - 16 );
+}
+
+
+
+
+/****************
+ * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT.
+ *
+ * c = m^e mod n
+ *
+ * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY.
+ */
+void
+rsa_public(MPI output, MPI input, RSA_public_key *pkey )
+{
+ if( output == input ) { /* powm doesn't like output and input the same */
+ MPI x = mpi_alloc( mpi_get_nlimbs(input)*2 );
+ mpi_powm( x, input, pkey->e, pkey->n );
+ mpi_set(output, x);
+ mpi_free(x);
+ }
+ else
+ mpi_powm( output, input, pkey->e, pkey->n );
+}
+
+/****************
+ * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT.
+ *
+ * m = c^d mod n
+ *
+ * Where m is OUTPUT, c is INPUT and d,n are elements of PKEY.
+ *
+ * FIXME: We should better use the Chinese Remainder Theorem
+ */
+void
+rsa_secret(MPI output, MPI input, RSA_secret_key *skey )
+{
+ mpi_powm( output, input, skey->d, skey->n );
+}
+
+
+
diff --git a/cipher/rsa.h b/cipher/rsa.h
new file mode 100644
index 000000000..a9980d0bc
--- /dev/null
+++ b/cipher/rsa.h
@@ -0,0 +1,53 @@
+/* rsa.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * ATTENTION: This code should not be exported from the United States
+ * nor should it be used their without a license agreement with PKP.
+ * The RSA alorithm is protected by U.S. Patent #4,405,829 which
+ * expires on September 20, 2000!
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_RSA_H
+#define G10_RSA_H
+
+#include "mpi.h"
+
+typedef struct {
+ MPI e; /* exponent */
+ MPI n; /* modulus */
+} RSA_public_key;
+
+
+typedef struct {
+ MPI e; /* public exponent */
+ MPI n; /* public modulus */
+ MPI p; /* prime p. */
+ MPI q; /* prime q. */
+ MPI d; /* exponent */
+ MPI u; /* inverse of p mod q. */
+} RSA_secret_key;
+
+
+void rsa_free_public_key( RSA_public_key *pk );
+void rsa_free_secret_key( RSA_secret_key *sk );
+void rsa_generate( RSA_public_key *pk, RSA_secret_key *sk, unsigned nbits );
+void rsa_public(MPI output, MPI input, RSA_public_key *skey );
+void rsa_secret(MPI output, MPI input, RSA_secret_key *skey );
+
+
+#endif /*G10_RSA_H*/
diff --git a/cipher/smallprime.c b/cipher/smallprime.c
new file mode 100644
index 000000000..74a1304a4
--- /dev/null
+++ b/cipher/smallprime.c
@@ -0,0 +1,114 @@
+/* smallprime.c - List of small primes
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "util.h"
+#include "types.h"
+
+/* Note: 2 is not included because it can be testest more easily
+ * by looking at bit 0. The last entry in this list is marked by a zero
+ */
+ushort
+small_prime_numbers[] = {
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
+ 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
+ 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
+ 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
+ 211, 223, 227, 229, 233, 239, 241, 251, 257, 263,
+ 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
+ 331, 337, 347, 349, 353, 359, 367, 373, 379, 383,
+ 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
+ 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
+ 509, 521, 523, 541, 547, 557, 563, 569, 571, 577,
+ 587, 593, 599, 601, 607, 613, 617, 619, 631, 641,
+ 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
+ 709, 719, 727, 733, 739, 743, 751, 757, 761, 769,
+ 773, 787, 797, 809, 811, 821, 823, 827, 829, 839,
+ 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
+ 919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
+ 991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
+ 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091,
+ 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
+ 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213,
+ 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277,
+ 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307,
+ 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,
+ 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
+ 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493,
+ 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559,
+ 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609,
+ 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
+ 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
+ 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789,
+ 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871,
+ 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931,
+ 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997,
+ 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053,
+ 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111,
+ 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161,
+ 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243,
+ 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297,
+ 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357,
+ 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411,
+ 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473,
+ 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551,
+ 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633,
+ 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687,
+ 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729,
+ 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791,
+ 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851,
+ 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917,
+ 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999,
+ 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061,
+ 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137,
+ 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209,
+ 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271,
+ 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
+ 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391,
+ 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467,
+ 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533,
+ 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583,
+ 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643,
+ 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709,
+ 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779,
+ 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851,
+ 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917,
+ 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989,
+ 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049,
+ 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111,
+ 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177,
+ 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243,
+ 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297,
+ 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391,
+ 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457,
+ 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519,
+ 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597,
+ 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657,
+ 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729,
+ 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799,
+ 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889,
+ 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951,
+ 4957, 4967, 4969, 4973, 4987, 4993, 4999,
+ 0
+};
+
+
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 000000000..1a4d6ef7e
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,60 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+/* acconfig.h - used by autoheader to make config.h.in
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_CONFIG_H
+#define G10_CONFIG_H
+
+
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define if you don't have vprintf but do have _doprnt. */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function. */
+#undef HAVE_VPRINTF
+
+/* Define as __inline if that's what the C compiler calls it. */
+#undef inline
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+#undef M_DEBUG
+#undef VERSION
+#undef PACKAGE
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strtol function. */
+#undef HAVE_STRTOL
+
+/* Define if you have the strtoul function. */
+#undef HAVE_STRTOUL
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+#endif /*G10_CONFIG_H*/
diff --git a/configure.in b/configure.in
new file mode 100644
index 000000000..d6eeab10b
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,54 @@
+dnl
+dnl Configure template for G10
+dnl
+dnl (Process this file with autoconf to produce a configure script.)
+
+AC_INIT(g10/g10.c)
+AC_CONFIG_AUX_DIR(scripts)
+AC_CONFIG_HEADER(config.h)
+
+VERSION=0.0.0
+PACKAGE=g10
+AC_SUBST(VERSION)
+AC_SUBST(PACKAGE)
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+
+AC_ARG_ENABLE(m-debug,
+[ --enable-m-debug Enable debugging of memory allocation])
+if test "$enableval" = y || test "$enableval" = yes; then
+ AC_DEFINE(M_DEBUG)
+ CFLAGS="-g"
+fi
+
+dnl Checks for programs.
+
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+AC_PROG_CC
+AC_PROG_CPP
+
+AC_ARG_PROGRAM
+
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_SIZE_T
+
+dnl Checks for library functions.
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(strerror strtol strtoul)
+
+AC_OUTPUT([ Makefile util/Makefile mpi/Makefile cipher/Makefile \
+ g10/Makefile tools/Makefile ],
+ [echo timestamp > stamp-h ])
+
+
diff --git a/g10/Makefile.am b/g10/Makefile.am
new file mode 100644
index 000000000..e01940b99
--- /dev/null
+++ b/g10/Makefile.am
@@ -0,0 +1,33 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/include
+
+bin_PROGRAMS = g10
+
+g10_SOURCES = g10.c \
+ build-packet.c \
+ compressed.c \
+ encode.c \
+ encr-data.c \
+ filter.h \
+ free-packet.c \
+ getkey.c \
+ keydb.h \
+ keygen.c \
+ main.h \
+ mainproc.c \
+ mdfilter.c \
+ options.h \
+ overwrite.c \
+ packet.h \
+ parse-packet.c \
+ passphrase.c \
+ plaintext.c \
+ pubkey-enc.c \
+ seckey-cert.c \
+ seskey.c \
+ sig-check.c
+
+
+LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil
+
diff --git a/g10/Makefile.in b/g10/Makefile.in
new file mode 100644
index 000000000..d7f9ae267
--- /dev/null
+++ b/g10/Makefile.in
@@ -0,0 +1,285 @@
+# Makefile.in generated automatically by automake 1.0 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+INCLUDES = -I$(top_srcdir)/include
+
+bin_PROGRAMS = g10
+
+g10_SOURCES = g10.c \
+ build-packet.c \
+ compressed.c \
+ encode.c \
+ encr-data.c \
+ filter.h \
+ free-packet.c \
+ getkey.c \
+ keydb.h \
+ keygen.c \
+ main.h \
+ mainproc.c \
+ mdfilter.c \
+ options.h \
+ overwrite.c \
+ packet.h \
+ parse-packet.c \
+ passphrase.c \
+ plaintext.c \
+ pubkey-enc.c \
+ seckey-cert.c \
+ seskey.c \
+ sig-check.c
+
+LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil
+mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
+CONFIG_HEADER = ../config.h
+PROGRAMS = $(bin_PROGRAMS)
+
+
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+g10_OBJECTS = g10.o build-packet.o compressed.o encode.o encr-data.o \
+free-packet.o getkey.o keygen.o mainproc.o mdfilter.o overwrite.o \
+parse-packet.o passphrase.o plaintext.o pubkey-enc.o seckey-cert.o \
+seskey.o sig-check.o
+EXTRA_g10_SOURCES =
+g10_LDADD = $(LDADD)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA)
+DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA)
+
+TAR = tar
+DEP_FILES = $(srcdir)/.deps/build-packet.P $(srcdir)/.deps/compressed.P \
+$(srcdir)/.deps/encode.P $(srcdir)/.deps/encr-data.P \
+$(srcdir)/.deps/free-packet.P $(srcdir)/.deps/g10.P \
+$(srcdir)/.deps/getkey.P $(srcdir)/.deps/keygen.P \
+$(srcdir)/.deps/mainproc.P $(srcdir)/.deps/mdfilter.P \
+$(srcdir)/.deps/overwrite.P $(srcdir)/.deps/parse-packet.P \
+$(srcdir)/.deps/passphrase.P $(srcdir)/.deps/plaintext.P \
+$(srcdir)/.deps/pubkey-enc.P $(srcdir)/.deps/seckey-cert.P \
+$(srcdir)/.deps/seskey.P $(srcdir)/.deps/sig-check.P
+SOURCES = $(g10_SOURCES)
+OBJECTS = $(g10_OBJECTS)
+
+default: all
+
+
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+ cd $(top_srcdir) && automake $(subdir)/Makefile
+
+Makefile: $(top_builddir)/config.status Makefile.in
+ cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+ rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+ $(mkinstalldirs) $(bindir)
+ list="$(bin_PROGRAMS)"; for p in $$list; do \
+ if test -f $$p; then \
+ $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ list="$(bin_PROGRAMS)"; for p in $$list; do \
+ rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+.c.o:
+ $(COMPILE) $<
+
+mostlyclean-compile:
+ rm -f *.o core
+
+clean-compile:
+
+distclean-compile:
+ rm -f *.tab.c
+
+maintainer-clean-compile:
+$(g10_OBJECTS): ../config.h
+
+g10: $(g10_OBJECTS) $(g10_DEPENDENCIES)
+ $(LINK) $(g10_OBJECTS) $(g10_LDADD) $(LIBS)
+
+ID: $(HEADERS) $(SOURCES)
+ here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
+
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
+ here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ rm -f TAGS ID
+
+maintainer-clean-tags:
+
+subdir = g10
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+distdir: $(DEP_DISTFILES)
+ @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \
+ test -f $(distdir)/$$file \
+ || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $(srcdir)/$$file $(distdir)/$$file; \
+ done
+
+# This fragment is probably only useful for maintainers. It relies on
+# GNU make and gcc. It is only included in the generated Makefile.in
+# if `automake' is not passed the `--include-deps' flag.
+
+MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+-include $(srcdir)/.deps/.P
+$(srcdir)/.deps/.P: $(BUILT_SOURCES)
+ cd $(srcdir) && test -d .deps || mkdir .deps
+ echo > $@
+
+-include $(DEP_FILES)
+$(DEP_FILES): $(srcdir)/.deps/.P
+
+$(srcdir)/.deps/%.P: $(srcdir)/%.c
+ @echo "mkdeps $< > $@"
+ @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \
+ $(MKDEP) $< | sed "$$re" > $@-tmp
+ @if test -n "$o"; then \
+ sed 's/\.o:/$$o:/' $@-tmp > $@; \
+ rm $@-tmp; \
+ else \
+ mv $@-tmp $@; \
+ fi
+
+# End of maintainer-only section
+info:
+
+dvi:
+
+check: all
+
+installcheck:
+
+install-exec: install-binPROGRAMS
+
+install-data:
+
+install: install-exec install-data all
+ @:
+
+uninstall: uninstall-binPROGRAMS
+
+all: $(PROGRAMS) Makefile
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
+installdirs:
+ $(mkinstalldirs) $(bindir)
+
+
+mostlyclean-generic:
+ test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ rm -f Makefile $(DISTCLEANFILES)
+ rm -f config.cache config.log $(CONFIG_HEADER) stamp-h
+
+maintainer-clean-generic:
+ test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean: mostlyclean-binPROGRAMS mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+clean: clean-binPROGRAMS clean-compile clean-tags clean-generic \
+ mostlyclean
+
+distclean: distclean-binPROGRAMS distclean-compile distclean-tags \
+ distclean-generic clean
+ rm -f config.status
+
+maintainer-clean: maintainer-clean-binPROGRAMS maintainer-clean-compile \
+ maintainer-clean-tags maintainer-clean-generic \
+ distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: default mostlyclean-binPROGRAMS distclean-binPROGRAMS \
+clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \
+install-binPROGRAMS mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info dvi check installcheck \
+install-exec install-data install uninstall all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/g10/build-packet.c b/g10/build-packet.c
new file mode 100644
index 000000000..b6e1b6fd4
--- /dev/null
+++ b/g10/build-packet.c
@@ -0,0 +1,386 @@
+/* build-packet.c - assemble packets and write them
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "packet.h"
+#include "errors.h"
+#include "iobuf.h"
+#include "mpi.h"
+#include "util.h"
+#include "cipher.h"
+#include "memory.h"
+#include "options.h"
+
+
+static int do_comment( IOBUF out, int ctb, PKT_comment *rem );
+static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid );
+static int do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pk );
+static int do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *pk );
+static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc );
+static u32 calc_plaintext( PKT_plaintext *pt );
+static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt );
+static int do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed );
+
+static int calc_header_length( u32 len );
+static int write_16(IOBUF inp, u16 a);
+static int write_32(IOBUF inp, u32 a);
+static int write_header( IOBUF out, int ctb, u32 len );
+static int write_version( IOBUF out, int ctb );
+
+/****************
+ * Build a packet and write it to INP
+ * Returns: 0 := okay
+ * >0 := error
+ * Note: Caller must free the packet
+ */
+int
+build_packet( IOBUF out, PACKET *pkt )
+{
+ int rc=0, ctb;
+
+ if( DBG_PACKET )
+ log_debug("build_packet() type=%d\n", pkt->pkttype );
+ assert( pkt->pkt.generic );
+ ctb = 0x80 | ((pkt->pkttype & 15)<<2);
+ switch( pkt->pkttype ) {
+ case PKT_USER_ID:
+ rc = do_user_id( out, ctb, pkt->pkt.user_id );
+ break;
+ case PKT_COMMENT:
+ rc = do_comment( out, ctb, pkt->pkt.comment );
+ break;
+ case PKT_PUBKEY_CERT:
+ rc = do_pubkey_cert( out, ctb, pkt->pkt.pubkey_cert );
+ break;
+ case PKT_SECKEY_CERT:
+ rc = do_seckey_cert( out, ctb, pkt->pkt.seckey_cert );
+ break;
+ case PKT_PUBKEY_ENC:
+ rc = do_pubkey_enc( out, ctb, pkt->pkt.pubkey_enc );
+ break;
+ case PKT_PLAINTEXT:
+ rc = do_plaintext( out, ctb, pkt->pkt.plaintext );
+ break;
+ case PKT_ENCR_DATA:
+ rc = do_encr_data( out, ctb, pkt->pkt.encr_data );
+ break;
+ case PKT_SIGNATURE:
+ case PKT_RING_TRUST:
+ case PKT_COMPR_DATA:
+ default:
+ log_bug("invalid packet type in build_packet()");
+ break;
+ }
+
+ return rc;
+}
+
+/****************
+ * calculate the length of a packet described by PKT
+ */
+u32
+calc_packet_length( PACKET *pkt )
+{
+ u32 n=0;
+
+ assert( pkt->pkt.generic );
+ switch( pkt->pkttype ) {
+ case PKT_PLAINTEXT:
+ n = calc_plaintext( pkt->pkt.plaintext );
+ break;
+ case PKT_USER_ID:
+ case PKT_COMMENT:
+ case PKT_PUBKEY_CERT:
+ case PKT_SECKEY_CERT:
+ case PKT_PUBKEY_ENC:
+ case PKT_ENCR_DATA:
+ case PKT_SIGNATURE:
+ case PKT_RING_TRUST:
+ case PKT_COMPR_DATA:
+ default:
+ log_bug("invalid packet type in calc_packet_length()");
+ break;
+ }
+ n += calc_header_length(n);
+ return n;
+}
+
+
+static int
+do_comment( IOBUF out, int ctb, PKT_comment *rem )
+{
+ write_header(out, ctb, rem->len);
+ if( iobuf_write( out, rem->data, rem->len ) )
+ return G10ERR_WRITE_FILE;
+ return 0;
+}
+
+static int
+do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
+{
+ write_header(out, ctb, uid->len);
+ if( iobuf_write( out, uid->name, uid->len ) )
+ return G10ERR_WRITE_FILE;
+ return 0;
+}
+
+static int
+do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pkc )
+{
+ int rc = 0;
+ IOBUF a = iobuf_temp();
+
+ write_version( a, ctb );
+ write_32(a, pkc->timestamp );
+ write_16(a, pkc->valid_days );
+ iobuf_put(a, pkc->pubkey_algo );
+ if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_encode(a, pkc->d.rsa.rsa_n );
+ mpi_encode(a, pkc->d.rsa.rsa_e );
+ }
+ else {
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+ write_header(out, ctb, iobuf_get_temp_length(a) );
+ if( iobuf_write_temp( out, a ) )
+ rc = G10ERR_WRITE_FILE;
+
+ leave:
+ iobuf_close(a);
+ return rc;
+}
+
+static int
+do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *skc )
+{
+ int rc = 0;
+ IOBUF a = iobuf_temp();
+
+ write_version( a, ctb );
+ write_32(a, skc->timestamp );
+ write_16(a, skc->valid_days );
+ iobuf_put(a, skc->pubkey_algo );
+ if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_encode(a, skc->d.rsa.rsa_n );
+ mpi_encode(a, skc->d.rsa.rsa_e );
+ iobuf_put(a, skc->d.rsa.protect_algo );
+ skc->d.rsa.calc_csum = 0;
+ if( skc->d.rsa.protect_algo ) {
+ assert( skc->d.rsa.is_protected == 1 );
+ assert( skc->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH );
+ iobuf_write(a, skc->d.rsa.protect.blowfish.iv, 8 );
+
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum );
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum );
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum );
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum );
+ }
+ else { /* Not protected: You fool you! */
+ assert( !skc->d.rsa.is_protected );
+ mpi_encode_csum(a, skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum );
+ mpi_encode_csum(a, skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum );
+ mpi_encode_csum(a, skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum );
+ mpi_encode_csum(a, skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum );
+ }
+
+ write_16(a, skc->d.rsa.calc_csum );
+ }
+ else {
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+ write_header(out, ctb, iobuf_get_temp_length(a) );
+ if( iobuf_write_temp( out, a ) )
+ rc = G10ERR_WRITE_FILE;
+
+ leave:
+ iobuf_close(a);
+ return rc;
+}
+
+static int
+do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
+{
+ int rc = 0;
+ IOBUF a = iobuf_temp();
+
+ write_version( a, ctb );
+ write_32(a, enc->keyid[0] );
+ write_32(a, enc->keyid[1] );
+ iobuf_put(a,enc->pubkey_algo );
+ if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_encode(a, enc->d.rsa.rsa_integer );
+ }
+ else {
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+ write_header(out, ctb, iobuf_get_temp_length(a) );
+ if( iobuf_write_temp( out, a ) )
+ rc = G10ERR_WRITE_FILE;
+
+ leave:
+ iobuf_close(a);
+ return rc;
+}
+
+
+static u32
+calc_plaintext( PKT_plaintext *pt )
+{
+ return pt->len? (1 + 1 + pt->namelen + 4 + pt->len) : 0;
+}
+
+static int
+do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
+{
+ int c, i, rc = 0;
+ u32 n;
+
+ write_header(out, ctb, calc_plaintext( pt ) );
+ iobuf_put(out, pt->mode );
+ iobuf_put(out, pt->namelen );
+ for(i=0; i < pt->namelen; i++ )
+ iobuf_put(out, pt->name[i] );
+ if( write_32(out, pt->timestamp ) )
+ rc = G10ERR_WRITE_FILE;
+
+ n = 0;
+ while( (c=iobuf_get(pt->buf)) != -1 ) {
+ if( iobuf_put(out, c) ) {
+ rc = G10ERR_WRITE_FILE;
+ break;
+ }
+ n++;
+ }
+ if( !pt->len )
+ iobuf_set_block_mode(out, 0 ); /* write end marker */
+ else if( n != pt->len )
+ log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n",
+ (ulong)n, (ulong)pt->len );
+
+ return rc;
+}
+
+
+
+static int
+do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed )
+{
+ int rc = 0;
+ u32 n;
+
+ n = ed->len ? (ed->len + 10) : 0;
+ write_header(out, ctb, n );
+
+ /* This is all. The caller has to write the real data */
+
+ return rc;
+}
+
+
+
+
+static int
+write_16(IOBUF out, u16 a)
+{
+ iobuf_put(out, a>>8);
+ if( iobuf_put(out,a) )
+ return -1;
+ return 0;
+}
+
+static int
+write_32(IOBUF out, u32 a)
+{
+ iobuf_put(out, a>> 24);
+ iobuf_put(out, a>> 16);
+ iobuf_put(out, a>> 8);
+ if( iobuf_put(out, a) )
+ return -1;
+ return 0;
+}
+
+
+/****************
+ * calculate the length of a header
+ */
+static int
+calc_header_length( u32 len )
+{
+ if( !len )
+ return 1; /* only the ctb */
+ else if( len < 256 )
+ return 2;
+ else if( len < 65536 )
+ return 3;
+ else
+ return 5;
+}
+
+/****************
+ * Write the CTB and the packet length
+ */
+static int
+write_header( IOBUF out, int ctb, u32 len )
+{
+ if( !len )
+ ctb |= 3;
+ else if( len < 256 )
+ ;
+ else if( len < 65536 )
+ ctb |= 1;
+ else
+ ctb |= 2;
+ if( iobuf_put(out, ctb ) )
+ return -1;
+ if( !len ) {
+ iobuf_set_block_mode(out, 5 /*8196*/ );
+ }
+ else {
+ if( ctb & 2 ) {
+ iobuf_put(out, len >> 24 );
+ iobuf_put(out, len >> 16 );
+ }
+ if( ctb & 3 )
+ iobuf_put(out, len >> 8 );
+ if( iobuf_put(out, len ) )
+ return -1;
+ }
+ return 0;
+}
+
+static int
+write_version( IOBUF out, int ctb )
+{
+ if( iobuf_put( out, 3 ) )
+ return -1;
+ return 0;
+}
+
diff --git a/g10/checksig.c b/g10/checksig.c
new file mode 100644
index 000000000..7f00d5801
--- /dev/null
+++ b/g10/checksig.c
@@ -0,0 +1,96 @@
+/* checksig.c - check a signature
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "packet.h"
+#include "iobuf.h"
+#include "memory.h"
+#include "util.h"
+#include "cipher.h"
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: checksig textfile sigfile\n");
+ exit(1);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ IOBUF a;
+ PACKET pkt;
+ PKT_signature *sig;
+ int rc, result, c;
+ FILE *fp;
+ MD5HANDLE md5;
+
+ if( argc != 3 )
+ usage();
+ argc--; argv++;
+
+
+ if( !(a = iobuf_open(argv[1])) )
+ log_fatal("can't open '%s'\n", argv[1]);
+
+ init_packet(&pkt);
+ while( (rc=parse_packet(a, &pkt)) != -1 ) {
+ if( !rc && pkt.pkttype == PKT_SECKEY_ENC ) {
+ sig = pkt.pkt.signature;
+ printf("sig: keyid=%08lX%08lX: ", sig->keyid[0], sig->keyid[1] );
+ if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) {
+ if( !(fp = fopen(*argv, "rb")) )
+ log_fatal("can't open '%s'\n", *argv);
+ md5 = md5_open(0);
+ while( (c=getc(fp)) != EOF )
+ md5_putchar(md5, c );
+ fclose(fp);
+ result = md5_signature_check( sig, md5 );
+ md5_close(md5);
+ }
+ else
+ result = G10ERR_DIGEST_ALGO;
+ }
+ else
+ result = G10ERR_PUBKEY_ALGO;
+
+ if( !result )
+ fputs( "signature is good", stdout );
+ else if( result == G10ERR_DIGEST_ALGO )
+ printf( "Unknown digest algorithm %d", sig->d.rsa.digest_algo);
+ else if( result == G10ERR_PUBKEY_ALGO )
+ printf( "Unknown pubkey algorithm %d", sig->pubkey_algo);
+ else
+ fputs( g10_errstr(result), stdout);
+ putchar('\n');
+ }
+ free_packet(&pkt);
+ }
+
+ iobuf_close(a);
+ return 0;
+}
+
+
diff --git a/g10/compressed.c b/g10/compressed.c
new file mode 100644
index 000000000..cc0eafcfa
--- /dev/null
+++ b/g10/compressed.c
@@ -0,0 +1,114 @@
+/* compressed.c - process an compressed packet
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+/*#include <zlib.h>*/
+#include "util.h"
+#include "memory.h"
+#include "packet.h"
+
+
+/****************
+ * Handle a compressed packet
+ */
+int
+handle_compressed( PKT_compressed *zd )
+{
+ return -1;
+ #if 0
+ int c, zrc, rc = 0;
+ z_stream *zs = NULL;
+ unsigned inbufsize = 4096;
+ unsigned outbufsize = 16384;
+ unsigned n;
+ byte *inbuf = NULL;
+ byte *outbuf = NULL;
+
+ if( zd->algorithm != 1 ) {
+ rc =G10ERR_COMPR_ALGO;
+ goto leave;
+ }
+
+ zs = m_alloc_clear( sizeof *zs );
+ if( (zrc = inflateInit( zs )) != Z_OK ) {
+ log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
+ zrc == Z_MEM_ERROR ? "out of core" :
+ zrc == Z_VERSION_ERROR ? "invalid lib version" :
+ "unknown error" );
+ }
+
+ inbuf = m_alloc( inbufsize );
+ outbuf = m_alloc( outbufsize ); /* Fixme: put it in secure space? */
+
+ zs->next_in = inbuf;
+ zs->avail_in = inbufsize;
+ zs->next_out = outbuf;
+ zs->avail_out = outbufsize;
+
+ n = 0;
+ inbuf[n++] = 0x58;
+ inbuf[n++] = 0x09;
+ for(; n < inbufsize && (c=iobuf_get(zd->buf)) != -1 ; n++ )
+ inbuf[n] = c;
+ if( n ) {
+ { int i;
+ printf("start of compressed packet (n=%u):\n", n);
+ for(i=0; i < 32 && i < n; i++ )
+ printf(" %02x", inbuf[i] );
+ putchar('\n');
+ }
+ zrc = inflate( zs, Z_PARTIAL_FLUSH );
+ switch( zrc ) {
+ case Z_OK:
+ log_info("inflate returned okay\n");
+ break;
+ case Z_STREAM_END:
+ log_info("inflate returned stream-end\n");
+ break;
+ case Z_NEED_DICT:
+ case Z_DATA_ERROR:
+ case Z_STREAM_ERROR:
+ case Z_MEM_ERROR:
+ case Z_BUF_ERROR:
+ default:
+ if( zs->msg )
+ log_error("zlib inflate problem: %s\n", zs->msg );
+ else
+ log_error("zlib inflate problem: rc=%d\n", zrc );
+ break;
+ }
+ }
+
+ leave:
+ if( zs ) {
+ inflateEnd(zs);
+ m_free(zs);
+ }
+ m_free(inbuf);
+ m_free(outbuf);
+ return rc;
+ #endif
+}
+
diff --git a/g10/encode.c b/g10/encode.c
new file mode 100644
index 000000000..5b599ef00
--- /dev/null
+++ b/g10/encode.c
@@ -0,0 +1,470 @@
+/* encode.c - encode/sign data
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "options.h"
+#include "packet.h"
+#include "errors.h"
+#include "iobuf.h"
+#include "keydb.h"
+#include "memory.h"
+#include "util.h"
+#include "main.h"
+
+
+
+
+static int encode_simple( const char *filename, int mode );
+static IOBUF open_outfile( const char *iname );
+static int armor_filter( void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *ret_len);
+static int compress_filter( void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *ret_len);
+static int cipher_filter( void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *ret_len);
+
+
+
+typedef struct {
+ DEK *dek;
+ PKT_encr_data ed;
+ BLOWFISH_context *bf_ctx;
+ int header;
+} cipher_filter_context_t;
+
+
+
+
+
+
+/****************
+ * Encode FILENAME only with the symmetric cipher. Take input from
+ * stdin if FILENAME is NULL.
+ */
+int
+encode_symmetric( const char *filename )
+{
+ return encode_simple( filename, 1 );
+}
+
+/****************
+ * Encode FILENAME as literal data packet only. Take input from
+ * stdin if FILENAME is NULL.
+ */
+int
+encode_store( const char *filename )
+{
+ return encode_simple( filename, 0 );
+}
+
+static void
+write_comment( IOBUF out, const char *s )
+{
+ PACKET pkt;
+ size_t n = strlen(s);
+ int rc;
+
+ pkt.pkttype = PKT_COMMENT;
+ pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n - 1 );
+ pkt.pkt.comment->len = n;
+ strcpy(pkt.pkt.comment->data, s);
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build_packet(comment) failed: %s\n", g10_errstr(rc) );
+ free_packet( &pkt );
+}
+
+
+static int
+encode_simple( const char *filename, int mode )
+{
+ IOBUF inp, out;
+ PACKET pkt;
+ PKT_plaintext *pt;
+ int rc = 0;
+ u32 filesize;
+ cipher_filter_context_t cfx;
+
+ memset( &cfx, 0, sizeof cfx);
+
+ /* prepare iobufs */
+ if( !(inp = iobuf_open(filename)) ) {
+ log_error("can't open %s: %s\n", filename? filename: "[stdin]",
+ strerror(errno) );
+ return G10ERR_OPEN_FILE;
+ }
+
+ cfx.dek = NULL;
+ if( mode ) {
+ cfx.dek = m_alloc_secure( sizeof *cfx.dek );
+ cfx.dek->algo = DEFAULT_CIPHER_ALGO;
+ if( (rc = make_dek_from_passphrase( cfx.dek , 2 )) ) {
+ m_free(cfx.dek);
+ iobuf_close(inp);
+ log_error("error creating passphrase: %s\n", g10_errstr(rc) );
+ return rc;
+ }
+ }
+
+ if( !(out = open_outfile( filename )) ) {
+ iobuf_close(inp);
+ m_free(cfx.dek);
+ return G10ERR_CREATE_FILE; /* or user said: do not overwrite */
+ }
+
+ if( opt.armor )
+ iobuf_push_filter( out, armor_filter, NULL );
+
+ write_comment( out, "#Created by G10 pre-release " VERSION );
+
+ if( opt.compress )
+ iobuf_push_filter( out, compress_filter, NULL );
+
+
+ /* setup the inner packet */
+ if( filename ) {
+ pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
+ pt->namelen = strlen(filename);
+ memcpy(pt->name, filename, pt->namelen );
+ if( !(filesize = iobuf_get_filelength(inp)) )
+ log_info("warning: '%s' is an empty file\n", filename );
+ }
+ else { /* no filename */
+ pt = m_alloc( sizeof *pt - 1 );
+ pt->namelen = 0;
+ filesize = 0; /* stdin */
+ }
+ pt->timestamp = make_timestamp();
+ pt->mode = 'b';
+ pt->len = filesize;
+ pt->buf = inp;
+ pkt.pkttype = PKT_PLAINTEXT;
+ pkt.pkt.plaintext = pt;
+ cfx.ed.len = filesize? calc_packet_length( &pkt ) : 0;
+ cfx.ed.buf = NULL; /* not used! */
+
+ /* register the cipher filter */
+ if( mode )
+ iobuf_push_filter( out, cipher_filter, &cfx );
+
+ /* do the work */
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build_packet failed: %s\n", g10_errstr(rc) );
+
+ /* finish the stuff */
+ iobuf_close(inp);
+ iobuf_close(out); /* fixme: check returncode */
+ pt->buf = NULL;
+ free_packet(&pkt);
+ m_free(cfx.dek);
+ return rc;
+}
+
+/****************
+ * Encrypt the file with the given userids (or ask if none
+ * is supplied).
+ */
+int
+encode_crypt( const char *filename, STRLIST remusr )
+{
+ IOBUF inp, out;
+ PACKET pkt;
+ PKT_plaintext *pt;
+ PKT_pubkey_cert *pkc = NULL;
+ PKT_pubkey_enc *enc = NULL;
+ int last_rc, rc = 0;
+ u32 filesize;
+ cipher_filter_context_t cfx;
+ int any_names = 0;
+ STRLIST local_remusr = NULL;
+ char *ustr;
+
+ memset( &cfx, 0, sizeof cfx);
+
+ if( !remusr ) {
+ remusr = NULL; /* fixme: ask */
+ local_remusr = remusr;
+ }
+
+ /* prepare iobufs */
+ if( !(inp = iobuf_open(filename)) ) {
+ log_error("can't open %s: %s\n", filename? filename: "[stdin]",
+ strerror(errno) );
+ free_strlist(local_remusr);
+ return G10ERR_OPEN_FILE;
+ }
+ else if( opt.verbose )
+ log_error("reding from '%s'\n", filename? filename: "[stdin]");
+
+ if( !(out = open_outfile( filename )) ) {
+ iobuf_close(inp);
+ free_strlist(local_remusr);
+ return G10ERR_CREATE_FILE; /* or user said: do not overwrite */
+ }
+
+ if( opt.armor )
+ iobuf_push_filter( out, armor_filter, NULL );
+
+ write_comment( out, "#Created by G10 pre-release " VERSION );
+
+ if( opt.compress )
+ iobuf_push_filter( out, compress_filter, NULL );
+
+ /* create a session key */
+ cfx.dek = m_alloc_secure( sizeof *cfx.dek );
+ cfx.dek->algo = DEFAULT_CIPHER_ALGO;
+ make_session_key( cfx.dek );
+ if( DBG_CIPHER )
+ log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
+
+ /* loop over all user ids and build public key packets for each */
+ for(last_rc=0 ; remusr; remusr = remusr->next ) {
+ if( pkc )
+ free_pubkey_cert( pkc );
+ pkc = m_alloc_clear( sizeof *pkc );
+ pkc->pubkey_algo = DEFAULT_PUBKEY_ALGO;
+
+ if( (rc = get_pubkey_by_name( pkc, remusr->d )) ) {
+ last_rc = rc;
+ log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
+ continue;
+ }
+ /* build the pubkey packet */
+ enc = m_alloc_clear( sizeof *enc );
+ enc->pubkey_algo = pkc->pubkey_algo;
+ if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ RSA_public_key pkey;
+
+ mpi_get_keyid( pkc->d.rsa.rsa_n, enc->keyid );
+ enc->d.rsa.rsa_integer = encode_session_key( cfx.dek,
+ mpi_get_nbits(pkc->d.rsa.rsa_n) );
+ pkey.n = pkc->d.rsa.rsa_n;
+ pkey.e = pkc->d.rsa.rsa_e;
+ if( DBG_CIPHER )
+ log_mpidump("Plain DEK frame: ", enc->d.rsa.rsa_integer);
+ rsa_public( enc->d.rsa.rsa_integer, enc->d.rsa.rsa_integer, &pkey);
+ if( DBG_CIPHER )
+ log_mpidump("Encry DEK frame: ", enc->d.rsa.rsa_integer);
+ if( opt.verbose ) {
+ ustr = get_user_id_string( enc->keyid );
+ log_info("RSA enciphered for: %s\n", ustr );
+ m_free(ustr);
+ }
+ }
+ else {
+ last_rc = rc = G10ERR_PUBKEY_ALGO;
+ log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
+ free_pubkey_enc(enc);
+ continue;
+ }
+ /* and write it */
+ init_packet(&pkt);
+ pkt.pkttype = PKT_PUBKEY_ENC;
+ pkt.pkt.pubkey_enc = enc;
+ if( (rc = build_packet( out, &pkt )) ) {
+ last_rc = rc;
+ log_error("build pubkey_enc packet failed: %s\n", g10_errstr(rc) );
+ free_pubkey_enc(enc);
+ continue;
+ }
+ /* okay: a pubkey packet has been written */
+ free_pubkey_enc(enc);
+ any_names = 1;
+ }
+ if( pkc ) {
+ free_pubkey_cert( pkc );
+ pkc = NULL;
+ }
+ if( !any_names ) {
+ log_error("no valid keys - aborting further processing\n");
+ iobuf_close(inp);
+ iobuf_cancel(out);
+ m_free(cfx.dek); /* free and burn the session key */
+ free_strlist(local_remusr);
+ return last_rc;
+ }
+
+ /* setup the inner packet */
+ if( filename ) {
+ pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
+ pt->namelen = strlen(filename);
+ memcpy(pt->name, filename, pt->namelen );
+ if( !(filesize = iobuf_get_filelength(inp)) )
+ log_info("warning: '%s' is an empty file\n", filename );
+ }
+ else { /* no filename */
+ pt = m_alloc( sizeof *pt - 1 );
+ pt->namelen = 0;
+ filesize = 0; /* stdin */
+ }
+ pt->timestamp = make_timestamp();
+ pt->mode = 'b';
+ pt->len = filesize;
+ pt->buf = inp;
+ init_packet(&pkt);
+ pkt.pkttype = PKT_PLAINTEXT;
+ pkt.pkt.plaintext = pt;
+ cfx.ed.len = filesize? calc_packet_length( &pkt ) : 0;
+ cfx.ed.buf = NULL; /* not used! */
+
+ /* register the cipher filter */
+ iobuf_push_filter( out, cipher_filter, &cfx );
+
+ /* do the work */
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build_packet failed: %s\n", g10_errstr(rc) );
+
+ /* finish the stuff */
+ iobuf_close(inp);
+ iobuf_close(out); /* fixme: check returncode */
+ pt->buf = NULL;
+ free_packet(&pkt);
+ m_free(cfx.dek);
+ free_strlist(local_remusr);
+ return rc;
+}
+
+
+/****************
+ * Make an output filename for the inputfile INAME.
+ * Returns an
+ */
+static IOBUF
+open_outfile( const char *iname )
+{
+ IOBUF a = NULL;
+ int rc;
+
+ if( (!iname && !opt.outfile) || opt.outfile_is_stdout ) {
+ if( !(a = iobuf_create(NULL)) )
+ log_error("can't open [stdout]: %s\n", strerror(errno) );
+ else if( opt.verbose )
+ log_info("writing to stdout\n");
+ }
+ else {
+ char *buf=NULL;
+ const char *name;
+
+ if( opt.outfile )
+ name = opt.outfile;
+ else {
+ buf = m_alloc(strlen(iname)+4+1);
+ strcpy(stpcpy(buf,iname), ".g10");
+ name = buf;
+ }
+ if( !(rc=overwrite_filep( name )) ) {
+ if( !(a = iobuf_create( name )) )
+ log_error("can't create %s: %s\n", name, strerror(errno) );
+ else if( opt.verbose )
+ log_info("writing to '%s'\n", name );
+ }
+ else if( rc != -1 )
+ log_error("oops: overwrite_filep(%s): %s\n", name, g10_errstr(rc) );
+ m_free(buf);
+ }
+ return a;
+}
+
+static int
+armor_filter( void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *ret_len)
+{
+ if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "armor_filter";
+ }
+ return 0;
+}
+
+static int
+compress_filter( void *opaque, int control,
+ IOBUF a, byte *buf, size_t *ret_len)
+{
+ size_t size = *ret_len;
+ int rc=0;
+
+ if( control == IOBUFCTRL_FLUSH ) {
+ assert(a);
+ if( iobuf_write( a, buf, size ) )
+ rc = G10ERR_WRITE_FILE;
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "compress_filter";
+ }
+ return rc;
+}
+
+
+/****************
+ * The filter is used to encipher data.
+ */
+static int
+cipher_filter( void *opaque, int control,
+ IOBUF a, byte *buf, size_t *ret_len)
+{
+ size_t size = *ret_len;
+ cipher_filter_context_t *cfx = opaque;
+ int rc=0;
+
+ if( control == IOBUFCTRL_FLUSH ) {
+ assert(a);
+ if( !cfx->header ) {
+ PACKET pkt;
+ byte temp[10];
+
+ pkt.pkttype = PKT_ENCR_DATA;
+ pkt.pkt.encr_data = &cfx->ed;
+ if( build_packet( a, &pkt ))
+ log_bug("build_packet(ENCR_DATA) failed\n");
+ randomize_buffer( temp, 8, 1 );
+ temp[8] = temp[6];
+ temp[9] = temp[7];
+ if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH ) {
+ cfx->bf_ctx = m_alloc_secure( sizeof *cfx->bf_ctx );
+ blowfish_setkey( cfx->bf_ctx, cfx->dek->key, cfx->dek->keylen );
+ blowfish_setiv( cfx->bf_ctx, NULL );
+ blowfish_encode_cfb( cfx->bf_ctx, temp, temp, 10);
+ }
+ else
+ log_bug("no cipher algo %d\n", cfx->dek->algo);
+
+ iobuf_write(a, temp, 10);
+ cfx->header=1;
+ }
+
+ if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH )
+ blowfish_encode_cfb( cfx->bf_ctx, buf, buf, size);
+ if( iobuf_write( a, buf, size ) )
+ rc = G10ERR_WRITE_FILE;
+ }
+ else if( control == IOBUFCTRL_FREE ) {
+ if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH )
+ m_free(cfx->bf_ctx);
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "cipher_filter";
+ }
+ return rc;
+}
+
diff --git a/g10/encr-data.c b/g10/encr-data.c
new file mode 100644
index 000000000..5c047e90d
--- /dev/null
+++ b/g10/encr-data.c
@@ -0,0 +1,122 @@
+/* encr-data.c - process an encrypted data packet
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "memory.h"
+#include "packet.h"
+#include "mpi.h"
+#include "cipher.h"
+
+
+static int decode_filter( void *opaque, int control, IOBUF a,
+ byte *buf, size_t *ret_len);
+
+typedef struct {
+ BLOWFISH_context *bf_ctx;
+} decode_filter_ctx_t;
+
+
+
+/****************
+ * Decrypt the data, specified by ED with the key DEK.
+ */
+int
+decrypt_data( PKT_encr_data *ed, DEK *dek )
+{
+ decode_filter_ctx_t dfx;
+ byte *p;
+ int c, i;
+ byte temp[16];
+
+
+ if( dek->algo != CIPHER_ALGO_BLOWFISH )
+ return G10ERR_CIPHER_ALGO;
+ if( ed->len && ed->len < 10 )
+ log_bug("Nanu\n"); /* oops: found a bug */
+
+ dfx.bf_ctx = m_alloc_secure( sizeof *dfx.bf_ctx );
+ blowfish_setkey( dfx.bf_ctx, dek->key, dek->keylen );
+ blowfish_setiv( dfx.bf_ctx, NULL );
+
+ if( ed->len ) {
+ iobuf_set_limit( ed->buf, ed->len );
+
+ for(i=0; i < 10 && ed->len; i++, ed->len-- )
+ temp[i] = iobuf_get(ed->buf);
+ }
+ else {
+ for(i=0; i < 10; i++ )
+ if( (c=iobuf_get(ed->buf)) == -1 )
+ break;
+ else
+ temp[i] = c;
+ }
+ blowfish_decode_cfb( dfx.bf_ctx, temp, temp, 10);
+ p = temp;
+ if( p[6] != p[8] || p[7] != p[9] ) {
+ m_free(dfx.bf_ctx);
+ return G10ERR_BAD_KEY;
+ }
+ iobuf_push_filter( ed->buf, decode_filter, &dfx );
+ proc_packets(ed->buf);
+ iobuf_pop_filter( ed->buf, decode_filter, &dfx );
+ if( ed->len )
+ iobuf_set_limit( ed->buf, 0 ); /* disable the readlimit */
+ else
+ iobuf_clear_eof( ed->buf );
+ ed->buf = NULL;
+ m_free(dfx.bf_ctx);
+ return 0;
+}
+
+static int
+decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len)
+{
+ decode_filter_ctx_t *fc = opaque;
+ size_t n, size = *ret_len;
+ int rc = 0;
+ int c;
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ assert(a);
+ for(n=0; n < size; n++ ) {
+ if( (c = iobuf_get(a)) == -1 )
+ break;
+ buf[n] = c;
+ }
+
+ if( n )
+ blowfish_decode_cfb( fc->bf_ctx, buf, buf, n);
+ else
+ rc = -1; /* eof */
+ *ret_len = n;
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "decode_filter";
+ }
+ return rc;
+}
+
+
diff --git a/g10/filter.h b/g10/filter.h
new file mode 100644
index 000000000..8cbb26af7
--- /dev/null
+++ b/g10/filter.h
@@ -0,0 +1,35 @@
+/* filter.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_FILTER_H
+#define G10_FILTER_H
+
+#include "cipher.h"
+
+typedef struct {
+ MD5HANDLE md5; /* if !NULL create md5 */
+ RMDHANDLE rmd160; /* if !NULL create rmd160 */
+ size_t maxbuf_size;
+} md_filter_context_t;
+
+
+/*-- mdfilter.c --*/
+int md_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len);
+
+#endif /*G10_FILTER_H*/
diff --git a/g10/free-packet.c b/g10/free-packet.c
new file mode 100644
index 000000000..f4f38baa4
--- /dev/null
+++ b/g10/free-packet.c
@@ -0,0 +1,198 @@
+/* free-packet.c - cleanup stuff for packets
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "packet.h"
+#include "iobuf.h"
+#include "mpi.h"
+#include "util.h"
+#include "cipher.h"
+#include "memory.h"
+
+
+void
+free_pubkey_enc( PKT_pubkey_enc *enc )
+{
+ mpi_free( enc->d.rsa.rsa_integer );
+ m_free(enc);
+}
+
+void
+free_seckey_enc( PKT_signature *enc )
+{
+ mpi_free( enc->d.rsa.rsa_integer );
+ m_free(enc);
+}
+
+void
+free_pubkey_cert( PKT_pubkey_cert *cert )
+{
+ mpi_free( cert->d.rsa.rsa_n );
+ mpi_free( cert->d.rsa.rsa_e );
+ md5_close( cert->mfx.md5 );
+ rmd160_close( cert->mfx.rmd160 );
+ m_free(cert);
+}
+
+PKT_pubkey_cert *
+copy_pubkey_cert( PKT_pubkey_cert *d, PKT_pubkey_cert *s )
+{
+ if( !d )
+ d = m_alloc(sizeof *d);
+ memcpy( d, s, sizeof *d );
+ d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n );
+ d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e );
+ d->mfx.md5 = NULL;
+ d->mfx.rmd160 =NULL;
+ return d;
+}
+
+void
+free_seckey_cert( PKT_seckey_cert *cert )
+{
+ mpi_free( cert->d.rsa.rsa_n );
+ mpi_free( cert->d.rsa.rsa_e );
+ if( cert->d.rsa.is_protected ) {
+ m_free( cert->d.rsa.rsa_d );
+ m_free( cert->d.rsa.rsa_p );
+ m_free( cert->d.rsa.rsa_q );
+ m_free( cert->d.rsa.rsa_u );
+ }
+ else {
+ mpi_free( cert->d.rsa.rsa_d );
+ mpi_free( cert->d.rsa.rsa_p );
+ mpi_free( cert->d.rsa.rsa_q );
+ mpi_free( cert->d.rsa.rsa_u );
+ }
+ m_free(cert);
+}
+
+void
+free_comment( PKT_comment *rem )
+{
+ m_free(rem);
+}
+
+void
+free_user_id( PKT_user_id *uid )
+{
+ m_free(uid);
+}
+
+void
+free_compressed( PKT_compressed *zd )
+{
+ if( zd->buf ) { /* have to skip some bytes */
+ /* don't have any informations about the length, so
+ * we assume this is the last packet */
+ while( iobuf_get(zd->buf) != -1 )
+ ;
+ }
+ m_free(zd);
+}
+
+void
+free_encr_data( PKT_encr_data *ed )
+{
+ if( ed->buf ) { /* have to skip some bytes */
+ if( iobuf_in_block_mode(ed->buf) ) {
+ while( iobuf_get(ed->buf) != -1 )
+ ;
+ iobuf_set_block_mode(ed->buf, 0);
+ }
+ else {
+ for( ; ed->len; ed->len-- ) /* skip the packet */
+ iobuf_get(ed->buf);
+ }
+ }
+ m_free(ed);
+}
+
+
+void
+free_plaintext( PKT_plaintext *pt )
+{
+ if( pt->buf ) { /* have to skip some bytes */
+ if( iobuf_in_block_mode(pt->buf) ) {
+ while( iobuf_get(pt->buf) != -1 )
+ ;
+ iobuf_set_block_mode(pt->buf, 0);
+ }
+ else {
+ for( ; pt->len; pt->len-- ) /* skip the packet */
+ iobuf_get(pt->buf);
+ }
+ }
+ m_free(pt);
+}
+
+/****************
+ * Free the packet in pkt.
+ */
+void
+free_packet( PACKET *pkt )
+{
+ if( !pkt || !pkt->pkt.generic )
+ return;
+
+ if( DBG_MEMORY )
+ log_debug("free_packet() type=%d\n", pkt->pkttype );
+
+ switch( pkt->pkttype ) {
+ case PKT_SIGNATURE:
+ free_seckey_enc( pkt->pkt.signature );
+ break;
+ case PKT_PUBKEY_ENC:
+ free_pubkey_enc( pkt->pkt.pubkey_enc );
+ break;
+ case PKT_PUBKEY_CERT:
+ free_pubkey_cert( pkt->pkt.pubkey_cert );
+ break;
+ case PKT_SECKEY_CERT:
+ free_seckey_cert( pkt->pkt.seckey_cert );
+ break;
+ case PKT_COMMENT:
+ free_comment( pkt->pkt.comment );
+ break;
+ case PKT_USER_ID:
+ free_user_id( pkt->pkt.user_id );
+ break;
+ case PKT_COMPR_DATA:
+ free_compressed( pkt->pkt.compressed);
+ break;
+ case PKT_ENCR_DATA:
+ free_encr_data( pkt->pkt.encr_data );
+ break;
+ case PKT_PLAINTEXT:
+ free_plaintext( pkt->pkt.plaintext );
+ break;
+ default:
+ m_free( pkt->pkt.generic );
+ break;
+ }
+ pkt->pkt.generic = NULL;
+}
+
+
diff --git a/g10/g10.c b/g10/g10.c
new file mode 100644
index 000000000..1cf1d769a
--- /dev/null
+++ b/g10/g10.c
@@ -0,0 +1,219 @@
+/* g10.c - The G10 re-install utility
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "packet.h"
+#include "iobuf.h"
+#include "memory.h"
+#include "util.h"
+#include "main.h"
+#include "options.h"
+#include "keydb.h"
+#include "mpi.h"
+#include "cipher.h"
+
+
+const char *
+strusage( int level )
+{
+ const char *p;
+ switch( level ) {
+ case 10:
+ case 0: p = "g10 - v" VERSION "; "
+ "Copyright 1997 Werner Koch (dd9jn)" ; break;
+ case 13: p = "g10"; break;
+ case 14: p = VERSION; break;
+ case 1:
+ case 11: p = "Usage: g10 [options] [files] (-h for help)";
+ break;
+ case 2:
+ case 12: p =
+ "\nSyntax: g10 [options] [files]\n"
+ "sign, check, encrypt or decrypt\n"
+ "default operation depends on the input data\n";
+ break;
+ default: p = default_strusage(level);
+ }
+ return p;
+}
+
+static void
+set_debug(void)
+{
+ if( opt.debug & DBG_MEMORY_VALUE )
+ memory_debug_mode = 1;
+ if( opt.debug & DBG_MEMSTAT_VALUE )
+ memory_stat_debug_mode = 1;
+ if( opt.debug & DBG_MPI_VALUE )
+ mpi_debug_mode = 1;
+ if( opt.debug & DBG_CIPHER_VALUE )
+ cipher_debug_mode = 1;
+}
+
+
+int
+main( int argc, char **argv )
+{
+ static ARGPARSE_OPTS opts[] = {
+ { 'a', "armor", 0, "create ascii armored output"},
+ { 'v', "verbose", 0, "verbose" },
+ { 'z', NULL, 1, "set compress level (0 disables)" },
+ { 'b', "batch", 0, "batch mode: never ask" },
+ { 'n', "dry-run", 0, "don't make any changes" },
+ { 'c', "symmetric", 0, "do only a symmetric encryption" },
+ { 'o', "output", 2, "use as output file" },
+ { 501, "yes", 0, "assume yes on most questions"},
+ { 502, "no", 0, "assume no on most questions"},
+ { 503, "make-key", 0, "generate a new key pair" },
+ { 504, "add-key", 0, "add key to the public keyring" },
+ { 505, "delete-key",0, "remove key from public keyring" },
+ { 506, "sign-key" ,0, "make a signature on a key in the keyring" },
+ { 507, "store", 0, "store only" },
+ { 508, "check-key" ,0, "check signatures on a key in the keyring" },
+ { 509, "keyring" ,2, "add this keyring to the list of keyrings" },
+ { 's', "sign", 0, "make a signature"},
+ { 'e', "encrypt", 0, "encrypt data" },
+ { 'd', "decrypt", 0, "decrypt data (default)" },
+ { 'c', "check", 0, "check a signature (default)" },
+ { 'l', "local-user",2, "use this user-id to sign or decrypt" },
+ { 'r', "remote-user", 2, "use this user-id for encryption" },
+ { 510, "debug" ,4|16, "set debugging flags" },
+ { 511, "debug-all" ,0, "enable full debugging"},
+ { 512, "cache-all" ,0, "hold everything in memory"},
+ { 513, "gen-prime" , 1, "generate a prime of length n" },
+ { 514, "gen-key" , 0, "generate a key pair" },
+ {0} };
+ ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
+ IOBUF a;
+ int rc;
+ enum { aNull, aSym, aStore, aEncr, aPrimegen, aKeygen,
+ } action = aNull;
+ const char *fname, *fname_print;
+ STRLIST sl, remusr= NULL;
+ int nrings=0;
+
+ opt.compress = -1; /* defaults to default compression level */
+ while( arg_parse( &pargs, opts) ) {
+ switch( pargs.r_opt ) {
+ case 'v': opt.verbose++; break;
+ case 'z':
+ opt.compress = pargs.r.ret_int;
+ break;
+ case 'a': opt.armor = 1; break;
+ case 'c': action = aSym; break;
+ case 'e': action = aEncr; break;
+ case 'o': opt.outfile = pargs.r.ret_str;
+ if( opt.outfile[0] == '-' && !opt.outfile[1] )
+ opt.outfile_is_stdout = 1;
+ break;
+ case 'b': opt.batch = 1; break;
+ case 501: opt.answer_yes = 1; break;
+ case 502: opt.answer_no = 1; break;
+ case 507: action = aStore; break;
+ case 508: opt.check_sigs = 1; break;
+ case 509: add_keyring(pargs.r.ret_str); nrings++; break;
+ case 510: opt.debug |= pargs.r.ret_ulong; break;
+ case 511: opt.debug = ~0; break;
+ case 512: opt.cache_all = 1; break;
+ case 'r': /* store the remote users */
+ sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
+ strcpy(sl->d, pargs.r.ret_str);
+ sl->next = remusr;
+ remusr = sl;
+ break;
+ case 513: action = aPrimegen; break;
+ case 514: action = aKeygen; break;
+ default : pargs.err = 2; break;
+ }
+ }
+ set_debug();
+ if( opt.verbose > 1 )
+ set_packet_list_mode(1);
+
+ if( !nrings ) { /* add default rings */
+ add_keyring("../keys/ring.pgp");
+ add_keyring("../keys/pubring.g10");
+ }
+
+ if( argc ) {
+ fname_print = fname = *argv;
+ }
+ else {
+ fname_print = "[stdin]";
+ fname = NULL;
+ }
+
+ switch( action ) {
+ case aStore: /* only store the file */
+ if( argc > 1 )
+ usage(1);
+ if( (rc = encode_store(fname)) )
+ log_error("encode_store('%s'): %s\n",
+ fname_print, g10_errstr(rc) );
+ break;
+
+ case aSym: /* encrypt the given file only with the symmetric cipher */
+ if( argc > 1 )
+ usage(1);
+ if( (rc = encode_symmetric(fname)) )
+ log_error("encode_symmetric('%s'): %s\n",
+ fname_print, g10_errstr(rc) );
+ break;
+
+ case aEncr: /* encrypt the given file */
+ if( argc > 1 )
+ usage(1);
+ if( (rc = encode_crypt(fname,remusr)) )
+ log_error("encode_crypt('%s'): %s\n",
+ fname_print, g10_errstr(rc) );
+ break;
+
+ case aPrimegen:
+ if( argc )
+ usage(1);
+ mpi_print( stdout, generate_random_prime( pargs.r.ret_int ), 1);
+ putchar('\n');
+ break;
+
+ case aKeygen: /* generate a key (interactive) */
+ if( argc )
+ usage(1);
+ generate_keypair();
+ break;
+
+ default:
+ if( argc > 1 )
+ usage(1);
+ if( !(a = iobuf_open(fname)) )
+ log_fatal("can't open '%s'\n", fname_print);
+ proc_packets( a );
+ iobuf_close(a);
+ break;
+ }
+
+ /* cleanup */
+ FREE_STRLIST(remusr);
+ return 0;
+}
+
+
diff --git a/g10/getkey.c b/g10/getkey.c
new file mode 100644
index 000000000..0bd14063b
--- /dev/null
+++ b/g10/getkey.c
@@ -0,0 +1,475 @@
+/* getkey.c - Get a key from the database
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "packet.h"
+#include "memory.h"
+#include "iobuf.h"
+#include "keydb.h"
+#include "options.h"
+
+#define MAX_PKC_CACHE_ENTRIES 500
+
+
+typedef struct keyid_list {
+ struct keyid_list *next;
+ u32 keyid[2];
+} *keyid_list_t;
+
+typedef struct user_id_db {
+ struct user_id_db *next;
+ u32 keyid[2];
+ int len;
+ char name[1];
+} *user_id_db_t;
+
+typedef struct pkc_cache_entry {
+ struct pkc_cache_entry *next;
+ u32 keyid[2];
+ PKT_pubkey_cert *pkc;
+} *pkc_cache_entry_t;
+
+static STRLIST keyrings;
+
+static keyid_list_t unknown_keyids;
+static user_id_db_t user_id_db;
+static pkc_cache_entry_t pkc_cache;
+static int pkc_cache_entries; /* number of entries in pkc cache */
+
+
+static int scan_keyring( PKT_pubkey_cert *pkc, u32 *keyid,
+ const char *name, const char *filename );
+static int scan_secret_keyring( PACKET *pkt, u32 *keyid, const char *filename);
+
+
+void
+add_keyring( const char *name )
+{
+ STRLIST sl;
+
+ /* FIXME: check wether this one is available etc */
+ /* my be we should do this later */
+ sl = m_alloc( sizeof *sl + strlen(name) );
+ strcpy(sl->d, name );
+ sl->next = keyrings;
+ keyrings = sl;
+}
+
+
+void
+cache_pubkey_cert( PKT_pubkey_cert *pkc )
+{
+ pkc_cache_entry_t ce;
+ u32 keyid[2];
+
+ if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_get_keyid( pkc->d.rsa.rsa_n, keyid );
+ }
+ else
+ return; /* don't know how to get the keyid */
+
+ for( ce = pkc_cache; ce; ce = ce->next )
+ if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) {
+ if( DBG_CACHE )
+ log_debug("cache_pubkey_cert: already in cache\n");
+ return;
+ }
+
+ if( pkc_cache_entries > MAX_PKC_CACHE_ENTRIES ) {
+ /* FIMXE: use another algorithm to free some cache slots */
+ if( pkc_cache_entries == MAX_PKC_CACHE_ENTRIES ) {
+ pkc_cache_entries++;
+ log_info("too many entries in pkc cache - disabled\n");
+ }
+ ce = pkc_cache;
+ free_pubkey_cert( ce->pkc );
+ }
+ else {
+ pkc_cache_entries++;
+ ce = m_alloc( sizeof *ce );
+ ce->next = pkc_cache;
+ pkc_cache = ce;
+ }
+ ce->pkc = copy_pubkey_cert( NULL, pkc );
+ ce->keyid[0] = keyid[0];
+ ce->keyid[1] = keyid[1];
+}
+
+
+/****************
+ * Store the association of keyid and userid
+ */
+void
+cache_user_id( PKT_user_id *uid, u32 *keyid )
+{
+ user_id_db_t r;
+
+ for(r=user_id_db; r; r = r->next )
+ if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
+ if( DBG_CACHE )
+ log_debug("cache_user_id: already in cache\n");
+ return;
+ }
+
+ r = m_alloc( sizeof *r + uid->len-1 );
+ r->keyid[0] = keyid[0];
+ r->keyid[1] = keyid[1];
+ r->len = uid->len;
+ memcpy(r->name, uid->name, r->len);
+ r->next = user_id_db;
+ user_id_db = r;
+}
+
+
+
+/****************
+ * Get a public key and store it into the allocated pkc
+ * can be called with PKC set to NULL to just read it into some
+ * internal structures.
+ */
+int
+get_pubkey( PKT_pubkey_cert *pkc, u32 *keyid )
+{
+ keyid_list_t kl;
+ int internal = 0;
+ int rc = 0;
+ pkc_cache_entry_t ce;
+ STRLIST sl;
+
+
+ if( opt.cache_all && !pkc_cache ) {
+ log_info("reading all entries ...\n");
+ for(sl = keyrings; sl; sl = sl->next )
+ if( !scan_keyring( NULL, NULL, NULL, sl->d ) )
+ goto leave;
+ log_info("cached %d entries\n", pkc_cache_entries);
+ }
+
+
+ /* lets see wether we checked the keyid already */
+ for( kl = unknown_keyids; kl; kl = kl->next )
+ if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
+ return G10ERR_NO_PUBKEY; /* already checked and not found */
+
+ /* 1. Try to get it from our cache */
+ for( ce = pkc_cache; ce; ce = ce->next )
+ if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) {
+ if( pkc )
+ copy_pubkey_cert( pkc, ce->pkc );
+ return 0;
+ }
+
+ /* more init stuff */
+ if( !pkc ) {
+ pkc = m_alloc_clear( sizeof *pkc );
+ internal++;
+ }
+
+
+ /* 2. Try to get it from the keyrings */
+ for(sl = keyrings; sl; sl = sl->next )
+ if( !scan_keyring( pkc, keyid, NULL, sl->d ) )
+ goto leave;
+
+ /* 3. Try to get it from a key server */
+
+ /* 4. not found: store it for future reference */
+ kl = m_alloc( sizeof *kl );
+ kl->keyid[0] = keyid[0];
+ kl->keyid[1] = keyid[1];
+ kl->next = unknown_keyids;
+ unknown_keyids = kl;
+ rc = G10ERR_NO_PUBKEY;
+
+ leave:
+ if( !rc )
+ cache_pubkey_cert( pkc );
+ if( internal )
+ m_free(pkc);
+ return rc;
+}
+
+
+/****************
+ * Try to get the pubkey by the userid. This functions looks for the
+ * first pubkey certificate which has the given name in a user_id.
+ * if pkc has the pubkey algo set, the function will only return
+ * a pubkey with that algo.
+ */
+int
+get_pubkey_by_name( PKT_pubkey_cert *pkc, const char *name )
+{
+ int internal = 0;
+ int rc = 0;
+ STRLIST sl;
+
+ if( !pkc ) {
+ pkc = m_alloc_clear( sizeof *pkc );
+ internal++;
+ }
+
+ /* 2. Try to get it from the keyrings */
+ for(sl = keyrings; sl; sl = sl->next )
+ if( !scan_keyring( pkc, NULL, name, sl->d ) )
+ goto leave;
+
+ /* 3. Try to get it from a key server */
+
+ /* 4. not found: store it for future reference */
+ rc = G10ERR_NO_PUBKEY;
+
+ leave:
+ if( internal )
+ m_free(pkc);
+ return rc;
+}
+
+
+/****************
+ * Get a secret key and store it into skey
+ */
+int
+get_seckey( RSA_secret_key *skey, u32 *keyid )
+{
+ int rc=0;
+ PACKET pkt;
+
+ init_packet( &pkt );
+ if( !(rc=scan_secret_keyring( &pkt, keyid, "../keys/secring.g10" ) ) )
+ goto found;
+ /* fixme: look at other places */
+ goto leave;
+
+ found:
+ /* get the secret key (this may prompt for a passprase to
+ * unlock the secret key
+ */
+ if( (rc = check_secret_key( pkt.pkt.seckey_cert )) )
+ goto leave;
+ if( pkt.pkt.seckey_cert->pubkey_algo != PUBKEY_ALGO_RSA ) {
+ rc = G10ERR_PUBKEY_ALGO; /* unsupport algorithm */
+ goto leave;
+ }
+ /* copy the stuff to SKEY. skey is then the owner */
+ skey->e = pkt.pkt.seckey_cert->d.rsa.rsa_e;
+ skey->n = pkt.pkt.seckey_cert->d.rsa.rsa_n;
+ skey->p = pkt.pkt.seckey_cert->d.rsa.rsa_p;
+ skey->q = pkt.pkt.seckey_cert->d.rsa.rsa_q;
+ skey->d = pkt.pkt.seckey_cert->d.rsa.rsa_d;
+ skey->u = pkt.pkt.seckey_cert->d.rsa.rsa_u;
+ /* set all these to NULL, so that free_packet will not destroy
+ * these integers. */
+ pkt.pkt.seckey_cert->d.rsa.rsa_e = NULL;
+ pkt.pkt.seckey_cert->d.rsa.rsa_n = NULL;
+ pkt.pkt.seckey_cert->d.rsa.rsa_p = NULL;
+ pkt.pkt.seckey_cert->d.rsa.rsa_q = NULL;
+ pkt.pkt.seckey_cert->d.rsa.rsa_d = NULL;
+ pkt.pkt.seckey_cert->d.rsa.rsa_u = NULL;
+
+ leave:
+ free_packet(&pkt);
+ return rc;
+}
+
+
+/****************
+ * scan the keyring and look for either the keyid or the name.
+ */
+static int
+scan_keyring( PKT_pubkey_cert *pkc, u32 *keyid,
+ const char *name, const char *filename )
+{
+ int rc=0;
+ int found = 0;
+ IOBUF a;
+ PACKET pkt;
+ int save_mode;
+ u32 akeyid[2];
+ PKT_pubkey_cert *last_pk = NULL;
+
+ assert( !keyid || !name );
+
+ if( opt.cache_all && (name || keyid) )
+ return G10ERR_NO_PUBKEY;
+
+ if( !(a = iobuf_open( filename ) ) ) {
+ log_debug("scan_keyring: can't open '%s'\n", filename );
+ return G10ERR_KEYRING_OPEN;
+ }
+
+ if( name )
+ log_debug("scan_keyring %s for '%s'\n", filename, name );
+ else if( keyid )
+ log_debug("scan_keyring %s for %08lx %08lx\n", filename,
+ keyid[0], keyid[1] );
+ else
+ log_debug("scan_keyring %s (all)\n", filename );
+
+ save_mode = set_packet_list_mode(0);
+ init_packet(&pkt);
+ while( (rc=parse_packet(a, &pkt)) != -1 ) {
+ if( rc )
+ ; /* e.g. unknown packet */
+ else if( keyid && found && pkt.pkttype == PKT_PUBKEY_CERT ) {
+ log_error("Hmmm, pubkey without an user id in '%s'\n", filename);
+ goto leave;
+ }
+ else if( keyid && pkt.pkttype == PKT_PUBKEY_CERT ) {
+ switch( pkt.pkt.pubkey_cert->pubkey_algo ) {
+ case PUBKEY_ALGO_RSA:
+ mpi_get_keyid( pkt.pkt.pubkey_cert->d.rsa.rsa_n , akeyid );
+ if( akeyid[0] == keyid[0] && akeyid[1] == keyid[1] ) {
+ copy_pubkey_cert( pkc, pkt.pkt.pubkey_cert );
+ found++;
+ }
+ break;
+ default:
+ log_error("cannot handle pubkey algo %d\n",
+ pkt.pkt.pubkey_cert->pubkey_algo);
+ }
+ }
+ else if( keyid && found && pkt.pkttype == PKT_USER_ID ) {
+ cache_user_id( pkt.pkt.user_id, keyid );
+ goto leave;
+ }
+ else if( name && pkt.pkttype == PKT_PUBKEY_CERT ) {
+ if( last_pk )
+ free_pubkey_cert(last_pk);
+ last_pk = pkt.pkt.pubkey_cert;
+ pkt.pkt.pubkey_cert = NULL;
+ }
+ else if( name && pkt.pkttype == PKT_USER_ID ) {
+ if( memistr( pkt.pkt.user_id->name, pkt.pkt.user_id->len, name )) {
+ if( !last_pk )
+ log_error("Ooops: no pubkey for userid '%.*s'\n",
+ pkt.pkt.user_id->len, pkt.pkt.user_id->name);
+ else if( pkc->pubkey_algo &&
+ pkc->pubkey_algo != last_pk->pubkey_algo )
+ log_info("skipping id '%.*s': want algo %d, found %d\n",
+ pkt.pkt.user_id->len, pkt.pkt.user_id->name,
+ pkc->pubkey_algo, last_pk->pubkey_algo );
+ else {
+ copy_pubkey_cert( pkc, last_pk );
+ goto leave;
+ }
+ }
+ }
+ else if( !keyid && !name && pkt.pkttype == PKT_PUBKEY_CERT ) {
+ if( last_pk )
+ free_pubkey_cert(last_pk);
+ last_pk = pkt.pkt.pubkey_cert;
+ pkt.pkt.pubkey_cert = NULL;
+ }
+ else if( !keyid && !name && pkt.pkttype == PKT_USER_ID ) {
+ if( !last_pk )
+ log_error("Ooops: no pubkey for userid '%.*s'\n",
+ pkt.pkt.user_id->len, pkt.pkt.user_id->name);
+ else {
+ if( last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_get_keyid( last_pk->d.rsa.rsa_n , akeyid );
+ cache_user_id( pkt.pkt.user_id, akeyid );
+ }
+ cache_pubkey_cert( last_pk );
+ }
+ }
+ free_packet(&pkt);
+ }
+ rc = G10ERR_NO_PUBKEY;
+
+ leave:
+ if( last_pk )
+ free_pubkey_cert(last_pk);
+ free_packet(&pkt);
+ iobuf_close(a);
+ set_packet_list_mode(save_mode);
+ return rc;
+}
+
+
+/****************
+ * This is the function to get a secret key. We use an extra function,
+ * so that we can easily add special handling for secret keyrings
+ * PKT returns the secret key certificate.
+ */
+static int
+scan_secret_keyring( PACKET *pkt, u32 *keyid, const char *filename )
+{
+ IOBUF a;
+ int save_mode, rc;
+ u32 akeyid[2];
+
+ if( !(a = iobuf_open( filename ) ) ) {
+ log_debug("scan_secret_keyring: can't open '%s'\n", filename );
+ return G10ERR_KEYRING_OPEN;
+ }
+
+ save_mode = set_packet_list_mode(0);
+ init_packet(pkt);
+ while( (rc=parse_packet(a, pkt)) != -1 ) {
+ if( rc )
+ ;
+ else if( pkt->pkttype == PKT_SECKEY_CERT ) {
+ mpi_get_keyid( pkt->pkt.seckey_cert->d.rsa.rsa_n , akeyid );
+ if( akeyid[0] == keyid[0] && akeyid[1] == keyid[1] ) {
+ iobuf_close(a);
+ set_packet_list_mode(save_mode);
+ return 0; /* got it */
+ }
+ }
+ free_packet(pkt);
+ }
+
+ iobuf_close(a);
+ set_packet_list_mode(save_mode);
+ return G10ERR_NO_SECKEY;
+}
+
+
+
+/****************
+ * Return a string with a printable representation of the user_id.
+ * this string must be freed by m_free.
+ */
+char*
+get_user_id_string( u32 *keyid )
+{
+ user_id_db_t r;
+ char *p;
+ int pass=0;
+ /* try it two times; second pass reads from keyrings */
+ do {
+ for(r=user_id_db; r; r = r->next )
+ if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
+ p = m_alloc( r->len + 10 );
+ sprintf(p, "%08lX %.*s", keyid[1], r->len, r->name );
+ return p;
+ }
+ } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
+ p = m_alloc( 15 );
+ sprintf(p, "%08lX [?]", keyid[1] );
+ return p;
+}
+
+
diff --git a/g10/keydb.h b/g10/keydb.h
new file mode 100644
index 000000000..641cd4cbc
--- /dev/null
+++ b/g10/keydb.h
@@ -0,0 +1,45 @@
+/* keydb.h - Key database
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef G10_KEYDB_H
+#define G10_KEYDB_H
+
+#include "types.h"
+#include "cipher.h"
+
+
+/*-- passphrase.h --*/
+DEK *get_passphrase_hash( u32 *keyid, char *text );
+int make_dek_from_passphrase( DEK *dek, int mode );
+
+/*-- getkey.c --*/
+void add_keyring( const char *name );
+void cache_pubkey_cert( PKT_pubkey_cert *pkc );
+void cache_user_id( PKT_user_id *uid, u32 *keyid );
+int get_pubkey( PKT_pubkey_cert *pkc, u32 *keyid );
+int get_pubkey_by_name( PKT_pubkey_cert *pkc, const char *name );
+int get_seckey( RSA_secret_key *skey, u32 *keyid );
+char*get_user_id_string( u32 *keyid );
+
+
+
+
+
+#endif /*G10_KEYDB_H*/
diff --git a/g10/keygen.c b/g10/keygen.c
new file mode 100644
index 000000000..0d5db8d85
--- /dev/null
+++ b/g10/keygen.c
@@ -0,0 +1,253 @@
+/* keygen.c - generate a key pair
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include "util.h"
+#include "main.h"
+#include "packet.h"
+#include "cipher.h"
+#include "ttyio.h"
+#include "options.h"
+
+static int
+answer_is_yes( const char *s )
+{
+ if( !stricmp(s, "yes") )
+ return 1;
+ if( *s == 'y' && !s[1] )
+ return 1;
+ if( *s == 'Y' && !s[1] )
+ return 1;
+ return 0;
+}
+
+
+static void
+write_comment( IOBUF out, const char *s )
+{
+ PACKET pkt;
+ size_t n = strlen(s);
+ int rc;
+
+ pkt.pkttype = PKT_COMMENT;
+ pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n - 1 );
+ pkt.pkt.comment->len = n;
+ strcpy(pkt.pkt.comment->data, s);
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build_packet(comment) failed: %s\n", g10_errstr(rc) );
+ free_packet( &pkt );
+}
+
+static void
+write_uid( IOBUF out, const char *s )
+{
+ PACKET pkt;
+ size_t n = strlen(s);
+ int rc;
+
+ pkt.pkttype = PKT_USER_ID;
+ pkt.pkt.user_id = m_alloc( sizeof *pkt.pkt.user_id + n - 1 );
+ pkt.pkt.user_id->len = n;
+ strcpy(pkt.pkt.user_id->name, s);
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build_packet(user_id) failed: %s\n", g10_errstr(rc) );
+ free_packet( &pkt );
+}
+
+
+static int
+gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io)
+{
+ int rc;
+ PACKET pkt1, pkt2;
+ PKT_seckey_cert *skc;
+ PKT_pubkey_cert *pkc;
+ RSA_public_key pk;
+ RSA_secret_key sk;
+
+ rsa_generate( &pk, &sk, nbits );
+
+ skc = m_alloc( sizeof *skc );
+ pkc = m_alloc( sizeof *pkc );
+ skc->timestamp = pkc->timestamp = make_timestamp();
+ skc->valid_days = pkc->valid_days = 0; /* fixme: make it configurable*/
+ skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_RSA;
+ memset(&pkc->mfx, 0, sizeof pkc->mfx);
+ pkc->d.rsa.rsa_n = pk.n;
+ pkc->d.rsa.rsa_e = pk.e;
+ skc->d.rsa.rsa_n = sk.n;
+ skc->d.rsa.rsa_e = sk.e;
+ skc->d.rsa.rsa_d = sk.d;
+ skc->d.rsa.rsa_p = sk.p;
+ skc->d.rsa.rsa_q = sk.q;
+ skc->d.rsa.rsa_u = sk.u;
+ skc->d.rsa.calc_csum = 0;
+ skc->d.rsa.is_protected = 0; /* FIXME!!! */
+ skc->d.rsa.protect_algo = 0; /* should be blowfish */
+ /*memcpy(skc->d.rsa.protect.blowfish.iv,"12345678", 8);*/
+
+ init_packet(&pkt1);
+ pkt1.pkttype = PKT_PUBKEY_CERT;
+ pkt1.pkt.pubkey_cert = pkc;
+ init_packet(&pkt2);
+ pkt2.pkttype = PKT_SECKEY_CERT;
+ pkt2.pkt.seckey_cert = skc;
+
+ if( (rc = build_packet( pub_io, &pkt1 )) ) {
+ log_error("build pubkey_cert packet failed: %s\n", g10_errstr(rc) );
+ goto leave;
+ }
+ if( (rc = build_packet( sec_io, &pkt2 )) ) {
+ log_error("build seckey_cert packet failed: %s\n", g10_errstr(rc) );
+ goto leave;
+ }
+
+ leave:
+ free_packet(&pkt1);
+ free_packet(&pkt2);
+ return rc;
+}
+
+
+/****************
+ * Generate a keypair
+ */
+void
+generate_keypair()
+{
+ char *answer;
+ unsigned nbits;
+ char *pub_fname = "./pubring.g10";
+ char *sec_fname = "./secring.g10";
+ char *uid = NULL;
+ IOBUF pub_io = NULL;
+ IOBUF sec_io = NULL;
+ int rc;
+
+ if( opt.batch || opt.answer_yes || opt.answer_no )
+ log_fatal("Key generation can only be used in interactive mode\n");
+
+ tty_printf("About to generate a new keypair:\n"
+ " minimum keysize is 768 bits\n"
+ " default keysize is 1024 bits\n"
+ " highest suggested keysize is 2048 bits\n" );
+ for(;;) {
+ answer = tty_get("What keysize do you want? (256) ");
+ tty_kill_prompt();
+ nbits = *answer? atoi(answer): 256;
+ m_free(answer);
+ if( nbits < 128 ) /* FIXME: change this to 768 */
+ tty_printf("keysize too small; please select a larger one\n");
+ else if( nbits > 2048 ) {
+ tty_printf("Keysizes larger than 2048 are not suggested, because "
+ "computations take REALLY long!\n");
+ answer = tty_get("Are you sure, that you want this keysize? ");
+ tty_kill_prompt();
+ if( answer_is_yes(answer) ) {
+ m_free(answer);
+ tty_printf("Okay, but keep in mind that your monitor "
+ "and keyboard radiation is also very vulnerable "
+ "to attacks!\n");
+ break;
+ }
+ m_free(answer);
+ }
+ else
+ break;
+ }
+ tty_printf("Requested keysize is %u bits\n", nbits );
+ if( (nbits % 32) ) {
+ nbits = ((nbits + 31) / 32) * 32;
+ tty_printf("rounded up to %u bits\n", nbits );
+ }
+ tty_printf( "\nYou need a User-ID to identify your key; please use your name and your\n"
+ "email address in this suggested format:\n"
+ " \"Heinrich Heine <heinrichh@uni-duesseldorf.de>\n" );
+ uid = NULL;
+ for(;;) {
+ m_free(uid);
+ tty_printf("\n");
+ uid = tty_get("Your User-ID: ");
+ tty_kill_prompt();
+ if( strlen(uid) < 5 )
+ tty_printf("Please enter a string of at least 5 characters\n");
+ else {
+ tty_printf("You selected this USER-ID:\n \"%s\"\n\n", uid);
+ answer = tty_get("Is this correct? ");
+ tty_kill_prompt();
+ if( answer_is_yes(answer) ) {
+ m_free(answer);
+ break;
+ }
+ m_free(answer);
+ }
+ }
+
+ /* now check wether we a are allowed to write the keyrings */
+ if( !(rc=overwrite_filep( pub_fname )) ) {
+ if( !(pub_io = iobuf_create( pub_fname )) )
+ log_error("can't create %s: %s\n", pub_fname, strerror(errno) );
+ else if( opt.verbose )
+ log_info("writing to '%s'\n", pub_fname );
+ }
+ else if( rc != -1 ) {
+ log_error("Oops: overwrite_filep(%s): %s\n", pub_fname, g10_errstr(rc) );
+ m_free(uid);
+ return;
+ }
+ else {
+ m_free(uid);
+ return;
+ }
+ if( !(rc=overwrite_filep( sec_fname )) ) {
+ if( !(sec_io = iobuf_create( sec_fname )) )
+ log_error("can't create %s: %s\n", sec_fname, strerror(errno) );
+ else if( opt.verbose )
+ log_info("writing to '%s'\n", sec_fname );
+ }
+ else if( rc != -1 ) {
+ log_error("Oops: overwrite_filep(%s): %s\n", sec_fname, g10_errstr(rc) );
+ m_free(uid);
+ return;
+ }
+ else {
+ iobuf_cancel(pub_io);
+ m_free(uid);
+ return;
+ }
+
+
+ write_comment( pub_io, "#public key created by G10 pre-release " VERSION );
+ write_comment( sec_io, "#secret key created by G10 pre-release " VERSION );
+
+ gen_rsa(nbits, pub_io, sec_io);
+ write_uid(pub_io, uid );
+ write_uid(sec_io, uid );
+ m_free(uid);
+
+ iobuf_close(pub_io);
+ iobuf_close(sec_io);
+}
+
diff --git a/g10/main.h b/g10/main.h
new file mode 100644
index 000000000..398dc40f1
--- /dev/null
+++ b/g10/main.h
@@ -0,0 +1,35 @@
+/* main.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_MAIN_H
+#define G10_MAIN_H
+#include "types.h"
+
+/*-- encode.c --*/
+int encode_symmetric( const char *filename );
+int encode_store( const char *filename );
+int encode_crypt( const char *filename, STRLIST remusr );
+
+/*-- keygen.c --*/
+void generate_keypair(void);
+
+/*-- overwrite.c --*/
+int overwrite_filep( const char *fname );
+
+#endif /*G10_MAIN_H*/
diff --git a/g10/mainproc.c b/g10/mainproc.c
new file mode 100644
index 000000000..0055200b4
--- /dev/null
+++ b/g10/mainproc.c
@@ -0,0 +1,275 @@
+/* mainproc.c - handle packets
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "packet.h"
+#include "iobuf.h"
+#include "memory.h"
+#include "options.h"
+#include "util.h"
+#include "cipher.h"
+#include "keydb.h"
+
+
+static int opt_list=1; /* and list the data packets to stdout */
+
+int
+proc_packets( IOBUF a )
+{
+ PACKET *pkt;
+ PKT_pubkey_cert *last_pubkey = NULL;
+ PKT_seckey_cert *last_seckey = NULL;
+ PKT_user_id *last_user_id = NULL;
+ DEK *dek = NULL;
+ PKT_signature *sig; /* CHECK: "might be used uninitialied" */
+ int rc, result;
+ MD_HANDLE md_handle; /* union to pass handles */
+ char *ustr;
+ int lvl0, lvl1;
+ int last_was_pubkey_enc = 0;
+ u32 keyid[2];
+
+ lvl0 = opt.check_sigs? 1:0; /* stdout or /dev/null */
+ lvl1 = opt.check_sigs? 1:3; /* stdout or error */
+ pkt = m_alloc( sizeof *pkt );
+ init_packet(pkt);
+ while( (rc=parse_packet(a, pkt)) != -1 ) {
+ if( dek && pkt->pkttype != PKT_ENCR_DATA ) {
+ log_error("oops: valid pubkey enc packet not followed by data\n");
+ m_free(dek); dek = NULL; /* burn it */
+ }
+
+ if( rc )
+ free_packet(pkt);
+ else if( pkt->pkttype == PKT_PUBKEY_CERT ) {
+ if( last_user_id ) {
+ free_user_id( last_user_id );
+ last_user_id = NULL;
+ }
+ if( last_pubkey ) {
+ free_pubkey_cert( last_pubkey );
+ last_pubkey = NULL;
+ }
+ if( opt.check_sigs ) {
+ ustr = get_user_id_string(sig->keyid);
+ printstr(lvl0, "pub: %s\n", ustr );
+ m_free(ustr);
+ }
+ else
+ fputs( "pub: [Public Key Cerificate]\n", stdout );
+ last_pubkey = pkt->pkt.pubkey_cert;
+ pkt->pkt.pubkey_cert = NULL;
+ free_packet(pkt);
+ pkt->pkc_parent = last_pubkey; /* set this as parent */
+ }
+ else if( pkt->pkttype == PKT_SECKEY_CERT ) {
+ if( last_user_id ) {
+ free_user_id( last_user_id );
+ last_user_id = NULL;
+ }
+ if( last_seckey ) {
+ free_seckey_cert( last_seckey );
+ last_seckey = NULL;
+ }
+ if( opt_list )
+ fputs( "sec: (secret key certificate)\n", stdout );
+ rc = check_secret_key( pkt->pkt.seckey_cert );
+ if( opt_list ) {
+ if( !rc )
+ fputs( " Secret key is good", stdout );
+ else
+ fputs( g10_errstr(rc), stdout);
+ putchar('\n');
+ }
+ else if( rc )
+ log_error("secret key certificate error: %s\n", g10_errstr(rc));
+ last_seckey = pkt->pkt.seckey_cert;
+ pkt->pkt.seckey_cert = NULL;
+ free_packet(pkt);
+ pkt->skc_parent = last_seckey; /* set this as parent */
+ }
+ else if( pkt->pkttype == PKT_USER_ID ) {
+ if( last_user_id ) {
+ free_user_id( last_user_id );
+ last_user_id = NULL;
+ }
+ if( opt_list ) {
+ printf("uid: '%.*s'\n", pkt->pkt.user_id->len,
+ pkt->pkt.user_id->name );
+ if( !pkt->pkc_parent && !pkt->skc_parent )
+ puts(" (orphaned)");
+ }
+ if( pkt->pkc_parent ) {
+ if( pkt->pkc_parent->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_get_keyid( pkt->pkc_parent->d.rsa.rsa_n, keyid );
+ cache_user_id( pkt->pkt.user_id, keyid );
+ }
+ }
+
+ last_user_id = pkt->pkt.user_id; /* save */
+ pkt->pkt.user_id = NULL;
+ free_packet(pkt); /* fixme: free_packet is not a good name */
+ pkt->user_parent = last_user_id; /* and set this as user */
+ }
+ else if( pkt->pkttype == PKT_SIGNATURE ) {
+ sig = pkt->pkt.signature;
+ ustr = get_user_id_string(sig->keyid);
+ result = -1;
+ if( sig->sig_class != 0x10 )
+ printstr(lvl1,"sig?: %s: unknown signature class %02x\n",
+ ustr, sig->sig_class);
+ else if( !pkt->pkc_parent || !pkt->user_parent )
+ printstr(lvl1,"sig?: %s: orphaned encoded packet\n", ustr);
+ else
+ result = 0;
+
+ if( result )
+ ;
+ else if( !opt.check_sigs ) {
+ result = -1;
+ printstr(lvl0, "sig: from %s\n", ustr );
+ }
+ else if(sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ md_handle.algo = sig->d.rsa.digest_algo;
+ if( sig->d.rsa.digest_algo == DIGEST_ALGO_RMD160 ) {
+ md_handle.u.rmd = rmd160_copy(pkt->pkc_parent->mfx.rmd160);
+ rmd160_write(md_handle.u.rmd, pkt->user_parent->name,
+ pkt->user_parent->len);
+ result = signature_check( sig, md_handle );
+ rmd160_close(md_handle.u.rmd);
+ }
+ else if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) {
+ md_handle.u.md5 = md5_copy(pkt->pkc_parent->mfx.md5);
+ md5_write(md_handle.u.md5, pkt->user_parent->name,
+ pkt->user_parent->len);
+ result = signature_check( sig, md_handle );
+ md5_close(md_handle.u.md5);
+ }
+ else
+ result = G10ERR_DIGEST_ALGO;
+ }
+ else
+ result = G10ERR_PUBKEY_ALGO;
+
+ if( result == -1 )
+ ;
+ else if( !result )
+ printstr(lvl0, "sig: good signature from %s\n", ustr );
+ else
+ printstr(lvl1, "sig? %s: %s\n", ustr, g10_errstr(result));
+ free_packet(pkt);
+ m_free(ustr);
+ }
+ else if( pkt->pkttype == PKT_PUBKEY_ENC ) {
+ PKT_pubkey_enc *enc;
+
+ last_was_pubkey_enc = 1;
+ result = 0;
+ enc = pkt->pkt.pubkey_enc;
+ printf("enc: encrypted by a pubkey with keyid %08lX\n",
+ enc->keyid[1] );
+ if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ m_free(dek ); /* paranoid: delete a pending DEK */
+ dek = m_alloc_secure( sizeof *dek );
+ if( (result = get_session_key( enc, dek )) ) {
+ /* error: delete the DEK */
+ m_free(dek); dek = NULL;
+ }
+ }
+ else
+ result = G10ERR_PUBKEY_ALGO;
+
+ if( result == -1 )
+ ;
+ else if( !result )
+ fputs( " DEK is good", stdout );
+ else
+ printf( " %s", g10_errstr(result));
+ putchar('\n');
+ free_packet(pkt);
+ }
+ else if( pkt->pkttype == PKT_ENCR_DATA ) {
+ result = 0;
+ printf("dat: %sencrypted data\n", dek?"":"conventional ");
+ if( !dek && !last_was_pubkey_enc ) {
+ /* assume this is conventional encrypted data */
+ dek = m_alloc_secure( sizeof *dek );
+ dek->algo = DEFAULT_CIPHER_ALGO;
+ result = make_dek_from_passphrase( dek, 0 );
+ }
+ else if( !dek )
+ result = G10ERR_NO_SECKEY;
+ if( !result )
+ result = decrypt_data( pkt->pkt.encr_data, dek );
+ m_free(dek); dek = NULL;
+ if( result == -1 )
+ ;
+ else if( !result )
+ fputs( " encryption okay",stdout);
+ else
+ printf( " %s", g10_errstr(result));
+ putchar('\n');
+ free_packet(pkt);
+ last_was_pubkey_enc = 0;
+ }
+ else if( pkt->pkttype == PKT_PLAINTEXT ) {
+ PKT_plaintext *pt = pkt->pkt.plaintext;
+ printf("txt: plain text data name='%.*s'\n", pt->namelen, pt->name);
+ result = handle_plaintext( pt );
+ if( !result )
+ fputs( " okay",stdout);
+ else
+ printf( " %s", g10_errstr(result));
+ putchar('\n');
+ free_packet(pkt);
+ last_was_pubkey_enc = 0;
+ }
+ else if( pkt->pkttype == PKT_COMPR_DATA ) {
+ PKT_compressed *zd = pkt->pkt.compressed;
+ printf("zip: compressed data packet\n");
+ result = handle_compressed( zd );
+ if( !result )
+ fputs( " okay",stdout);
+ else
+ printf( " %s", g10_errstr(result));
+ putchar('\n');
+ free_packet(pkt);
+ last_was_pubkey_enc = 0;
+ }
+ else
+ free_packet(pkt);
+ }
+
+ if( last_user_id )
+ free_user_id( last_user_id );
+ if( last_seckey )
+ free_seckey_cert( last_seckey );
+ if( last_pubkey )
+ free_pubkey_cert( last_pubkey );
+ m_free(dek);
+ free_packet( pkt );
+ m_free( pkt );
+ return 0;
+}
+
+
diff --git a/g10/mdfilter.c b/g10/mdfilter.c
new file mode 100644
index 000000000..b6cd86110
--- /dev/null
+++ b/g10/mdfilter.c
@@ -0,0 +1,70 @@
+/* mdfilter.c - filter data and calculate a message digest
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "errors.h"
+#include "iobuf.h"
+#include "memory.h"
+#include "util.h"
+#include "filter.h"
+
+
+
+/****************
+ * The filter is used to collect a message digest
+ */
+int
+md_filter( void *opaque, int control,
+ IOBUF a, byte *buf, size_t *ret_len)
+{
+ size_t size = *ret_len;
+ md_filter_context_t *mfx = opaque;
+ int i, c, rc=0;
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ if( size > mfx->maxbuf_size )
+ size = mfx->maxbuf_size;
+ for(i=0; i < size; i++ ) {
+ if( (c = iobuf_get(a)) == -1 )
+ break;
+ buf[i] = c;
+ }
+
+ if( i ) {
+ if( mfx->md5 )
+ md5_write(mfx->md5, buf, i );
+ if( mfx->rmd160 )
+ rmd160_write(mfx->rmd160, buf, i );
+ }
+ else
+ rc = -1; /* eof */
+ *ret_len = i;
+ }
+ else if( control == IOBUFCTRL_DESC )
+ *(char**)buf = "md_filter";
+ return rc;
+}
+
diff --git a/g10/options.h b/g10/options.h
new file mode 100644
index 000000000..f2a17de85
--- /dev/null
+++ b/g10/options.h
@@ -0,0 +1,68 @@
+/* options.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_OPTIONS_H
+#define G10_OPTIONS_H
+
+struct {
+ int verbose;
+ unsigned debug;
+ int armor;
+ int compress;
+ char *outfile;
+ int outfile_is_stdout;
+ int batch; /* run in batch mode */
+ int answer_yes; /* answer yes on most questions */
+ int answer_no; /* answer no on most questions */
+ int check_sigs; /* check key signatures */
+ int cache_all;
+ int reserved2;
+ int reserved3;
+ int reserved4;
+ int reserved5;
+ int reserved6;
+ int reserved7;
+ int reserved8;
+ int reserved9;
+ int reserved10;
+ int reserved11;
+ int reserved12;
+ int reserved13;
+ int reserved14;
+ int reserved15;
+} opt;
+
+
+#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
+#define DBG_MPI_VALUE 2 /* debug mpi details */
+#define DBG_CIPHER_VALUE 4 /* debug cipher handling */
+ /* (may reveal sensitive data) */
+#define DBG_FILTER_VALUE 8 /* debug internal filter handling */
+#define DBG_IOBUF_VALUE 16 /* debug iobuf stuff */
+#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
+#define DBG_CACHE_VALUE 64 /* debug the cacheing */
+#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
+
+
+#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
+#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
+#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
+
+
+#endif /*G10_OPTIONS_H*/
diff --git a/g10/overwrite.c b/g10/overwrite.c
new file mode 100644
index 000000000..a98dd3be7
--- /dev/null
+++ b/g10/overwrite.c
@@ -0,0 +1,79 @@
+/* overwrite.c
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include "util.h"
+#include "memory.h"
+#include "ttyio.h"
+#include "options.h"
+#include "main.h"
+
+
+/****************
+ * Check wether FNAME exists and ask if it's okay to overwrite an
+ * existing one.
+ * Returns: -1 : Do not overwrite
+ * 0 : it's okay to overwrite or the file does not exist
+ * >0 : other error
+ */
+int
+overwrite_filep( const char *fname )
+{
+ if( !access( fname, F_OK ) ) {
+ char *p;
+ int okay;
+ int first = 1;
+
+ if( opt.answer_yes )
+ okay = 1;
+ else if( opt.answer_no || opt.batch )
+ okay = 2;
+ else
+ okay = 0;
+
+ while( !okay ) {
+ if( !okay )
+ if( first ) {
+ tty_printf("File '%s' exists. ", fname);
+ first = 0;
+ }
+ p = tty_get("Overwrite (y/N)? ");
+ tty_kill_prompt();
+ if( (*p == 'y' || *p == 'Y') && !p[1] )
+ okay = 1;
+ else if( !*p || ((*p == 'n' || *p == 'N') && !p[1]) )
+ okay = 2;
+ else
+ okay = 0;
+ m_free(p);
+ }
+ if( okay == 2 )
+ return -1;
+ /* fixme: add some backup stuff */
+ }
+ return 0;
+}
+
+
diff --git a/g10/packet.h b/g10/packet.h
new file mode 100644
index 000000000..6ac57cab0
--- /dev/null
+++ b/g10/packet.h
@@ -0,0 +1,214 @@
+/* packet.h - packet read/write stuff
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef G10_PACKET_H
+#define G10_PACKET_H
+
+#include "types.h"
+#include "iobuf.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "filter.h"
+
+
+#define PKT_PUBKEY_ENC 1 /* public key encrypted packet */
+#define PKT_SIGNATURE 2 /* secret key encrypted packet */
+#define PKT_SECKEY_CERT 5 /* secret key certificate */
+#define PKT_PUBKEY_CERT 6 /* public key certificate */
+#define PKT_COMPR_DATA 8 /* compressed data packet */
+#define PKT_ENCR_DATA 9 /* conventional encrypted data */
+#define PKT_PLAINTEXT 11 /* plaintext data with filename and mode */
+#define PKT_RING_TRUST 12 /* keyring trust packet */
+#define PKT_USER_ID 13 /* user id packet */
+#define PKT_COMMENT 14 /* comment packet */
+
+typedef struct packet_struct PACKET;
+
+typedef struct {
+ u32 keyid[2]; /* 64 bit keyid */
+ byte pubkey_algo; /* algorithm used for public key scheme */
+ union {
+ struct {
+ MPI rsa_integer; /* integer containing the DEK */
+ } rsa;
+ } d;
+} PKT_pubkey_enc;
+
+
+typedef struct {
+ u32 keyid[2]; /* 64 bit keyid */
+ u32 timestamp; /* signature made */
+ byte sig_class; /* sig classification, append for MD calculation*/
+ byte pubkey_algo; /* algorithm used for public key scheme */
+ /* (PUBKEY_ALGO_xxx) */
+ union {
+ struct {
+ byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */
+ byte digest_start[2]; /* first 2 byte of the digest */
+ MPI rsa_integer; /* the encrypted digest */
+ } rsa;
+ } d;
+} PKT_signature;
+
+
+typedef struct {
+ u32 timestamp; /* certificate made */
+ u16 valid_days; /* valid for this number of days */
+ byte pubkey_algo; /* algorithm used for public key scheme */
+ md_filter_context_t mfx;
+ union {
+ struct {
+ MPI rsa_n; /* public modulus */
+ MPI rsa_e; /* public exponent */
+ } rsa;
+ } d;
+} PKT_pubkey_cert;
+
+typedef struct {
+ u32 timestamp; /* certificate made */
+ u16 valid_days; /* valid for this number of days */
+ byte pubkey_algo; /* algorithm used for public key scheme */
+ union {
+ struct {
+ MPI rsa_n; /* public modulus */
+ MPI rsa_e; /* public exponent */
+ MPI rsa_d; /* secret descryption exponent */
+ MPI rsa_p; /* secret first prime number */
+ MPI rsa_q; /* secret second prime number */
+ MPI rsa_u; /* secret multiplicative inverse */
+ u16 csum; /* checksum */
+ u16 calc_csum; /* and a place to store the calculated csum */
+ byte is_protected; /* The above infos are protected and must */
+ /* be deciphered before use */
+ byte protect_algo; /* cipher used to protect the secret informations*/
+ union { /* information for the protection */
+ struct {
+ byte iv[8]; /* initialization vector for CFB mode */
+ /* when protected, the MPIs above are pointers
+ * to plain storage */
+ } idea;
+ struct {
+ byte iv[8];
+ } blowfish;
+ } protect;
+ } rsa;
+ } d;
+} PKT_seckey_cert;
+
+
+typedef struct {
+ int len; /* length of data */
+ char data[1];
+} PKT_comment;
+
+typedef struct {
+ int len; /* length of the name */
+ char name[1];
+} PKT_user_id;
+
+typedef struct {
+ u32 len; /* reserved */
+ byte algorithm;
+ IOBUF buf; /* IOBUF reference */
+} PKT_compressed;
+
+typedef struct {
+ u32 len; /* length of encrypted data */
+ IOBUF buf; /* IOBUF reference */
+} PKT_encr_data;
+
+typedef struct {
+ u32 len; /* length of encrypted data */
+ IOBUF buf; /* IOBUF reference */
+ int mode;
+ u32 timestamp;
+ int namelen;
+ char name[1];
+} PKT_plaintext;
+
+/* combine all packets into a union */
+struct packet_struct {
+ int pkttype;
+ PKT_pubkey_cert *pkc_parent; /* the pubkey to which it belongs */
+ PKT_seckey_cert *skc_parent; /* the seckey to which it belongs */
+ PKT_user_id *user_parent; /* the user_id to which it belongs */
+ union {
+ void *generic;
+ PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */
+ PKT_signature *signature; /* PKT_SIGNATURE */
+ PKT_pubkey_cert *pubkey_cert; /* PKT_PUBKEY_CERT */
+ PKT_seckey_cert *seckey_cert; /* PKT_SECKEY_CERT */
+ PKT_comment *comment; /* PKT_COMMENT */
+ PKT_user_id *user_id; /* PKT_USER_ID */
+ PKT_compressed *compressed; /* PKT_COMPRESSED */
+ PKT_encr_data *encr_data; /* PKT_ENCR_DATA */
+ PKT_plaintext *plaintext; /* PKT_PLAINTEXT */
+ } pkt;
+};
+
+#define init_packet(a) do { (a)->pkttype = 0; \
+ (a)->pkc_parent = NULL; \
+ (a)->skc_parent = NULL; \
+ (a)->user_parent = NULL; \
+ (a)->pkt.generic = NULL; \
+ } while(0)
+
+/*-- mainproc.c --*/
+int proc_packets( IOBUF a );
+
+/*-- parse-packet.c --*/
+int set_packet_list_mode( int mode );
+int parse_packet( IOBUF inp, PACKET *ret_pkt);
+
+/*-- build-packet.c --*/
+int build_packet( IOBUF inp, PACKET *pkt );
+u32 calc_packet_length( PACKET *pkt );
+
+/*-- free-packet.c --*/
+void free_pubkey_enc( PKT_pubkey_enc *enc );
+void free_seckey_enc( PKT_signature *enc );
+void free_pubkey_cert( PKT_pubkey_cert *cert );
+void free_seckey_cert( PKT_seckey_cert *cert );
+void free_user_id( PKT_user_id *uid );
+void free_comment( PKT_comment *rem );
+void free_packet( PACKET *pkt );
+PKT_pubkey_cert *copy_pubkey_cert( PKT_pubkey_cert *d, PKT_pubkey_cert *s );
+
+
+/*-- sig-check.c --*/
+int signature_check( PKT_signature *sig, MD_HANDLE digest );
+
+/*-- seckey-cert.c --*/
+int check_secret_key( PKT_seckey_cert *cert );
+
+/*-- pubkey-enc.c --*/
+int get_session_key( PKT_pubkey_enc *k, DEK *dek );
+
+/*-- compressed.c --*/
+int handle_compressed( PKT_compressed *zd );
+
+/*-- encr-data.c --*/
+int decrypt_data( PKT_encr_data *ed, DEK *dek );
+int encrypt_data( PKT_encr_data *ed, DEK *dek );
+
+/*-- plaintext.c --*/
+int handle_plaintext( PKT_plaintext *pt );
+
+#endif /*G10_PACKET_H*/
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
new file mode 100644
index 000000000..7c6b85782
--- /dev/null
+++ b/g10/parse-packet.c
@@ -0,0 +1,662 @@
+/* parse-packet.c - read packets
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "packet.h"
+#include "iobuf.h"
+#include "mpi.h"
+#include "util.h"
+#include "cipher.h"
+#include "memory.h"
+#include "filter.h"
+#include "options.h"
+
+static mpi_print_mode = 0;
+static list_mode = 0;
+
+static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen );
+static void skip_rest( IOBUF inp, unsigned long pktlen );
+static int parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *packet );
+static int parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
+ PKT_signature *sig );
+static int parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen,
+ byte *hdr, int hdrlen, PACKET *packet );
+static int parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *packet );
+static void parse_comment( IOBUF inp, int pkttype, unsigned long pktlen );
+static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen );
+static int parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *pkt );
+static int parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *packet );
+static int parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *packet );
+
+static u16
+checksum( byte *p )
+{
+ u16 n, a;
+
+ n = *p++ << 8;
+ n |= *p++;
+ for(a=0; n; n-- )
+ a += *p++;
+ return a;
+}
+
+static unsigned short
+read_16(IOBUF inp)
+{
+ unsigned short a;
+ a = iobuf_get_noeof(inp) << 8;
+ a |= iobuf_get_noeof(inp);
+ return a;
+}
+
+static unsigned long
+read_32(IOBUF inp)
+{
+ unsigned long a;
+ a = iobuf_get_noeof(inp) << 24;
+ a |= iobuf_get_noeof(inp) << 16;
+ a |= iobuf_get_noeof(inp) << 8;
+ a |= iobuf_get_noeof(inp);
+ return a;
+}
+
+int
+set_packet_list_mode( int mode )
+{
+ int old = list_mode;
+ list_mode = mode;
+ mpi_print_mode = DBG_MPI;
+ return old;
+}
+
+/****************
+ * Parse a Packet and return it in packet
+ * Returns: 0 := valid packet in pkt
+ * -1 := no more packets
+ * >0 := error
+ * Note: The function may return an error and a partly valid packet;
+ * caller must free this packet.
+ */
+int
+parse_packet( IOBUF inp, PACKET *pkt )
+{
+ int rc, ctb, pkttype, lenbytes;
+ unsigned long pktlen;
+ byte hdr[5];
+ int hdrlen;
+
+ assert( !pkt->pkt.generic );
+ if( (ctb = iobuf_get(inp)) == -1 )
+ return -1;
+ hdrlen=0;
+ hdr[hdrlen++] = ctb;
+ if( !(ctb & 0x80) ) {
+ log_error("invalid packet at '%s'\n", iobuf_where(inp) );
+ return G10ERR_INVALID_PACKET;
+ }
+ /* we handle the pgp 3 extensions here, so that we can skip such packets*/
+ pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
+ lenbytes = (ctb & 0x40) || ((ctb&3)==3)? 0 : (1<<(ctb & 3));
+ pktlen = 0;
+ if( !lenbytes ) {
+ pktlen = 0; /* don't know the value */
+ iobuf_set_block_mode(inp, 1);
+ }
+ else {
+ for( ; lenbytes; lenbytes-- ) {
+ pktlen <<= 8;
+ pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp);
+ }
+ }
+
+ if( DBG_PACKET )
+ log_debug("parse_packet(iob=%d): type=%d length=%lu\n",
+ iobuf_id(inp), pkttype, pktlen );
+ pkt->pkttype = pkttype;
+ rc = G10ERR_UNKNOWN_PACKET; /* default to no error */
+ switch( pkttype ) {
+ case PKT_PUBKEY_CERT:
+ pkt->pkt.pubkey_cert = m_alloc_clear(sizeof *pkt->pkt.pubkey_cert );
+ rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt );
+ break;
+ case PKT_SECKEY_CERT:
+ pkt->pkt.seckey_cert = m_alloc_clear(sizeof *pkt->pkt.seckey_cert );
+ rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt );
+ break;
+ case PKT_PUBKEY_ENC:
+ rc = parse_publickey(inp, pkttype, pktlen, pkt );
+ break;
+ case PKT_SIGNATURE:
+ pkt->pkt.signature = m_alloc_clear(sizeof *pkt->pkt.signature );
+ rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature );
+ m_check(pkt->pkt.signature);
+ break;
+ case PKT_USER_ID:
+ rc = parse_user_id(inp, pkttype, pktlen, pkt );
+ break;
+ case PKT_COMMENT:
+ parse_comment(inp, pkttype, pktlen);
+ break;
+ case PKT_RING_TRUST:
+ parse_trust(inp, pkttype, pktlen);
+ break;
+ case PKT_PLAINTEXT:
+ rc = parse_plaintext(inp, pkttype, pktlen, pkt );
+ break;
+ case PKT_COMPR_DATA:
+ rc = parse_compressed(inp, pkttype, pktlen, pkt );
+ break;
+ case PKT_ENCR_DATA:
+ rc = parse_encrypted(inp, pkttype, pktlen, pkt );
+ break;
+ default:
+ skip_packet(inp, pkttype, pktlen);
+ break;
+ }
+
+ return rc;
+}
+
+
+static void
+skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
+{
+ if( list_mode )
+ printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen );
+ skip_rest(inp,pktlen);
+}
+
+static void
+skip_rest( IOBUF inp, unsigned long pktlen )
+{
+ if( iobuf_in_block_mode(inp) ) {
+ while( iobuf_get(inp) != -1 )
+ ;
+ }
+ else {
+ for( ; pktlen; pktlen-- )
+ iobuf_get(inp);
+ }
+}
+
+
+static int
+parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
+{
+ int version;
+ unsigned n;
+ PKT_pubkey_enc *k;
+
+ k = packet->pkt.pubkey_enc = m_alloc(sizeof *packet->pkt.pubkey_enc );
+ if( pktlen < 12 ) {
+ log_error("packet(%d) too short\n", pkttype);
+ goto leave;
+ }
+ version = iobuf_get_noeof(inp); pktlen--;
+ if( version != 2 && version != 3 ) {
+ log_error("packet(%d) with unknown version %d\n", pkttype, version);
+ goto leave;
+ }
+ k->keyid[0] = read_32(inp); pktlen -= 4;
+ k->keyid[1] = read_32(inp); pktlen -= 4;
+ k->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
+ if( list_mode )
+ printf(":public key packet: keyid %08lX%08lX\n",
+ k->keyid[0], k->keyid[1]);
+ if( k->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ n = pktlen;
+ k->d.rsa.rsa_integer = mpi_decode(inp, &n ); pktlen -=n;
+ if( list_mode ) {
+ printf("\trsa integer: ");
+ mpi_print(stdout, k->d.rsa.rsa_integer, mpi_print_mode );
+ putchar('\n');
+ }
+ }
+ else if( list_mode )
+ printf("\tunknown algorithm %d\n", k->pubkey_algo );
+
+
+ leave:
+ skip_rest(inp, pktlen);
+ return 0;
+}
+
+
+static int
+parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
+ PKT_signature *sig )
+{
+ int version, md5_len;
+ unsigned n;
+
+ if( pktlen < 16 ) {
+ log_error("packet(%d) too short\n", pkttype);
+ goto leave;
+ }
+ version = iobuf_get_noeof(inp); pktlen--;
+ if( version != 2 && version != 3 ) {
+ log_error("packet(%d) with unknown version %d\n", pkttype, version);
+ goto leave;
+ }
+ m_check(sig);
+ md5_len = iobuf_get_noeof(inp); pktlen--;
+ sig->sig_class = iobuf_get_noeof(inp); pktlen--;
+ sig->timestamp = read_32(inp); pktlen -= 4;
+ sig->keyid[0] = read_32(inp); pktlen -= 4;
+ sig->keyid[1] = read_32(inp); pktlen -= 4;
+ sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
+ m_check(sig);
+ if( list_mode )
+ printf(":signature packet: keyid %08lX%08lX\n"
+ "\tversion %d, created %lu, md5len %d, sigclass %02x\n",
+ sig->keyid[0], sig->keyid[1],
+ version, sig->timestamp, md5_len, sig->sig_class );
+ if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ if( pktlen < 5 ) {
+ log_error("packet(%d) too short\n", pkttype);
+ goto leave;
+ }
+ m_check(sig);
+ sig->d.rsa.digest_algo = iobuf_get_noeof(inp); pktlen--;
+ sig->d.rsa.digest_start[0] = iobuf_get_noeof(inp); pktlen--;
+ sig->d.rsa.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
+ m_check(sig);
+ n = pktlen;
+ sig->d.rsa.rsa_integer = mpi_decode(inp, &n ); pktlen -=n;
+ if( list_mode ) {
+ printf("\tdigest algo %d, begin of digest %02x %02x\n",
+ sig->d.rsa.digest_algo,
+ sig->d.rsa.digest_start[0], sig->d.rsa.digest_start[1] );
+ printf("\trsa integer: ");
+ mpi_print(stdout, sig->d.rsa.rsa_integer, mpi_print_mode );
+ putchar('\n');
+ }
+ }
+ else if( list_mode )
+ printf("\tunknown algorithm %d\n", sig->pubkey_algo );
+ m_check(sig);
+
+
+ leave:
+ skip_rest(inp, pktlen);
+ return 0;
+}
+
+
+
+
+static int
+parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen,
+ byte *hdr, int hdrlen, PACKET *pkt )
+{
+ int i, version, algorithm;
+ unsigned n;
+ unsigned long timestamp;
+ unsigned short valid_period;
+ MPI rsa_pub_mod, rsa_pub_exp;
+
+ if( pkttype == PKT_PUBKEY_CERT ) {
+ pkt->pkt.pubkey_cert->mfx.md5 = md5_open(0);
+ pkt->pkt.pubkey_cert->mfx.rmd160 = rmd160_open(0);
+ pkt->pkt.pubkey_cert->mfx.maxbuf_size = 1;
+ md5_write(pkt->pkt.pubkey_cert->mfx.md5, hdr, hdrlen);
+ rmd160_write(pkt->pkt.pubkey_cert->mfx.rmd160, hdr, hdrlen);
+ iobuf_push_filter( inp, md_filter, &pkt->pkt.pubkey_cert->mfx );
+ }
+
+ if( pktlen < 12 ) {
+ log_error("packet(%d) too short\n", pkttype);
+ goto leave;
+ }
+ version = iobuf_get_noeof(inp); pktlen--;
+ if( version != 2 && version != 3 ) {
+ log_error("packet(%d) with unknown version %d\n", pkttype, version);
+ goto leave;
+ }
+
+ timestamp = read_32(inp); pktlen -= 4;
+ valid_period = read_16(inp); pktlen -= 2;
+ algorithm = iobuf_get_noeof(inp); pktlen--;
+ if( list_mode )
+ printf(":%s key certification packet:\n"
+ "\tversion %d, created %lu, valid for %hu days\n",
+ pkttype == PKT_PUBKEY_CERT? "public": "secret",
+ version, timestamp, valid_period );
+ if( pkttype == PKT_SECKEY_CERT ) {
+ pkt->pkt.seckey_cert->timestamp = timestamp;
+ pkt->pkt.seckey_cert->valid_days = valid_period;
+ pkt->pkt.seckey_cert->pubkey_algo = algorithm;
+ }
+ else {
+ pkt->pkt.pubkey_cert->timestamp = timestamp;
+ pkt->pkt.pubkey_cert->valid_days = valid_period;
+ pkt->pkt.pubkey_cert->pubkey_algo = algorithm;
+ }
+
+ if( algorithm == PUBKEY_ALGO_RSA ) {
+ n = pktlen; rsa_pub_mod = mpi_decode(inp, &n ); pktlen -=n;
+ n = pktlen; rsa_pub_exp = mpi_decode(inp, &n ); pktlen -=n;
+ if( list_mode ) {
+ printf( "\tpublic modulus n: ");
+ mpi_print(stdout, rsa_pub_mod, mpi_print_mode );
+ printf("\n\tpublic exponent e: ");
+ mpi_print(stdout, rsa_pub_exp, mpi_print_mode );
+ putchar('\n');
+ }
+ if( pkttype == PKT_PUBKEY_CERT ) {
+ pkt->pkt.pubkey_cert->d.rsa.rsa_n = rsa_pub_mod;
+ pkt->pkt.pubkey_cert->d.rsa.rsa_e = rsa_pub_exp;
+ }
+ else {
+ PKT_seckey_cert *cert = pkt->pkt.seckey_cert;
+ byte temp[8];
+ byte *mpibuf;
+
+ pkt->pkt.seckey_cert->d.rsa.rsa_n = rsa_pub_mod;
+ pkt->pkt.seckey_cert->d.rsa.rsa_e = rsa_pub_exp;
+ cert->d.rsa.protect_algo = iobuf_get_noeof(inp); pktlen--;
+ if( list_mode )
+ printf( "\tprotect algo: %d\n", cert->d.rsa.protect_algo);
+ if( cert->d.rsa.protect_algo ) {
+ cert->d.rsa.is_protected = 1;
+ for(i=0; i < 8 && pktlen; i++, pktlen-- )
+ temp[i] = iobuf_get_noeof(inp);
+ if( list_mode ) {
+ printf( "\tprotect IV: ");
+ for(i=0; i < 8; i++ )
+ printf(" %02x", temp[i] );
+ putchar('\n');
+ }
+ if( cert->d.rsa.protect_algo == CIPHER_ALGO_IDEA )
+ memcpy(cert->d.rsa.protect.idea.iv, temp, 8 );
+ else if( cert->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH )
+ memcpy(cert->d.rsa.protect.blowfish.iv, temp, 8 );
+ }
+ else
+ cert->d.rsa.is_protected = 0;
+
+ n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2);
+ cert->d.rsa.rsa_d = (MPI)mpibuf;
+
+ n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2);
+ cert->d.rsa.rsa_p = (MPI)mpibuf;
+
+ n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2);
+ cert->d.rsa.rsa_q = (MPI)mpibuf;
+
+ n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2);
+ cert->d.rsa.rsa_u = (MPI)mpibuf;
+
+ cert->d.rsa.csum = read_16(inp); pktlen -= 2;
+ cert->d.rsa.calc_csum = 0;
+ if( list_mode ) {
+ printf("\t[secret values d,p,q,u are not shown]\n"
+ "\tchecksum: %04hx\n", cert->d.rsa.csum);
+ }
+ if( !cert->d.rsa.is_protected ) { /* convert buffer to MPIs */
+ #define X(a) do { \
+ mpibuf = (byte*)cert->d.rsa.rsa_##a; \
+ cert->d.rsa.calc_csum += checksum( mpibuf ); \
+ cert->d.rsa.rsa_##a = mpi_decode_buffer( mpibuf ); \
+ m_free( mpibuf ); \
+ } while(0)
+ X(d);
+ X(p);
+ X(q);
+ X(u);
+ #undef X
+ log_mpidump("rsa n=", cert->d.rsa.rsa_n );
+ log_mpidump("rsa e=", cert->d.rsa.rsa_e );
+ log_mpidump("rsa d=", cert->d.rsa.rsa_d );
+ log_mpidump("rsa p=", cert->d.rsa.rsa_p );
+ log_mpidump("rsa q=", cert->d.rsa.rsa_q );
+ log_mpidump("rsa u=", cert->d.rsa.rsa_u );
+ }
+ }
+ }
+ else if( list_mode )
+ printf("\tunknown algorithm %d\n", algorithm );
+
+
+ leave:
+ if( pkttype == PKT_PUBKEY_CERT )
+ iobuf_pop_filter( inp, md_filter, &pkt->pkt.pubkey_cert->mfx );
+ skip_rest(inp, pktlen);
+ return 0;
+}
+
+
+static int
+parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
+{
+ byte *p;
+
+ packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + pktlen - 1);
+ packet->pkt.user_id->len = pktlen;
+ p = packet->pkt.user_id->name;
+ for( ; pktlen; pktlen--, p++ )
+ *p = iobuf_get_noeof(inp);
+
+ if( list_mode ) {
+ int n = packet->pkt.user_id->len;
+ printf(":user id packet: \"");
+ for(p=packet->pkt.user_id->name; n; p++, n-- ) {
+ if( *p >= ' ' && *p <= 'z' )
+ putchar(*p);
+ else
+ printf("\\x%02x", *p );
+ }
+ printf("\"\n");
+ }
+ return 0;
+}
+
+static void
+parse_comment( IOBUF inp, int pkttype, unsigned long pktlen )
+{
+ if( list_mode ) {
+ printf(":comment packet: \"" );
+ for( ; pktlen; pktlen-- ) {
+ int c;
+ c = iobuf_get_noeof(inp);
+ if( c >= ' ' && c <= 'z' )
+ putchar(c);
+ else
+ printf("\\x%02x", c );
+ }
+ printf("\"\n");
+ }
+ skip_rest(inp, pktlen);
+}
+
+
+static void
+parse_trust( IOBUF inp, int pkttype, unsigned long pktlen )
+{
+ int c;
+
+ c = iobuf_get_noeof(inp);
+ if( list_mode )
+ printf(":trust packet: flag=%02x\n", c );
+ #if 0 /* fixme: depending on the context we have different interpretations*/
+ if( prev_packet_is_a_key_packet ) {
+ int ot = c & 7; /* ownertrust bits (for the key owner) */
+
+ !ot ? "undefined" :
+ ot == 1 ? "unknown" : /* we don't know the owner of this key */
+ ot == 2 ? "no" : /* usually we do not trust this key owner */
+ /* to sign other keys */
+ ot == 5 ? "usually" : /* usually we trust this key owner to sign */
+ ot == 6 ? "always" : /* always trust this key owner to sign */
+ ot == 7 ? "ultimate" : /* also present in the secret keyring */
+ "" /* reserved value */
+ if( c & (1<<5) )
+ "key is disabled"
+ if( c & (1<<7) )
+ "buckstop"
+ else if( prev_packet_is_user_is_packet ) {
+ int kl = c & 3; /* keylegit bits */
+ 0 = "unknown, undefined, or uninitialized trust"
+ 1 = "we do not trust this key's ownership"
+ 2 = "we have marginal confidence of this key's ownership"
+ 3 = "we completely trust this key's ownership."
+ /* This one (3) requires either:
+ * - 1 ultimately trusted signature (SIGTRUST=7)
+ * - COMPLETES_NEEDED completely trusted signatures (SIGTRUST=6)
+ * - MARGINALS_NEEDED marginally trusted signatures (SIGTRUST=5)
+ */
+ if( c & 0x80 )
+ "warnonly"
+ else if( prev_packet_is_a_signature ) {
+ Bits 0-2 - SIGTRUST bits - Trust bits for this signature. Value is
+ copied directly from OWNERTRUST bits of signer:
+ 000 - undefined, or uninitialized trust.
+ 001 - unknown
+ 010 - We do not trust this signature.
+ 011 - reserved
+ 100 - reserved
+ 101 - We reasonably trust this signature.
+ 110 - We completely trust this signature.
+ 111 - ultimately trusted signature (from the owner of the ring)
+ Bit 6 - CHECKED bit - This means that the key checking pass (pgp -kc,
+ also invoked automatically whenever keys are added to the
+ keyring) has tested this signature and found it good. If
+ this bit is not set, the maintenance pass considers this
+ signature untrustworthy.
+ Bit 7 - CONTIG bit - Means this signature leads up a contiguous trusted
+ certification path all the way back to the ultimately-
+ trusted keyring owner, where the buck stops. This bit is derived
+ from other trust packets. It is currently not used for anything
+ in PGP.
+ }
+ #endif
+}
+
+
+static int
+parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
+{
+ int mode, namelen;
+ PKT_plaintext *pt;
+ byte *p;
+ int c, i;
+
+ if( pktlen && pktlen < 6 ) {
+ log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
+ goto leave;
+ }
+ mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
+ namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
+ pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
+ pt->mode = mode;
+ pt->namelen = namelen;
+ if( pktlen ) {
+ for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
+ pt->name[i] = iobuf_get_noeof(inp);
+ }
+ else {
+ for( i=0; i < namelen; i++ )
+ if( (c=iobuf_get(inp)) == -1 )
+ break;
+ else
+ pt->name[i] = c;
+ }
+ pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
+ pt->len = pktlen;
+ pt->buf = inp;
+ pktlen = 0;
+
+ if( list_mode ) {
+ printf(":literal data packet:\n"
+ "\tmode %c, created %lu, name=\"",
+ mode >= ' ' && mode <'z'? mode : '?',
+ pt->timestamp );
+ for(p=pt->name,i=0; i < namelen; p++, i++ ) {
+ if( *p >= ' ' && *p <= 'z' )
+ putchar(*p);
+ else
+ printf("\\x%02x", *p );
+ }
+ printf("\",\n\traw data: %lu bytes\n", pt->len );
+ }
+
+ leave:
+ return 0;
+}
+
+
+static int
+parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
+{
+ PKT_compressed *zd;
+ int algorithm;
+
+ /* pktlen is here 0, but data follows
+ * (this should be the last object in a file or
+ * the compress algorithm should know the length)
+ */
+ zd = pkt->pkt.compressed = m_alloc(sizeof *pkt->pkt.compressed );
+ zd->len = 0; /* not yet used */
+ zd->algorithm = iobuf_get_noeof(inp);
+ zd->buf = inp;
+ algorithm = iobuf_get_noeof(inp);
+ if( list_mode )
+ printf(":compressed packet: algo=%d\n", zd->algorithm);
+ return 0;
+}
+
+
+static int
+parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
+{
+ PKT_encr_data *ed;
+
+ ed = pkt->pkt.encr_data = m_alloc(sizeof *pkt->pkt.encr_data );
+ ed->len = pktlen;
+ ed->buf = NULL;
+ if( pktlen && pktlen < 10 ) {
+ log_error("packet(%d) too short\n", pkttype);
+ skip_rest(inp, pktlen);
+ goto leave;
+ }
+ if( list_mode )
+ if( pktlen )
+ printf(":encrypted data packet:\n\tlength: %lu\n", pktlen-10);
+ else
+ printf(":encrypted data packet:\n\tlength: unknown\n");
+
+ ed->buf = inp;
+ pktlen = 0;
+
+ leave:
+ return 0;
+}
+
+
diff --git a/g10/passphrase.c b/g10/passphrase.c
new file mode 100644
index 000000000..c95b27bbd
--- /dev/null
+++ b/g10/passphrase.c
@@ -0,0 +1,126 @@
+/* passphrase.c - Get a passphrase
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "memory.h"
+#include "ttyio.h"
+#include "cipher.h"
+
+
+static int hash_passphrase( DEK *dek, char *pw );
+
+
+/****************
+ * Get a passphrase for the secret key with KEYID, display TEXT
+ * if the user needs to enter the passphrase.
+ * Returns: m_alloced md5 passphrase hash; caller must free
+ */
+DEK *
+get_passphrase_hash( u32 *keyid, char *text )
+{
+ char *p=NULL, *pw;
+ DEK *dek;
+
+ if( keyid ) {
+ tty_printf("Need a pass phrase to unlock the secret key!\n");
+ tty_printf("KeyID: %08lX\n\n", keyid[1] );
+ }
+ if( keyid && (p=getenv("PGPPATHPHRASE")) ) {
+ pw = m_alloc_secure(strlen(p)+1);
+ strcpy(pw,p);
+ tty_printf("Taking it from $PGPPATHPHRASE !\n", keyid[1] );
+ }
+ else
+ pw = tty_get_hidden("Enter pass phrase: " );
+ dek = m_alloc_secure( sizeof *dek );
+ dek->algo = CIPHER_ALGO_BLOWFISH;
+ if( hash_passphrase( dek, pw ) )
+ log_bug("get_passphrase_hash\n");
+ m_free(pw); /* is allocated in secure memory, so it will be burned */
+ if( !p ) {
+ tty_kill_prompt();
+ tty_printf("\n\n");
+ }
+ return dek;
+}
+
+
+/****************
+ * This function is used to construct a DEK from a user input.
+ * It uses the default CIPHER
+ */
+int
+make_dek_from_passphrase( DEK *dek, int mode )
+{
+ char *pw, *pw2;
+ int rc=0;
+
+ pw = tty_get_hidden("Enter pass phrase: " );
+ tty_kill_prompt();
+ if( mode == 2 ) {
+ pw2 = tty_get_hidden("Repeat pass phrase: " );
+ if( strcmp(pw, pw2) ) {
+ m_free(pw2);
+ m_free(pw);
+ return G10ERR_PASSPHRASE;
+ }
+ m_free(pw2);
+ }
+ rc = hash_passphrase( dek, pw );
+ m_free(pw);
+ return rc;
+}
+
+
+static int
+hash_passphrase( DEK *dek, char *pw )
+{
+ int rc = 0;
+
+ dek->keylen = 0;
+ if( dek->algo == CIPHER_ALGO_IDEA ) {
+ MD5HANDLE md5;
+
+ md5 = md5_open(1);
+ md5_write( md5, pw, strlen(pw) );
+ md5_final( md5 );
+ dek->keylen = 16;
+ memcpy( dek->key, md5_read(md5), dek->keylen );
+ md5_close(md5);
+ }
+ else if( dek->algo == CIPHER_ALGO_BLOWFISH ) {
+ RMDHANDLE rmd;
+
+ rmd = rmd160_open(1);
+ rmd160_write( rmd, pw, strlen(pw) );
+ dek->keylen = 20;
+ memcpy( dek->key, rmd160_final(rmd), dek->keylen );
+ rmd160_close(rmd);
+ }
+ else
+ rc = G10ERR_UNSUPPORTED;
+ return rc;
+}
+
diff --git a/g10/plaintext.c b/g10/plaintext.c
new file mode 100644
index 000000000..be8047bd0
--- /dev/null
+++ b/g10/plaintext.c
@@ -0,0 +1,114 @@
+/* plaintext.c - process an plaintext packet
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "util.h"
+#include "memory.h"
+#include "options.h"
+#include "packet.h"
+#include "ttyio.h"
+
+
+/****************
+ * Handle a plaintext packet
+ */
+int
+handle_plaintext( PKT_plaintext *pt )
+{
+ char *fname;
+ FILE *fp = NULL;
+ int rc = 0;
+ int c;
+
+ /* create the filename as C string */
+ if( opt.outfile ) {
+ fname = m_alloc( strlen( opt.outfile ) + 1);
+ strcpy(fname, opt.outfile );
+ }
+ else {
+ fname = m_alloc( pt->namelen +1 );
+ memcpy( fname, pt->name, pt->namelen );
+ fname[pt->namelen] = 0;
+ }
+
+ if( !*fname ) { /* no filename given */
+ if( opt.outfile_is_stdout )
+ fp = stdout;
+ else {
+ log_error("no outputfile given\n");
+ goto leave;
+ }
+ }
+ else if( overwrite_filep( fname ) )
+ goto leave;
+
+ if( fp )
+ ;
+ else if( !(fp = fopen(fname,"wb")) ) {
+ log_error("Error creating '%s': %s\n", fname, strerror(errno) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+
+ if( pt->len ) {
+ for( ; pt->len; pt->len-- ) {
+ if( (c = iobuf_get(pt->buf)) == -1 ) {
+ log_error("Problem reading source\n");
+ rc = G10ERR_READ_FILE;
+ goto leave;
+ }
+ if( putc( c, fp ) == EOF ) {
+ log_error("Error writing to '%s': %s\n", fname, strerror(errno) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
+ }
+ else {
+ while( (c = iobuf_get(pt->buf)) != -1 ) {
+ if( putc( c, fp ) == EOF ) {
+ log_error("Error writing to '%s': %s\n",
+ fname, strerror(errno) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
+ iobuf_clear_eof(pt->buf);
+ }
+
+ if( fp && fp != stdout && fclose(fp) ) {
+ log_error("Error closing '%s': %s\n", fname, strerror(errno) );
+ fp = NULL;
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ fp = NULL;
+
+ leave:
+ if( fp && fp != stdout )
+ fclose(fp);
+ m_free(fname);
+ return rc;
+}
+
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
new file mode 100644
index 000000000..18c737c2d
--- /dev/null
+++ b/g10/pubkey-enc.c
@@ -0,0 +1,130 @@
+/* pubkey-enc.c - public key encoded packet handling
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "memory.h"
+#include "packet.h"
+#include "mpi.h"
+#include "keydb.h"
+#include "cipher.h"
+
+
+/****************
+ * Get the session key from a pubkey enc paket and return
+ * it in DEK, which should have been allocated in secure memory.
+ */
+int
+get_session_key( PKT_pubkey_enc *k, DEK *dek )
+{
+ int i, j, c, rc = 0;
+ RSA_secret_key *skey = m_alloc_secure( sizeof *skey );
+ MPI dek_frame = mpi_alloc_secure(40);
+ u16 csum, csum2;
+
+ if( k->pubkey_algo != PUBKEY_ALGO_RSA ) {
+ rc = G10ERR_PUBKEY_ALGO; /* unsupported algorithm */
+ goto leave;
+ }
+
+ /* get the secret key for the given public key
+ * and decode the rsa_integer
+ */
+ if( (rc = get_seckey( skey, k->keyid )) )
+ goto leave;
+
+ if( DBG_CIPHER )
+ log_mpidump("Encr DEK frame:", k->d.rsa.rsa_integer );
+ rsa_secret( dek_frame, k->d.rsa.rsa_integer, skey );
+ /* Now get the DEK (data encryption key) from the dek_frame
+ *
+ * Old versions encode the DEK in in this format (msb is left):
+ *
+ * 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2
+ *
+ * Later versions encode the DEK like this:
+ *
+ * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
+ *
+ * RND are non-zero randow bytes.
+ * A is the cipher algorithm ( 1 for IDEA, 42 for blowfish )
+ * DEK is the encryption key (session key) with length k
+ * (16 for idea, 42 for blowfish)
+ * CSUM
+ */
+ if( DBG_CIPHER )
+ log_mpidump("DEK frame:", dek_frame );
+ for(i=0; mpi_getbyte(dek_frame, i) != -1; i++ )
+ ;
+ for(i--; i >= 0 && !(c=mpi_getbyte(dek_frame, i)); i--)
+ ; /* Skip leading zeroes */
+ if( i < 16 )
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
+ if( c == 1 && mpi_getbyte(dek_frame,0) == 2 ) {
+ log_error("old encoding of DEK is not supported\n");
+ rc = G10ERR_CIPHER_ALGO;
+ goto leave;
+ }
+ if( c != 2 ) /* somethink is wrong */
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
+ /* look for the zeor byte */
+ for(i--; i > 4 ; i-- )
+ if( !mpi_getbyte(dek_frame,i) )
+ break;
+ if( i <= 4 ) /* zero byte not found */
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
+ /* next byte indicates the used cipher */
+ switch( mpi_getbyte(dek_frame, --i ) ) {
+ case 1:
+ rc = G10ERR_NI_CIPHER;
+ goto leave;
+ case 42:
+ if( i != 22 ) /* length of blowfish is 20 (+2 bytes checksum) */
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
+ dek->algo = CIPHER_ALGO_BLOWFISH;
+ break;
+ default:
+ rc = G10ERR_CIPHER_ALGO;
+ goto leave;
+ }
+ /* copy the key to DEK and compare the checksum */
+ csum = mpi_getbyte(dek_frame, 1) << 8;
+ csum |= mpi_getbyte(dek_frame, 0);
+ dek->keylen = i - 2;
+ for( i--, csum2=0, j=0; i > 1; i-- )
+ csum2 += dek->key[j++] = mpi_getbyte(dek_frame, i);
+ if( csum != csum2 ) {
+ rc = G10ERR_WRONG_SECKEY;
+ goto leave;
+ }
+ if( DBG_CIPHER )
+ log_hexdump("DEK is:", dek->key, dek->keylen );
+
+ leave:
+ mpi_free(dek_frame);
+ m_free(skey);
+ return rc;
+}
+
+
diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c
new file mode 100644
index 000000000..3cae571ab
--- /dev/null
+++ b/g10/seckey-cert.c
@@ -0,0 +1,157 @@
+/* seckey-cert.c - secret key certifucate packet handling
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "memory.h"
+#include "packet.h"
+#include "mpi.h"
+#include "keydb.h"
+#include "cipher.h"
+
+
+static u16
+checksum( byte *p )
+{
+ u16 n, a;
+
+ n = *p++ << 8;
+ n |= *p++;
+ for(a=0; n; n-- )
+ a += *p++;
+ return a;
+}
+
+
+/****************
+ * Check the secret key certificate
+ */
+int
+check_secret_key( PKT_seckey_cert *cert )
+{
+ IDEA_context idea_ctx; /* FIXME: allocate this in secure space ! */
+ byte iv[8];
+ byte *mpibuf;
+ u16 n;
+ MPI temp_mpi;
+ int res;
+ u32 keyid[2];
+
+#if IDEA_BLOCKSIZE != 8 || BLOWFISH_BLOCKSIZE != 8
+ #error unsupportted blocksize
+#endif
+
+ if( cert->pubkey_algo != PUBKEY_ALGO_RSA )
+ return G10ERR_PUBKEY_ALGO; /* unsupport algorithm */
+
+ if( cert->d.rsa.is_protected ) { /* remove the protection */
+ DEK *dek = NULL;
+ BLOWFISH_context *blowfish_ctx=NULL;
+
+ switch( cert->d.rsa.protect_algo ) {
+ case CIPHER_ALGO_NONE:
+ log_bug("unprotect seckey_cert is flagged protected\n");
+ break;
+ case CIPHER_ALGO_IDEA:
+ case CIPHER_ALGO_BLOWFISH:
+ mpi_get_keyid( cert->d.rsa.rsa_n , keyid );
+ dek = get_passphrase_hash( keyid, NULL );
+
+ /* idea_setkey( &idea_ctx, dpw );*/
+ m_free(dek); /* pw is in secure memory, so m_free() burns it */
+ memset( iv, 0, BLOWFISH_BLOCKSIZE );
+ if( cert->d.rsa.protect_algo == CIPHER_ALGO_IDEA ) {
+ idea_setiv( &idea_ctx, iv );
+ /* fixme: is it save to leave the IV unencrypted in the
+ * certificate or should we move it to secure storage? */
+ idea_decode_cfb( &idea_ctx, cert->d.rsa.protect.idea.iv,
+ cert->d.rsa.protect.idea.iv, 8 );
+ }
+ else {
+ blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
+ blowfish_setiv( blowfish_ctx, iv );
+ blowfish_decode_cfb( blowfish_ctx,
+ cert->d.rsa.protect.blowfish.iv,
+ cert->d.rsa.protect.blowfish.iv, 8 );
+ }
+ cert->d.rsa.calc_csum = 0;
+ #define X(a) do { \
+ mpibuf = (byte*)cert->d.rsa.rsa_##a; \
+ n = ((mpibuf[0] << 8) | mpibuf[1])-2; \
+ if( blowfish_ctx ) \
+ blowfish_decode_cfb( blowfish_ctx, \
+ mpibuf+4, mpibuf+4, n ); \
+ else \
+ idea_decode_cfb( &idea_ctx, mpibuf+4, mpibuf+4, n );\
+ cert->d.rsa.calc_csum += checksum( mpibuf ); \
+ cert->d.rsa.rsa_##a = mpi_decode_buffer( mpibuf ); \
+ m_free( mpibuf ); \
+ } while(0)
+ X(d);
+ X(p);
+ X(q);
+ X(u);
+ #undef X
+ m_free( blowfish_ctx );
+ cert->d.rsa.is_protected = 0;
+ #if 0
+ #define X(a) do { printf("\tRSA " #a ": "); \
+ mpi_print(stdout, cert->d.rsa.rsa_##a, 1 ); \
+ putchar('\n'); \
+ } while(0)
+ X(n);
+ X(e);
+ X(d);
+ X(p);
+ X(q);
+ X(u);
+ #undef X
+ #endif
+ /* now let's see wether we have used the right passphrase */
+ if( cert->d.rsa.calc_csum != cert->d.rsa.csum )
+ return G10ERR_BAD_PASS;
+ temp_mpi = mpi_alloc(40);
+ mpi_mul(temp_mpi, cert->d.rsa.rsa_p, cert->d.rsa.rsa_q );
+ res = mpi_cmp( temp_mpi, cert->d.rsa.rsa_n );
+ mpi_free(temp_mpi);
+ if( res )
+ return G10ERR_BAD_PASS;
+ break;
+
+ default:
+ return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
+ }
+ }
+ /* must check the checksum here, because we didn't do it when
+ * parsing an unprotected certificate */
+ if( cert->d.rsa.calc_csum != cert->d.rsa.csum ) {
+ log_error("checksum in secret key certificate is wrong\n");
+ log_debug("stored csum=%04hx calculated csum=%04hx\n",
+ cert->d.rsa.csum, cert->d.rsa.calc_csum );
+ return G10ERR_CHECKSUM;
+ }
+ return 0;
+}
+
+
diff --git a/g10/seskey.c b/g10/seskey.c
new file mode 100644
index 000000000..d81697296
--- /dev/null
+++ b/g10/seskey.c
@@ -0,0 +1,101 @@
+/* seskey.c - make sesssion keys
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "cipher.h"
+#include "mpi.h"
+
+
+
+/****************
+ * Make a session key and put it into DEK
+ */
+void
+make_session_key( DEK *dek )
+{
+ switch( dek->algo ) {
+ case CIPHER_ALGO_BLOWFISH:
+ dek->keylen = 20;
+ randomize_buffer( dek->key, dek->keylen, 1 );
+ break;
+
+ default: log_bug("invalid algo %d in make_session_key()\n");
+ }
+}
+
+
+/****************
+ * Encode the session key. NBITS is the number of bits which should be used
+ * for packing teh session key.
+ * returns: A mpi with the session key (caller must free)
+ */
+MPI
+encode_session_key( DEK *dek, unsigned nbits )
+{
+ int nframe = (nbits+7) / 8;
+ byte *p;
+ MPI frame;
+ int i,n,c;
+ u16 csum;
+
+ /* the current limitation is, that we can only use a session key
+ * which length is a multiple of BITS_PER_MPI_LIMB
+ * I think we can live with that.
+ */
+ if( dek->keylen + 7 > nframe || (nbits % BITS_PER_MPI_LIMB) || !nframe )
+ log_bug("can't encode a %d bit key in a %d bits frame\n",
+ dek->keylen*8, nbits );
+
+ /* We encode the session key in this way:
+ *
+ * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
+ *
+ * RND are non-zero random bytes.
+ * A is the cipher algorithm ( 42 for Blowfish )
+ * DEK is the encryption key (session key) length k depends on the
+ * cipher algorithm (20 is used with blowfish).
+ * CSUM is the 16 bit checksum over the DEK
+ */
+ frame = mpi_alloc_secure( nframe / BYTES_PER_MPI_LIMB );
+ csum = 0;
+ for( p = dek->key, i=0; i < dek->keylen; i++ )
+ csum += *p++;
+ mpi_putbyte(frame, 0, csum );
+ mpi_putbyte(frame, 1, csum >> 8 );
+ for(n=2,i=dek->keylen-1, p = dek->key; i >= 0; i--, n++ )
+ mpi_putbyte(frame, n, p[i] );
+ mpi_putbyte(frame, n++, dek->algo );
+ mpi_putbyte(frame, n++, 0 );
+ while( n < nframe-2 ) {
+ while( !(c = get_random_byte(1)) )
+ ;
+ mpi_putbyte(frame, n++, c );
+ }
+ mpi_putbyte(frame, n++, 2 );
+ mpi_putbyte(frame, n++, 0 );
+ assert( n == nframe );
+ return frame;
+}
+
diff --git a/g10/sig-check.c b/g10/sig-check.c
new file mode 100644
index 000000000..41ac89341
--- /dev/null
+++ b/g10/sig-check.c
@@ -0,0 +1,213 @@
+/* sig-check.c - Check a signature
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "util.h"
+#include "packet.h"
+#include "memory.h"
+#include "mpi.h"
+#include "keydb.h"
+#include "cipher.h"
+
+
+/****************
+ * Check the signature which is contained in the rsa_integer.
+ * The md5handle should be currently open, so that this function
+ * is able to append some data, before getting the digest.
+ */
+int
+signature_check( PKT_signature *sig, MD_HANDLE digest )
+{
+ PKT_pubkey_cert *pkc = m_alloc_clear( sizeof *pkc );
+ MPI result = mpi_alloc(35);
+ int rc=0, i, j, c, old_enc;
+ byte *dp;
+
+
+ if( get_pubkey( pkc, sig->keyid ) ) {
+ rc = G10ERR_NO_PUBKEY;
+ goto leave;
+ }
+
+ if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ RSA_public_key pkey;
+ pkey.n = pkc->d.rsa.rsa_n;
+ pkey.e = pkc->d.rsa.rsa_e;
+ rsa_public( result, sig->d.rsa.rsa_integer, &pkey );
+ }
+ else {
+ log_debug("signature_check: unsupported pubkey algo %d\n",
+ pkc->pubkey_algo );
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+
+ /* Now RESULT contains the deciphered session key.
+ *
+ * The session key is stored in different ways:
+ *
+ * Old versions encodes the digest in in this format (msb is left):
+ *
+ * 0 1 MD5(16 bytes) 0 PAD(n bytes) 1
+ *
+ * Later versions encodes the digest like this:
+ *
+ * 0 1 PAD(n bytes) 0 ASN(18 bytes) MD(16 bytes)
+ *
+ * RIPE MD 160 digests are encoded like this:
+ *
+ * 0 42 PAD(n bytes) 0 ASN(18 bytes) MD(20 bytes)
+ *
+ * FIXME: we should use another ASN!
+ *
+ * PAD consists of FF bytes.
+ * ASN is here the constant: 3020300c06082a864886f70d020505000410
+ */
+ old_enc = 0;
+ for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) {
+ if( !j ) {
+ if( !i && c != 1 )
+ break;
+ else if( i && c == 0xff )
+ ; /* skip the padding */
+ else if( i && !c )
+ j++;
+ else
+ break;
+ }
+ else if( ++j == 18 && c != 1 )
+ break;
+ else if( j == 19 && c == 0 ) {
+ old_enc++;
+ break;
+ }
+ }
+ if( old_enc ) {
+ log_error("old encoding scheme is not supported\n");
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
+
+ if( sig->d.rsa.digest_algo == DIGEST_ALGO_RMD160 ) {
+ static byte asn[18] = /* stored reverse FIXME: need other values*/
+ { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86,
+ 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 };
+
+ for(i=20,j=0; j < 18 && (c=mpi_getbyte(result, i)) != -1; i++, j++ )
+ if( asn[j] != c )
+ break;
+ if( j != 18 ) { /* ASN is wrong */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ if( !c ) {
+ for(; (c=mpi_getbyte(result, i)) != -1; i++ )
+ if( c != 0xff )
+ break;
+ if( c != 42 || mpi_getbyte(result, i) ) {
+ /* Padding or leading bytes in signature is wrong */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ if( mpi_getbyte(result, 19) != sig->d.rsa.digest_start[0]
+ || mpi_getbyte(result, 18) != sig->d.rsa.digest_start[1] ) {
+ /* Wrong key used to check the signature */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ }
+
+ /* complete the digest */
+ rmd160_putchar( digest.u.rmd, sig->sig_class );
+ { u32 a = sig->timestamp;
+ rmd160_putchar( digest.u.rmd, (a >> 24) & 0xff );
+ rmd160_putchar( digest.u.rmd, (a >> 16) & 0xff );
+ rmd160_putchar( digest.u.rmd, (a >> 8) & 0xff );
+ rmd160_putchar( digest.u.rmd, a & 0xff );
+ }
+ dp = rmd160_final( digest.u.rmd );
+ for(i=19; i >= 0; i--, dp++ )
+ if( mpi_getbyte( result, i ) != *dp ) {
+ rc = G10ERR_BAD_SIGN;
+ goto leave;
+ }
+ }
+ else if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) {
+ static byte asn[18] = /* stored reverse */
+ { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86,
+ 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 };
+
+ for(i=16,j=0; j < 18 && (c=mpi_getbyte(result, i)) != -1; i++, j++ )
+ if( asn[j] != c )
+ break;
+ if( j != 18 ) { /* ASN is wrong */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ if( !c ) {
+ for(; (c=mpi_getbyte(result, i)) != -1; i++ )
+ if( c != 0xff )
+ break;
+ if( c != 1 || mpi_getbyte(result, i) ) {
+ /* Padding or leading bytes in signature is wrong */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ if( mpi_getbyte(result, 15) != sig->d.rsa.digest_start[0]
+ || mpi_getbyte(result, 14) != sig->d.rsa.digest_start[1] ) {
+ /* Wrong key used to check the signature */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ }
+
+ /* complete the digest */
+ md5_putchar( digest.u.md5, sig->sig_class );
+ { u32 a = sig->timestamp;
+ md5_putchar( digest.u.md5, (a >> 24) & 0xff );
+ md5_putchar( digest.u.md5, (a >> 16) & 0xff );
+ md5_putchar( digest.u.md5, (a >> 8) & 0xff );
+ md5_putchar( digest.u.md5, a & 0xff );
+ }
+ md5_final( digest.u.md5 );
+ dp = md5_read( digest.u.md5 );
+ for(i=15; i >= 0; i--, dp++ )
+ if( mpi_getbyte( result, i ) != *dp ) {
+ rc = G10ERR_BAD_SIGN;
+ goto leave;
+ }
+ }
+ else {
+ rc = G10ERR_DIGEST_ALGO;
+ goto leave;
+ }
+
+ leave:
+ mpi_free( result );
+ if( pkc )
+ free_pubkey_cert( pkc );
+ return rc;
+}
+
diff --git a/include/cipher.h b/include/cipher.h
new file mode 100644
index 000000000..ac19c3fc0
--- /dev/null
+++ b/include/cipher.h
@@ -0,0 +1,87 @@
+/* cipher.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * ATTENTION: This code should not be exported from the United States
+ * nor should it be used their without a license agreement with PKP.
+ * The RSA alorithm is protected by U.S. Patent #4,405,829 which
+ * expires on September 20, 2000!
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_CIPHER_H
+#define G10_CIPHER_H
+
+#define DBG_CIPHER cipher_debug_mode
+
+#include "mpi.h"
+#include "../cipher/md5.h"
+#include "../cipher/rmd.h"
+#include "../cipher/rsa.h"
+#include "../cipher/idea.h"
+#include "../cipher/blowfish.h"
+#include "../cipher/gost.h"
+#include "../cipher/elgamal.h"
+
+
+#define CIPHER_ALGO_NONE 0
+#define CIPHER_ALGO_IDEA 1
+#define CIPHER_ALGO_BLOWFISH 42
+#define CIPHER_ALGO_GOST 43
+
+#define PUBKEY_ALGO_RSA 1
+#define PUBKEY_ALGO_ELGAMAL 42
+
+#define DIGEST_ALGO_MD5 1
+#define DIGEST_ALGO_RMD160 42
+
+#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_BLOWFISH
+#define DEFAULT_PUBKEY_ALGO PUBKEY_ALGO_RSA
+#define DEFAULT_DIGEST_ALGO DIGEST_ALGO_RMD160
+
+typedef struct {
+ int algo;
+ int keylen;
+ byte key[20]; /* this is the largest used keylen */
+} DEK;
+
+typedef struct {
+ int algo; /* digest algo */
+ union {
+ MD5HANDLE md5;
+ RMDHANDLE rmd;
+ } u;
+} MD_HANDLE;
+
+
+int cipher_debug_mode;
+
+/*-- random.c --*/
+void randomize_buffer( byte *buffer, size_t length, int level );
+byte get_random_byte( int level );
+
+/*-- smallprime.c --*/
+extern ushort small_prime_numbers[];
+
+/*-- primegen.c --*/
+MPI generate_random_prime( unsigned nbits );
+
+/*-- seskey.c --*/
+void make_session_key( DEK *dek );
+MPI encode_session_key( DEK *dek, unsigned nbits );
+
+
+#endif /*G10_CIPHER_H*/
diff --git a/include/errors.h b/include/errors.h
new file mode 100644
index 000000000..f2e7570cc
--- /dev/null
+++ b/include/errors.h
@@ -0,0 +1,52 @@
+/* errors.h - erro code
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_ERRORS_H
+#define G10_ERRORS_H
+
+#define G10ERR_GENERAL 1
+#define G10ERR_UNKNOWN_PACKET 2
+#define G10ERR_UNKNOWN_VERSION 3 /* Unknown version (in packet) */
+#define G10ERR_PUBKEY_ALGO 4 /* Unknown pubkey algorithm */
+#define G10ERR_DIGEST_ALGO 5 /* Unknown digest algorithm */
+#define G10ERR_BAD_PUBKEY 6 /* Bad public key */
+#define G10ERR_BAD_SECKEY 7 /* Bad secret key */
+#define G10ERR_BAD_SIGN 8 /* Bad signature */
+#define G10ERR_NO_PUBKEY 9 /* public key not found */
+#define G10ERR_CHECKSUM 10 /* checksum error */
+#define G10ERR_BAD_PASS 11 /* Bad passphrase */
+#define G10ERR_CIPHER_ALGO 12 /* Unknown cipher algorithm */
+#define G10ERR_KEYRING_OPEN 13
+#define G10ERR_INVALID_PACKET 14
+#define G10ERR_BAD_RING 15
+#define G10ERR_NO_USER_ID 16
+#define G10ERR_NO_SECKEY 17 /* secret key not available */
+#define G10ERR_WRONG_SECKEY 18 /* wrong seckey used */
+#define G10ERR_UNSUPPORTED 19
+#define G10ERR_BAD_KEY 20 /* bad (session) key */
+#define G10ERR_READ_FILE 21
+#define G10ERR_WRITE_FILE 22
+#define G10ERR_COMPR_ALGO 23 /* Unknown compress algorithm */
+#define G10ERR_OPEN_FILE 24
+#define G10ERR_CREATE_FILE 25
+#define G10ERR_PASSPHRASE 26 /* invalid passphrase */
+#define G10ERR_NI_PUBKEY 27
+#define G10ERR_NI_CIPHER 28
+
+#endif /*G10_ERRORS_H*/
diff --git a/include/iobuf.h b/include/iobuf.h
new file mode 100644
index 000000000..328cd8da5
--- /dev/null
+++ b/include/iobuf.h
@@ -0,0 +1,120 @@
+/* iobuf.h - I/O buffer
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef G10_IOBUF_H
+#define G10_IOBUF_H
+
+#include "types.h"
+
+
+#define DBG_IOBUF iobuf_debug_mode
+
+
+#define IOBUFCTRL_INIT 1
+#define IOBUFCTRL_FREE 2
+#define IOBUFCTRL_UNDERFLOW 3
+#define IOBUFCTRL_FLUSH 4
+#define IOBUFCTRL_DESC 5
+#define IOBUFCTRL_USER 16
+
+typedef struct iobuf_struct *IOBUF;
+
+struct iobuf_struct {
+ int usage; /* 1 input , 2 output, 3 temp */
+ unsigned long nlimit;
+ unsigned long nbytes;
+ struct {
+ size_t size; /* allocated size */
+ size_t start; /* number of invalid bytes at the begin of the buffer */
+ size_t len; /* currently filled to this size */
+ byte *buf;
+ } d;
+ struct {
+ size_t size;
+ size_t len;
+ char *buf;
+ } recorder;
+ int filter_eof;
+ int (*filter)( void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *len);
+ void *filter_ov; /* value for opaque */
+ IOBUF chain; /* next iobuf used for i/o if any (passed to filter) */
+ int no, subno;
+ const char *desc;
+};
+
+int iobuf_debug_mode;
+
+IOBUF iobuf_alloc(int usage, size_t bufsize);
+IOBUF iobuf_temp(void);
+IOBUF iobuf_open( const char *fname );
+IOBUF iobuf_create( const char *fname );
+int iobuf_close( IOBUF iobuf );
+int iobuf_cancel( IOBUF iobuf );
+
+int iobuf_push_filter( IOBUF a, int (*f)(void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *len), void *ov );
+int iobuf_pop_filter( IOBUF a, int (*f)(void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *len), void *ov );
+int iobuf_flush(IOBUF a);
+void iobuf_clear_eof(IOBUF a);
+
+void iobuf_set_limit( IOBUF a, unsigned long nlimit );
+
+int iobuf_readbyte(IOBUF a);
+int iobuf_writebyte(IOBUF a, unsigned c);
+int iobuf_write(IOBUF a, byte *buf, unsigned buflen );
+
+int iobuf_write_temp( IOBUF a, IOBUF temp );
+size_t iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen );
+
+void iobuf_start_recorder( IOBUF a );
+void iobuf_push_recorder( IOBUF a, int c );
+char *iobuf_stop_recorder( IOBUF a, size_t *n );
+
+u32 iobuf_get_filelength( IOBUF a );
+
+void iobuf_set_block_mode( IOBUF a, size_t n );
+int iobuf_in_block_mode( IOBUF a );
+
+/* get a byte form the iobuf; must check for eof prior to this function
+ * this function returns values in the range 0 .. 255 or -1 to indicate EOF
+ * iobuf_get_noeof() does not return -1 to indicate EOF, but masks the
+ * returned value to be in the range 0 ..255.
+ */
+#define iobuf_get(a) \
+ ( ((a)->recorder.buf || (a)->nlimit \
+ || (a)->d.start >= (a)->d.len )? \
+ iobuf_readbyte((a)) : ( (a)->nbytes++, (a)->d.buf[(a)->d.start++] ) )
+#define iobuf_get_noeof(a) (iobuf_get((a))&0xff)
+
+
+/* write a byte to the iobuf and return true on write error
+ * This macro does only write the low order byte
+ */
+#define iobuf_put(a,c) iobuf_writebyte(a,c)
+
+#define iobuf_where(a) "[don't know]"
+#define iobuf_id(a) ((a)->no)
+
+#define iobuf_get_temp_length(a) ( (a)->d.len )
+#define iobuf_is_temp(a) ( (a)->usage == 3 )
+
+#endif /*G10_IOBUF_H*/
diff --git a/include/memory.h b/include/memory.h
new file mode 100644
index 000000000..aa8bb706d
--- /dev/null
+++ b/include/memory.h
@@ -0,0 +1,64 @@
+/* memory.h - memory allocation
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef G10_MEMORY_H
+#define G10_MEMORY_H
+
+#ifdef M_DEBUG
+#ifndef STR
+ #define STR(v) #v
+#endif
+#define M_DBGINFO(a) __FUNCTION__ "["__FILE__ ":" STR(a) "]"
+#define m_alloc(n) m_debug_alloc((n), M_DBGINFO( __LINE__ ) )
+#define m_alloc_clear(n) m_debug_alloc_clear((n), M_DBGINFO(__LINE__) )
+#define m_alloc_secure(n) m_debug_alloc((n), M_DBGINFO(__LINE__) )
+#define m_alloc_secure_clear(n) m_debug_alloc((n), M_DBGINFO(__LINE__) )
+#define m_realloc(n,m) m_debug_realloc((n),(m), M_DBGINFO(__LINE__) )
+#define m_free(n) m_debug_free((n), M_DBGINFO(__LINE__) )
+#define m_check(n) m_debug_check((n), M_DBGINFO(__LINE__) )
+
+void *m_debug_alloc( size_t n, const char *info );
+void *m_debug_alloc_clear( size_t n, const char *info );
+void *m_debug_alloc_secure( size_t n, const char *info );
+void *m_debug_alloc_secure_clear( size_t n, const char *info );
+void *m_debug_realloc( void *a, size_t n, const char *info );
+void m_debug_free( void *p, const char *info );
+void m_debug_check( const void *a, const char *info );
+
+#else
+void *m_alloc( size_t n );
+void *m_alloc_clear( size_t n );
+void *m_alloc_secure( size_t n );
+void *m_alloc_secure_clear( size_t n );
+void *m_realloc( void *a, size_t n );
+void m_free( void *p );
+void m_check( const void *a );
+#endif
+
+
+size_t m_size( const void *a );
+int m_is_secure( const void *p );
+
+#define DBG_MEMORY memory_debug_mode
+#define DBG_MEMSTAT memory_stat_debug_mode
+int memory_debug_mode;
+int memory_stat_debug_mode;
+
+#endif /*G10_MEMORY_H*/
diff --git a/include/mpi.h b/include/mpi.h
new file mode 100644
index 000000000..4470c609a
--- /dev/null
+++ b/include/mpi.h
@@ -0,0 +1,147 @@
+/* mpi.h - Multi Precision Integers
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef G10_MPI_H
+#define G10_MPI_H
+
+#include <stdio.h>
+#include "iobuf.h"
+#include "types.h"
+#include "memory.h"
+
+
+#define DBG_MPI mpi_debug_mode
+int mpi_debug_mode;
+
+#if defined(__i386__)
+ #define BITS_PER_MPI_LIMB 32
+ #define BYTES_PER_MPI_LIMB 4
+ #define BYTES_PER_MPI_LIMB2 8
+ typedef unsigned long int mpi_limb_t;
+ typedef signed long int mpi_limb_signed_t;
+#else
+ #error add definions for this machine here
+#endif
+
+typedef struct {
+ int alloced; /* array size (# of allocated limbs) */
+ int nlimbs; /* number of valid limbs */
+ int sign; /* indicates a negative number */
+ int secure; /* array mut be allocated in secure memory space */
+ mpi_limb_t *d; /* array with the limbs */
+} *MPI;
+
+#define MPI_NULL NULL
+
+#define mpi_get_nlimbs(a) ((a)->nlimbs)
+
+/*-- mpiutil.c --*/
+
+#ifdef M_DEBUG
+ #define mpi_alloc(n) mpi_debug_alloc((n), M_DBGINFO( __LINE__ ) )
+ #define mpi_alloc_secure(n) mpi_debug_alloc_secure((n), M_DBGINFO( __LINE__ ) )
+ #define mpi_free(a) mpi_debug_free((a), M_DBGINFO(__LINE__) )
+ #define mpi_resize(a,b) mpi_debug_resize((a),(b), M_DBGINFO(__LINE__) )
+ #define mpi_copy(a) mpi_debug_copy((a), M_DBGINFO(__LINE__) )
+ MPI mpi_debug_alloc( unsigned nlimbs, const char *info );
+ MPI mpi_debug_alloc_secure( unsigned nlimbs, const char *info );
+ void mpi_debug_free( MPI a, const char *info );
+ void mpi_debug_resize( MPI a, unsigned nlimbs, const char *info );
+ MPI mpi_debug_copy( MPI a, const char *info );
+#else
+ MPI mpi_alloc( unsigned nlimbs );
+ MPI mpi_alloc_secure( unsigned nlimbs );
+ void mpi_free( MPI a );
+ void mpi_resize( MPI a, unsigned nlimbs );
+ MPI mpi_copy( MPI a );
+#endif
+void mpi_clear( MPI a );
+void mpi_set( MPI w, MPI u);
+void mpi_set_ui( MPI w, ulong u);
+MPI mpi_alloc_set_ui( unsigned long u);
+void mpi_m_check( MPI a );
+void mpi_swap( MPI a, MPI b);
+
+/*-- mpicoder.c --*/
+int mpi_encode( IOBUF out, MPI a );
+int mpi_encode_csum( IOBUF out, MPI a, u16 *csum );
+int mpi_write( IOBUF out, byte *a);
+int mpi_write_csum( IOBUF out, byte *a, u16 *csum);
+#ifdef M_DEBUG
+ #define mpi_decode(a,b) mpi_debug_decode((a),(b), M_DBGINFO( __LINE__ ) )
+ #define mpi_decode_buffer(a) mpi_debug_decode_buffer((a), M_DBGINFO( __LINE__ ) )
+ MPI mpi_debug_decode(IOBUF inp, unsigned *nread, const char *info);
+ MPI mpi_debug_decode_buffer(byte *buffer, const char *info );
+#else
+ MPI mpi_decode(IOBUF inp, unsigned *nread);
+ MPI mpi_decode_buffer(byte *buffer );
+#endif
+byte *mpi_read(IOBUF inp, unsigned *ret_nread);
+int mpi_fromstr(MPI val, const char *str);
+int mpi_print( FILE *fp, MPI a, int mode );
+u32 mpi_get_keyid( MPI a, u32 *keyid );
+
+/*-- mpi-add.c --*/
+void mpi_add_ui(MPI w, MPI u, ulong v );
+void mpi_add(MPI w, MPI u, MPI v);
+void mpi_sub_ui(MPI w, MPI u, ulong v );
+void mpi_sub( MPI w, MPI u, MPI v);
+
+/*-- mpi-mul.c --*/
+void mpi_mul_ui(MPI w, MPI u, ulong v );
+void mpi_mul_2exp( MPI w, MPI u, ulong cnt);
+void mpi_mul( MPI w, MPI u, MPI v);
+
+/*-- mpi-div.c --*/
+ulong mpi_fdiv_r_ui( MPI rem, MPI dividend, ulong divisor );
+void mpi_fdiv_r( MPI rem, MPI dividend, MPI divisor );
+void mpi_fdiv_q( MPI quot, MPI dividend, MPI divisor );
+void mpi_fdiv_qr( MPI quot, MPI rem, MPI dividend, MPI divisor );
+void mpi_tdiv_r( MPI rem, MPI num, MPI den);
+void mpi_tdiv_qr( MPI quot, MPI rem, MPI num, MPI den);
+int mpi_divisible_ui(MPI dividend, ulong divisor );
+
+/*-- mpi-gcd.c --*/
+int mpi_gcd( MPI g, MPI a, MPI b );
+
+/*-- mpi-pow.c --*/
+void mpi_pow( MPI w, MPI u, MPI v);
+void mpi_powm( MPI res, MPI base, MPI exp, MPI mod);
+
+/*-- mpi-cmp.c --*/
+int mpi_cmp_ui( MPI u, ulong v );
+int mpi_cmp( MPI u, MPI v );
+
+/*-- mpi-scan.c --*/
+int mpi_getbyte( MPI a, unsigned index );
+void mpi_putbyte( MPI a, unsigned index, int value );
+
+/*-- mpi-bit.c --*/
+unsigned mpi_get_nbits( MPI a );
+int mpi_test_bit( MPI a, unsigned n );
+void mpi_set_bit( MPI a, unsigned n );
+void mpi_clear_bit( MPI a, unsigned n );
+void mpi_set_bytes( MPI a, unsigned nbits, byte (*fnc)(int), int opaque );
+
+/*-- mpi-inv.c --*/
+int mpi_inv_mod( MPI x, MPI u, MPI v );
+
+
+#endif /*G10_MPI_H*/
diff --git a/include/ttyio.h b/include/ttyio.h
new file mode 100644
index 000000000..80f66d842
--- /dev/null
+++ b/include/ttyio.h
@@ -0,0 +1,29 @@
+/* ttyio.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_TTYIO_H
+#define G10_TTYIO_H
+
+void tty_printf( const char *fmt, ... );
+char *tty_get( const char *prompt );
+char *tty_get_hidden( const char *prompt );
+void tty_kill_prompt(void);
+
+
+#endif /*G10_TTYIO_H*/
diff --git a/include/types.h b/include/types.h
new file mode 100644
index 000000000..7db849f41
--- /dev/null
+++ b/include/types.h
@@ -0,0 +1,76 @@
+/* types.h - some common typedefs
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef G10_TYPES_H
+#define G10_TYPES_H
+
+#ifdef __linux__
+ #include <linux/types.h>
+ #define HAVE_ULONG_TYPEDEF
+ #define HAVE_USHORT_TYPEDEF
+#endif
+
+
+/* Common code */
+#ifndef HAVE_ULONG_TYPEDEF
+ #define HAVE_ULONG_TYPEDEF
+ typedef unsigned long ulong;
+#endif
+#ifndef HAVE_USHORT_TYPEDEF
+ #define HAVE_USHORT_TYPEDEF
+ typedef unsigned short ushort;
+#endif
+
+
+typedef struct string_list {
+ struct string_list *next;
+ char d[1];
+} *STRLIST;
+
+
+
+/****************************************
+ ******** machine dependent stuff *******
+ ****************************************/
+
+#if defined(__hpux)
+ #define HAVE_BIG_ENDIAN 1
+#else
+ #define HAVE_LITTLE_ENDIAN 1
+#endif
+
+
+/*** some defaults ***/
+#ifndef HAVE_BYTE_TYPEDEF
+ #define HAVE_BYTE_TYPEDEF
+ typedef unsigned char byte;
+#endif
+#ifndef HAVE_U16_TYPEDEF
+ #define HAVE_U16_TYPEDEF
+ typedef unsigned short u16;
+#endif
+#ifndef HAVE_U32_TYPEDEF
+ #define HAVE_U32_TYPEDEF
+ typedef unsigned long u32;
+#endif
+
+
+
+#endif /*G10_TYPES_H*/
diff --git a/include/util.h b/include/util.h
new file mode 100644
index 000000000..6740e5edd
--- /dev/null
+++ b/include/util.h
@@ -0,0 +1,100 @@
+/* util.h
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef G10_UTIL_H
+#define G10_UTIL_H
+
+#include "errors.h"
+#include "types.h"
+#include "mpi.h"
+
+
+typedef struct {
+ int *argc; /* pointer to argc (value subject to change) */
+ char ***argv; /* pointer to argv (value subject to change) */
+ unsigned flags; /* Global flags (DO NOT CHANGE) */
+ int err; /* print error about last option */
+ /* 1 = warning, 2 = abort */
+ int r_opt; /* return option */
+ int r_type; /* type of return value (0 = no argument found)*/
+ union {
+ int ret_int;
+ long ret_long;
+ ulong ret_ulong;
+ char *ret_str;
+ } r; /* Return values */
+ struct {
+ int index;
+ int inarg;
+ int stopped;
+ const char *last;
+ } internal; /* DO NOT CHANGE */
+} ARGPARSE_ARGS;
+
+typedef struct {
+ int short_opt;
+ const char *long_opt;
+ unsigned flags;
+ const char *description; /* optional option description */
+} ARGPARSE_OPTS;
+
+/*-- logger.c --*/
+void printstr( int level, const char *fmt, ... );
+void log_bug( const char *fmt, ... );
+void log_fatal( const char *fmt, ... );
+void log_error( const char *fmt, ... );
+void log_info( const char *fmt, ... );
+void log_debug( const char *fmt, ... );
+void log_hexdump( const char *text, char *buf, size_t len );
+void log_mpidump( const char *text, MPI a );
+
+/*-- errors.c --*/
+const char * g10_errstr( int no );
+
+/*-- argparse.c --*/
+int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
+void usage( int level );
+const char *default_strusage( int level );
+
+
+/*-- (main program) --*/
+const char *strusage( int level );
+
+
+/*-- fileutil.c --*/
+
+/*-- miscutil.c --*/
+u32 make_timestamp(void);
+
+/*-- strgutil.c --*/
+void free_strlist( STRLIST sl );
+#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0)
+char *memistr( char *buf, size_t buflen, const char *sub );
+#define stricmp(a,b) strcasecmp((a),(b))
+
+
+/******** some macros ************/
+#ifndef STR
+ #define STR(v) #v
+#endif
+#define STR2(v) STR(v)
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member) DIM(((type *)0)->member)
+
+#endif /*G10_UTIL_H*/
diff --git a/mpi/Makefile.am b/mpi/Makefile.am
new file mode 100644
index 000000000..5edd90c28
--- /dev/null
+++ b/mpi/Makefile.am
@@ -0,0 +1,27 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LIBRARIES = mpi
+
+
+mpi_SOURCES = longlong.h \
+ mpi-add.c \
+ mpi-bit.c \
+ mpi-cmp.c \
+ mpi-div.c \
+ mpi-gcd.c \
+ mpi-internal.h \
+ mpi-inv.c \
+ mpi-mul.c \
+ mpi-pow.c \
+ mpi-scan.c \
+ mpicoder.c \
+ mpihelp-add.c \
+ mpihelp-cmp.c \
+ mpihelp-div.c \
+ mpihelp-mul.c \
+ mpihelp-shift.c \
+ mpihelp-sub.c \
+ mpiutil.c
+
diff --git a/mpi/Makefile.in b/mpi/Makefile.in
new file mode 100644
index 000000000..4f493a88e
--- /dev/null
+++ b/mpi/Makefile.in
@@ -0,0 +1,271 @@
+# Makefile.in generated automatically by automake 1.0 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LIBRARIES = mpi
+
+mpi_SOURCES = longlong.h \
+ mpi-add.c \
+ mpi-bit.c \
+ mpi-cmp.c \
+ mpi-div.c \
+ mpi-gcd.c \
+ mpi-internal.h \
+ mpi-inv.c \
+ mpi-mul.c \
+ mpi-pow.c \
+ mpi-scan.c \
+ mpicoder.c \
+ mpihelp-add.c \
+ mpihelp-cmp.c \
+ mpihelp-div.c \
+ mpihelp-mul.c \
+ mpihelp-shift.c \
+ mpihelp-sub.c \
+ mpiutil.c
+mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
+CONFIG_HEADER = ../config.h
+LIBRARIES = $(noinst_LIBRARIES)
+
+noinst_LIBFILES = libmpi.a
+
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+mpi_LIBADD =
+mpi_OBJECTS = mpi-add.o mpi-bit.o mpi-cmp.o mpi-div.o mpi-gcd.o \
+mpi-inv.o mpi-mul.o mpi-pow.o mpi-scan.o mpicoder.o mpihelp-add.o \
+mpihelp-cmp.o mpihelp-div.o mpihelp-mul.o mpihelp-shift.o mpihelp-sub.o \
+mpiutil.o
+EXTRA_mpi_SOURCES =
+LIBFILES = libmpi.a
+AR = ar
+RANLIB = @RANLIB@
+DIST_COMMON = Makefile.am Makefile.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA)
+DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA)
+
+TAR = tar
+DEP_FILES = $(srcdir)/.deps/mpi-add.P $(srcdir)/.deps/mpi-bit.P \
+$(srcdir)/.deps/mpi-cmp.P $(srcdir)/.deps/mpi-div.P \
+$(srcdir)/.deps/mpi-gcd.P $(srcdir)/.deps/mpi-inv.P \
+$(srcdir)/.deps/mpi-mul.P $(srcdir)/.deps/mpi-pow.P \
+$(srcdir)/.deps/mpi-scan.P $(srcdir)/.deps/mpicoder.P \
+$(srcdir)/.deps/mpihelp-add.P $(srcdir)/.deps/mpihelp-cmp.P \
+$(srcdir)/.deps/mpihelp-div.P $(srcdir)/.deps/mpihelp-mul.P \
+$(srcdir)/.deps/mpihelp-shift.P $(srcdir)/.deps/mpihelp-sub.P \
+$(srcdir)/.deps/mpiutil.P
+SOURCES = $(mpi_SOURCES)
+OBJECTS = $(mpi_OBJECTS)
+
+default: all
+
+
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+ cd $(top_srcdir) && automake $(subdir)/Makefile
+
+Makefile: $(top_builddir)/config.status Makefile.in
+ cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+ rm -f $(noinst_LIBFILES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+ $(COMPILE) $<
+
+mostlyclean-compile:
+ rm -f *.o core
+
+clean-compile:
+
+distclean-compile:
+ rm -f *.tab.c
+
+maintainer-clean-compile:
+$(mpi_OBJECTS): ../config.h
+
+libmpi.a: $(mpi_OBJECTS) $(mpi_LIBADD)
+ rm -f libmpi.a
+ $(AR) cru libmpi.a $(mpi_OBJECTS) $(mpi_LIBADD)
+ $(RANLIB) libmpi.a
+
+ID: $(HEADERS) $(SOURCES)
+ here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
+
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
+ here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ rm -f TAGS ID
+
+maintainer-clean-tags:
+
+subdir = mpi
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+distdir: $(DEP_DISTFILES)
+ @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \
+ test -f $(distdir)/$$file \
+ || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $(srcdir)/$$file $(distdir)/$$file; \
+ done
+
+# This fragment is probably only useful for maintainers. It relies on
+# GNU make and gcc. It is only included in the generated Makefile.in
+# if `automake' is not passed the `--include-deps' flag.
+
+MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+-include $(srcdir)/.deps/.P
+$(srcdir)/.deps/.P: $(BUILT_SOURCES)
+ cd $(srcdir) && test -d .deps || mkdir .deps
+ echo > $@
+
+-include $(DEP_FILES)
+$(DEP_FILES): $(srcdir)/.deps/.P
+
+$(srcdir)/.deps/%.P: $(srcdir)/%.c
+ @echo "mkdeps $< > $@"
+ @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \
+ $(MKDEP) $< | sed "$$re" > $@-tmp
+ @if test -n "$o"; then \
+ sed 's/\.o:/$$o:/' $@-tmp > $@; \
+ rm $@-tmp; \
+ else \
+ mv $@-tmp $@; \
+ fi
+
+# End of maintainer-only section
+info:
+
+dvi:
+
+check: all
+
+installcheck:
+
+install-exec:
+
+install-data:
+
+install: install-exec install-data all
+ @:
+
+uninstall:
+
+all: $(LIBFILES) Makefile
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
+installdirs:
+
+
+mostlyclean-generic:
+ test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ rm -f Makefile $(DISTCLEANFILES)
+ rm -f config.cache config.log $(CONFIG_HEADER) stamp-h
+
+maintainer-clean-generic:
+ test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+ mostlyclean
+
+distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \
+ distclean-generic clean
+ rm -f config.status
+
+maintainer-clean: maintainer-clean-noinstLIBRARIES \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info dvi check installcheck \
+install-exec install-data install uninstall all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/mpi/longlong.h b/mpi/longlong.h
new file mode 100644
index 000000000..006f69edd
--- /dev/null
+++ b/mpi/longlong.h
@@ -0,0 +1,1398 @@
+/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
+
+Copyright (C) 1991, 1992, 1993, 1994, 1996 Free Software Foundation, Inc.
+
+This file is free software; you can redistribute it and/or modify
+it under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+This file 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 Library General Public
+License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this file; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+MA 02111-1307, USA. */
+
+/* You have to define the following before including this file:
+
+ UWtype -- An unsigned type, default type for operations (typically a "word")
+ UHWtype -- An unsigned type, at least half the size of UWtype.
+ UDWtype -- An unsigned type, at least twice as large a UWtype
+ W_TYPE_SIZE -- size in bits of UWtype
+
+ SItype, USItype -- Signed and unsigned 32 bit types.
+ DItype, UDItype -- Signed and unsigned 64 bit types.
+
+ On a 32 bit machine UWtype should typically be USItype;
+ on a 64 bit machine, UWtype should typically be UDItype.
+*/
+
+#define __BITS4 (W_TYPE_SIZE / 4)
+#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
+#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
+
+/* This is used to make sure no undesirable sharing between different libraries
+ that use this file takes place. */
+#ifndef __MPN
+#define __MPN(x) __##x
+#endif
+
+/* Define auxiliary asm macros.
+
+ 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two
+ UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype
+ word product in HIGH_PROD and LOW_PROD.
+
+ 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a
+ UDWtype product. This is just a variant of umul_ppmm.
+
+ 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+ denominator) divides a UDWtype, composed by the UWtype integers
+ HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
+ in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less
+ than DENOMINATOR for correct operation. If, in addition, the most
+ significant bit of DENOMINATOR must be 1, then the pre-processor symbol
+ UDIV_NEEDS_NORMALIZATION is defined to 1.
+
+ 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+ denominator). Like udiv_qrnnd but the numbers are signed. The quotient
+ is rounded towards 0.
+
+ 5) count_leading_zeros(count, x) counts the number of zero-bits from the
+ msb to the first non-zero bit in the UWtype X. This is the number of
+ steps X needs to be shifted left to set the msb. Undefined for X == 0,
+ unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value.
+
+ 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts
+ from the least significant end.
+
+ 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
+ high_addend_2, low_addend_2) adds two UWtype integers, composed by
+ HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
+ respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow
+ (i.e. carry out) is not stored anywhere, and is lost.
+
+ 8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
+ high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
+ composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
+ LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE
+ and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere,
+ and is lost.
+
+ If any of these macros are left undefined for a particular CPU,
+ C macros are used. */
+
+/* The CPUs come in alphabetical order below.
+
+ Please add support for more CPUs here, or improve the current support
+ for the CPUs below! */
+
+#if defined (__GNUC__) && !defined (NO_ASM)
+
+/* We sometimes need to clobber "cc" with gcc2, but that would not be
+ understood by gcc1. Use cpp to avoid major code duplication. */
+#if __GNUC__ < 2
+#define __CLOBBER_CC
+#define __AND_CLOBBER_CC
+#else /* __GNUC__ >= 2 */
+#define __CLOBBER_CC : "cc"
+#define __AND_CLOBBER_CC , "cc"
+#endif /* __GNUC__ < 2 */
+
+#if (defined (__a29k__) || defined (_AM29K)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("add %1,%4,%5
+ addc %0,%2,%3" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%r" ((USItype)(ah)), \
+ "rI" ((USItype)(bh)), \
+ "%r" ((USItype)(al)), \
+ "rI" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub %1,%4,%5
+ subc %0,%2,%3" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "r" ((USItype)(ah)), \
+ "rI" ((USItype)(bh)), \
+ "r" ((USItype)(al)), \
+ "rI" ((USItype)(bl)))
+#define umul_ppmm(xh, xl, m0, m1) \
+ do { \
+ USItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("multiplu %0,%1,%2" \
+ : "=r" ((USItype)(xl)) \
+ : "r" (__m0), \
+ "r" (__m1)); \
+ __asm__ ("multmu %0,%1,%2" \
+ : "=r" ((USItype)(xh)) \
+ : "r" (__m0), \
+ "r" (__m1)); \
+ } while (0)
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ __asm__ ("dividu %0,%3,%4" \
+ : "=r" ((USItype)(q)), \
+ "=q" ((USItype)(r)) \
+ : "1" ((USItype)(n1)), \
+ "r" ((USItype)(n0)), \
+ "r" ((USItype)(d)))
+#define count_leading_zeros(count, x) \
+ __asm__ ("clz %0,%1" \
+ : "=r" ((USItype)(count)) \
+ : "r" ((USItype)(x)))
+#define COUNT_LEADING_ZEROS_0 32
+#endif /* __a29k__ */
+
+#if defined (__alpha) && W_TYPE_SIZE == 64
+#define umul_ppmm(ph, pl, m0, m1) \
+ do { \
+ UDItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("umulh %r1,%2,%0" \
+ : "=r" ((UDItype) ph) \
+ : "%rJ" (__m0), \
+ "rI" (__m1)); \
+ (pl) = __m0 * __m1; \
+ } while (0)
+#define UMUL_TIME 46
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ do { UDItype __r; \
+ (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \
+ (r) = __r; \
+ } while (0)
+extern UDItype __udiv_qrnnd ();
+#define UDIV_TIME 220
+#endif /* LONGLONG_STANDALONE */
+#endif /* __alpha */
+
+#if defined (__arm__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("adds %1, %4, %5
+ adc %0, %2, %3" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%r" ((USItype)(ah)), \
+ "rI" ((USItype)(bh)), \
+ "%r" ((USItype)(al)), \
+ "rI" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subs %1, %4, %5
+ sbc %0, %2, %3" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "r" ((USItype)(ah)), \
+ "rI" ((USItype)(bh)), \
+ "r" ((USItype)(al)), \
+ "rI" ((USItype)(bl)))
+#define umul_ppmm(xh, xl, a, b) \
+ __asm__ ("%@ Inlined umul_ppmm
+ mov %|r0, %2, lsr #16
+ mov %|r2, %3, lsr #16
+ bic %|r1, %2, %|r0, lsl #16
+ bic %|r2, %3, %|r2, lsl #16
+ mul %1, %|r1, %|r2
+ mul %|r2, %|r0, %|r2
+ mul %|r1, %0, %|r1
+ mul %0, %|r0, %0
+ adds %|r1, %|r2, %|r1
+ addcs %0, %0, #65536
+ adds %1, %1, %|r1, lsl #16
+ adc %0, %0, %|r1, lsr #16" \
+ : "=&r" ((USItype)(xh)), \
+ "=r" ((USItype)(xl)) \
+ : "r" ((USItype)(a)), \
+ "r" ((USItype)(b)) \
+ : "r0", "r1", "r2")
+#define UMUL_TIME 20
+#define UDIV_TIME 100
+#endif /* __arm__ */
+
+#if defined (__clipper__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+ ({union {UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __xx; \
+ __asm__ ("mulwux %2,%0" \
+ : "=r" (__xx.__ll) \
+ : "%0" ((USItype)(u)), \
+ "r" ((USItype)(v))); \
+ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
+#define smul_ppmm(w1, w0, u, v) \
+ ({union {DItype __ll; \
+ struct {SItype __l, __h;} __i; \
+ } __xx; \
+ __asm__ ("mulwx %2,%0" \
+ : "=r" (__xx.__ll) \
+ : "%0" ((SItype)(u)), \
+ "r" ((SItype)(v))); \
+ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
+#define __umulsidi3(u, v) \
+ ({UDItype __w; \
+ __asm__ ("mulwux %2,%0" \
+ : "=r" (__w) \
+ : "%0" ((USItype)(u)), \
+ "r" ((USItype)(v))); \
+ __w; })
+#endif /* __clipper__ */
+
+#if defined (__gmicro__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("add.w %5,%1
+ addx %3,%0" \
+ : "=g" ((USItype)(sh)), \
+ "=&g" ((USItype)(sl)) \
+ : "%0" ((USItype)(ah)), \
+ "g" ((USItype)(bh)), \
+ "%1" ((USItype)(al)), \
+ "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub.w %5,%1
+ subx %3,%0" \
+ : "=g" ((USItype)(sh)), \
+ "=&g" ((USItype)(sl)) \
+ : "0" ((USItype)(ah)), \
+ "g" ((USItype)(bh)), \
+ "1" ((USItype)(al)), \
+ "g" ((USItype)(bl)))
+#define umul_ppmm(ph, pl, m0, m1) \
+ __asm__ ("mulx %3,%0,%1" \
+ : "=g" ((USItype)(ph)), \
+ "=r" ((USItype)(pl)) \
+ : "%0" ((USItype)(m0)), \
+ "g" ((USItype)(m1)))
+#define udiv_qrnnd(q, r, nh, nl, d) \
+ __asm__ ("divx %4,%0,%1" \
+ : "=g" ((USItype)(q)), \
+ "=r" ((USItype)(r)) \
+ : "1" ((USItype)(nh)), \
+ "0" ((USItype)(nl)), \
+ "g" ((USItype)(d)))
+#define count_leading_zeros(count, x) \
+ __asm__ ("bsch/1 %1,%0" \
+ : "=g" (count) \
+ : "g" ((USItype)(x)), \
+ "0" ((USItype)0))
+#endif
+
+#if defined (__hppa) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("add %4,%5,%1
+ addc %2,%3,%0" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%rM" ((USItype)(ah)), \
+ "rM" ((USItype)(bh)), \
+ "%rM" ((USItype)(al)), \
+ "rM" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub %4,%5,%1
+ subb %2,%3,%0" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "rM" ((USItype)(ah)), \
+ "rM" ((USItype)(bh)), \
+ "rM" ((USItype)(al)), \
+ "rM" ((USItype)(bl)))
+#if defined (_PA_RISC1_1)
+#define umul_ppmm(wh, wl, u, v) \
+ do { \
+ union {UDItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __xx; \
+ __asm__ ("xmpyu %1,%2,%0" \
+ : "=*f" (__xx.__ll) \
+ : "*f" ((USItype)(u)), \
+ "*f" ((USItype)(v))); \
+ (wh) = __xx.__i.__h; \
+ (wl) = __xx.__i.__l; \
+ } while (0)
+#define UMUL_TIME 8
+#define UDIV_TIME 60
+#else
+#define UMUL_TIME 40
+#define UDIV_TIME 80
+#endif
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ do { USItype __r; \
+ (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \
+ (r) = __r; \
+ } while (0)
+extern USItype __udiv_qrnnd ();
+#endif /* LONGLONG_STANDALONE */
+#define count_leading_zeros(count, x) \
+ do { \
+ USItype __tmp; \
+ __asm__ ( \
+ "ldi 1,%0
+ extru,= %1,15,16,%%r0 ; Bits 31..16 zero?
+ extru,tr %1,15,16,%1 ; No. Shift down, skip add.
+ ldo 16(%0),%0 ; Yes. Perform add.
+ extru,= %1,23,8,%%r0 ; Bits 15..8 zero?
+ extru,tr %1,23,8,%1 ; No. Shift down, skip add.
+ ldo 8(%0),%0 ; Yes. Perform add.
+ extru,= %1,27,4,%%r0 ; Bits 7..4 zero?
+ extru,tr %1,27,4,%1 ; No. Shift down, skip add.
+ ldo 4(%0),%0 ; Yes. Perform add.
+ extru,= %1,29,2,%%r0 ; Bits 3..2 zero?
+ extru,tr %1,29,2,%1 ; No. Shift down, skip add.
+ ldo 2(%0),%0 ; Yes. Perform add.
+ extru %1,30,1,%1 ; Extract bit 1.
+ sub %0,%1,%0 ; Subtract it.
+ " : "=r" (count), "=r" (__tmp) : "1" (x)); \
+ } while (0)
+#endif /* hppa */
+
+#if (defined (__i370__) || defined (__mvs__)) && W_TYPE_SIZE == 32
+#define umul_ppmm(xh, xl, m0, m1) \
+ do { \
+ union {UDItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __xx; \
+ USItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mr %0,%3" \
+ : "=r" (__xx.__i.__h), \
+ "=r" (__xx.__i.__l) \
+ : "%1" (__m0), \
+ "r" (__m1)); \
+ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+ (xh) += ((((SItype) __m0 >> 31) & __m1) \
+ + (((SItype) __m1 >> 31) & __m0)); \
+ } while (0)
+#define smul_ppmm(xh, xl, m0, m1) \
+ do { \
+ union {DItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __xx; \
+ __asm__ ("mr %0,%3" \
+ : "=r" (__xx.__i.__h), \
+ "=r" (__xx.__i.__l) \
+ : "%1" (m0), \
+ "r" (m1)); \
+ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+ } while (0)
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+ do { \
+ union {DItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __xx; \
+ __xx.__i.__h = n1; __xx.__i.__l = n0; \
+ __asm__ ("dr %0,%2" \
+ : "=r" (__xx.__ll) \
+ : "0" (__xx.__ll), "r" (d)); \
+ (q) = __xx.__i.__l; (r) = __xx.__i.__h; \
+ } while (0)
+#endif
+
+#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("addl %5,%1
+ adcl %3,%0" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%0" ((USItype)(ah)), \
+ "g" ((USItype)(bh)), \
+ "%1" ((USItype)(al)), \
+ "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subl %5,%1
+ sbbl %3,%0" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "0" ((USItype)(ah)), \
+ "g" ((USItype)(bh)), \
+ "1" ((USItype)(al)), \
+ "g" ((USItype)(bl)))
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("mull %3" \
+ : "=a" ((USItype)(w0)), \
+ "=d" ((USItype)(w1)) \
+ : "%0" ((USItype)(u)), \
+ "rm" ((USItype)(v)))
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ __asm__ ("divl %4" \
+ : "=a" ((USItype)(q)), \
+ "=d" ((USItype)(r)) \
+ : "0" ((USItype)(n0)), \
+ "1" ((USItype)(n1)), \
+ "rm" ((USItype)(d)))
+#define count_leading_zeros(count, x) \
+ do { \
+ USItype __cbtmp; \
+ __asm__ ("bsrl %1,%0" \
+ : "=r" (__cbtmp) : "rm" ((USItype)(x))); \
+ (count) = __cbtmp ^ 31; \
+ } while (0)
+#define count_trailing_zeros(count, x) \
+ __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x)))
+#ifndef UMUL_TIME
+#define UMUL_TIME 40
+#endif
+#ifndef UDIV_TIME
+#define UDIV_TIME 40
+#endif
+#endif /* 80x86 */
+
+#if defined (__i860__) && W_TYPE_SIZE == 32
+#define rshift_rhlc(r,h,l,c) \
+ __asm__ ("shr %3,r0,r0\;shrd %1,%2,%0" \
+ "=r" (r) : "r" (h), "r" (l), "rn" (c))
+#endif /* i860 */
+
+#if defined (__i960__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("cmpo 1,0\;addc %5,%4,%1\;addc %3,%2,%0" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%dI" ((USItype)(ah)), \
+ "dI" ((USItype)(bh)), \
+ "%dI" ((USItype)(al)), \
+ "dI" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("cmpo 0,0\;subc %5,%4,%1\;subc %3,%2,%0" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "dI" ((USItype)(ah)), \
+ "dI" ((USItype)(bh)), \
+ "dI" ((USItype)(al)), \
+ "dI" ((USItype)(bl)))
+#define umul_ppmm(w1, w0, u, v) \
+ ({union {UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __xx; \
+ __asm__ ("emul %2,%1,%0" \
+ : "=d" (__xx.__ll) \
+ : "%dI" ((USItype)(u)), \
+ "dI" ((USItype)(v))); \
+ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
+#define __umulsidi3(u, v) \
+ ({UDItype __w; \
+ __asm__ ("emul %2,%1,%0" \
+ : "=d" (__w) \
+ : "%dI" ((USItype)(u)), \
+ "dI" ((USItype)(v))); \
+ __w; })
+#define udiv_qrnnd(q, r, nh, nl, d) \
+ do { \
+ union {UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __nn; \
+ __nn.__i.__h = (nh); __nn.__i.__l = (nl); \
+ __asm__ ("ediv %d,%n,%0" \
+ : "=d" (__rq.__ll) \
+ : "dI" (__nn.__ll), \
+ "dI" ((USItype)(d))); \
+ (r) = __rq.__i.__l; (q) = __rq.__i.__h; \
+ } while (0)
+#define count_leading_zeros(count, x) \
+ do { \
+ USItype __cbtmp; \
+ __asm__ ("scanbit %1,%0" \
+ : "=r" (__cbtmp) \
+ : "r" ((USItype)(x))); \
+ (count) = __cbtmp ^ 31; \
+ } while (0)
+#define COUNT_LEADING_ZEROS_0 (-32) /* sic */
+#if defined (__i960mx) /* what is the proper symbol to test??? */
+#define rshift_rhlc(r,h,l,c) \
+ do { \
+ union {UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __nn; \
+ __nn.__i.__h = (h); __nn.__i.__l = (l); \
+ __asm__ ("shre %2,%1,%0" \
+ : "=d" (r) : "dI" (__nn.__ll), "dI" (c)); \
+ }
+#endif /* i960mx */
+#endif /* i960 */
+
+#if (defined (__mc68000__) || defined (__mc68020__) || defined (__NeXT__) || defined(mc68020)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("add%.l %5,%1
+ addx%.l %3,%0" \
+ : "=d" ((USItype)(sh)), \
+ "=&d" ((USItype)(sl)) \
+ : "%0" ((USItype)(ah)), \
+ "d" ((USItype)(bh)), \
+ "%1" ((USItype)(al)), \
+ "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub%.l %5,%1
+ subx%.l %3,%0" \
+ : "=d" ((USItype)(sh)), \
+ "=&d" ((USItype)(sl)) \
+ : "0" ((USItype)(ah)), \
+ "d" ((USItype)(bh)), \
+ "1" ((USItype)(al)), \
+ "g" ((USItype)(bl)))
+#if (defined (__mc68020__) || defined (__NeXT__) || defined(mc68020))
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("mulu%.l %3,%1:%0" \
+ : "=d" ((USItype)(w0)), \
+ "=d" ((USItype)(w1)) \
+ : "%0" ((USItype)(u)), \
+ "dmi" ((USItype)(v)))
+#define UMUL_TIME 45
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ __asm__ ("divu%.l %4,%1:%0" \
+ : "=d" ((USItype)(q)), \
+ "=d" ((USItype)(r)) \
+ : "0" ((USItype)(n0)), \
+ "1" ((USItype)(n1)), \
+ "dmi" ((USItype)(d)))
+#define UDIV_TIME 90
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+ __asm__ ("divs%.l %4,%1:%0" \
+ : "=d" ((USItype)(q)), \
+ "=d" ((USItype)(r)) \
+ : "0" ((USItype)(n0)), \
+ "1" ((USItype)(n1)), \
+ "dmi" ((USItype)(d)))
+#define count_leading_zeros(count, x) \
+ __asm__ ("bfffo %1{%b2:%b2},%0" \
+ : "=d" ((USItype)(count)) \
+ : "od" ((USItype)(x)), "n" (0))
+#define COUNT_LEADING_ZEROS_0 32
+#else /* not mc68020 */
+#define umul_ppmm(xh, xl, a, b) \
+ do { USItype __umul_tmp1, __umul_tmp2; \
+ __asm__ ("| Inlined umul_ppmm
+ move%.l %5,%3
+ move%.l %2,%0
+ move%.w %3,%1
+ swap %3
+ swap %0
+ mulu %2,%1
+ mulu %3,%0
+ mulu %2,%3
+ swap %2
+ mulu %5,%2
+ add%.l %3,%2
+ jcc 1f
+ add%.l %#0x10000,%0
+1: move%.l %2,%3
+ clr%.w %2
+ swap %2
+ swap %3
+ clr%.w %3
+ add%.l %3,%1
+ addx%.l %2,%0
+ | End inlined umul_ppmm" \
+ : "=&d" ((USItype)(xh)), "=&d" ((USItype)(xl)), \
+ "=d" (__umul_tmp1), "=&d" (__umul_tmp2) \
+ : "%2" ((USItype)(a)), "d" ((USItype)(b))); \
+ } while (0)
+#define UMUL_TIME 100
+#define UDIV_TIME 400
+#endif /* not mc68020 */
+#endif /* mc68000 */
+
+#if defined (__m88000__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("addu.co %1,%r4,%r5
+ addu.ci %0,%r2,%r3" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%rJ" ((USItype)(ah)), \
+ "rJ" ((USItype)(bh)), \
+ "%rJ" ((USItype)(al)), \
+ "rJ" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subu.co %1,%r4,%r5
+ subu.ci %0,%r2,%r3" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "rJ" ((USItype)(ah)), \
+ "rJ" ((USItype)(bh)), \
+ "rJ" ((USItype)(al)), \
+ "rJ" ((USItype)(bl)))
+#define count_leading_zeros(count, x) \
+ do { \
+ USItype __cbtmp; \
+ __asm__ ("ff1 %0,%1" \
+ : "=r" (__cbtmp) \
+ : "r" ((USItype)(x))); \
+ (count) = __cbtmp ^ 31; \
+ } while (0)
+#define COUNT_LEADING_ZEROS_0 63 /* sic */
+#if defined (__m88110__)
+#define umul_ppmm(wh, wl, u, v) \
+ do { \
+ union {UDItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __x; \
+ __asm__ ("mulu.d %0,%1,%2" : "=r" (__x.__ll) : "r" (u), "r" (v)); \
+ (wh) = __x.__i.__h; \
+ (wl) = __x.__i.__l; \
+ } while (0)
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ ({union {UDItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __x, __q; \
+ __x.__i.__h = (n1); __x.__i.__l = (n0); \
+ __asm__ ("divu.d %0,%1,%2" \
+ : "=r" (__q.__ll) : "r" (__x.__ll), "r" (d)); \
+ (r) = (n0) - __q.__l * (d); (q) = __q.__l; })
+#define UMUL_TIME 5
+#define UDIV_TIME 25
+#else
+#define UMUL_TIME 17
+#define UDIV_TIME 150
+#endif /* __m88110__ */
+#endif /* __m88000__ */
+
+#if defined (__mips__) && W_TYPE_SIZE == 32
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("multu %2,%3" \
+ : "=l" ((USItype)(w0)), \
+ "=h" ((USItype)(w1)) \
+ : "d" ((USItype)(u)), \
+ "d" ((USItype)(v)))
+#else
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("multu %2,%3
+ mflo %0
+ mfhi %1" \
+ : "=d" ((USItype)(w0)), \
+ "=d" ((USItype)(w1)) \
+ : "d" ((USItype)(u)), \
+ "d" ((USItype)(v)))
+#endif
+#define UMUL_TIME 10
+#define UDIV_TIME 100
+#endif /* __mips__ */
+
+#if (defined (__mips) && __mips >= 3) && W_TYPE_SIZE == 64
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("dmultu %2,%3" \
+ : "=l" ((UDItype)(w0)), \
+ "=h" ((UDItype)(w1)) \
+ : "d" ((UDItype)(u)), \
+ "d" ((UDItype)(v)))
+#else
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("dmultu %2,%3
+ mflo %0
+ mfhi %1" \
+ : "=d" ((UDItype)(w0)), \
+ "=d" ((UDItype)(w1)) \
+ : "d" ((UDItype)(u)), \
+ "d" ((UDItype)(v)))
+#endif
+#define UMUL_TIME 20
+#define UDIV_TIME 140
+#endif /* __mips__ */
+
+#if defined (__ns32000__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+ ({union {UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __xx; \
+ __asm__ ("meid %2,%0" \
+ : "=g" (__xx.__ll) \
+ : "%0" ((USItype)(u)), \
+ "g" ((USItype)(v))); \
+ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
+#define __umulsidi3(u, v) \
+ ({UDItype __w; \
+ __asm__ ("meid %2,%0" \
+ : "=g" (__w) \
+ : "%0" ((USItype)(u)), \
+ "g" ((USItype)(v))); \
+ __w; })
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ ({union {UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __xx; \
+ __xx.__i.__h = (n1); __xx.__i.__l = (n0); \
+ __asm__ ("deid %2,%0" \
+ : "=g" (__xx.__ll) \
+ : "0" (__xx.__ll), \
+ "g" ((USItype)(d))); \
+ (r) = __xx.__i.__l; (q) = __xx.__i.__h; })
+#define count_trailing_zeros(count,x) \
+ do {
+ __asm__ ("ffsd %2,%0" \
+ : "=r" ((USItype) (count)) \
+ : "0" ((USItype) 0), \
+ "r" ((USItype) (x))); \
+ } while (0)
+#endif /* __ns32000__ */
+
+#if (defined (_ARCH_PPC) || defined (_IBMR2)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ do { \
+ if (__builtin_constant_p (bh) && (bh) == 0) \
+ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%r" ((USItype)(ah)), \
+ "%r" ((USItype)(al)), \
+ "rI" ((USItype)(bl))); \
+ else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \
+ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%r" ((USItype)(ah)), \
+ "%r" ((USItype)(al)), \
+ "rI" ((USItype)(bl))); \
+ else \
+ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%r" ((USItype)(ah)), \
+ "r" ((USItype)(bh)), \
+ "%r" ((USItype)(al)), \
+ "rI" ((USItype)(bl))); \
+ } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ do { \
+ if (__builtin_constant_p (ah) && (ah) == 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "r" ((USItype)(bh)), \
+ "rI" ((USItype)(al)), \
+ "r" ((USItype)(bl))); \
+ else if (__builtin_constant_p (ah) && (ah) ==~(USItype) 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "r" ((USItype)(bh)), \
+ "rI" ((USItype)(al)), \
+ "r" ((USItype)(bl))); \
+ else if (__builtin_constant_p (bh) && (bh) == 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "r" ((USItype)(ah)), \
+ "rI" ((USItype)(al)), \
+ "r" ((USItype)(bl))); \
+ else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \
+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "r" ((USItype)(ah)), \
+ "rI" ((USItype)(al)), \
+ "r" ((USItype)(bl))); \
+ else \
+ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "r" ((USItype)(ah)), \
+ "r" ((USItype)(bh)), \
+ "rI" ((USItype)(al)), \
+ "r" ((USItype)(bl))); \
+ } while (0)
+#define count_leading_zeros(count, x) \
+ __asm__ ("{cntlz|cntlzw} %0,%1" \
+ : "=r" ((USItype)(count)) \
+ : "r" ((USItype)(x)))
+#define COUNT_LEADING_ZEROS_0 32
+#if defined (_ARCH_PPC)
+#define umul_ppmm(ph, pl, m0, m1) \
+ do { \
+ USItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mulhwu %0,%1,%2" \
+ : "=r" ((USItype) ph) \
+ : "%r" (__m0), \
+ "r" (__m1)); \
+ (pl) = __m0 * __m1; \
+ } while (0)
+#define UMUL_TIME 15
+#define smul_ppmm(ph, pl, m0, m1) \
+ do { \
+ SItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mulhw %0,%1,%2" \
+ : "=r" ((SItype) ph) \
+ : "%r" (__m0), \
+ "r" (__m1)); \
+ (pl) = __m0 * __m1; \
+ } while (0)
+#define SMUL_TIME 14
+#define UDIV_TIME 120
+#else
+#define umul_ppmm(xh, xl, m0, m1) \
+ do { \
+ USItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mul %0,%2,%3" \
+ : "=r" ((USItype)(xh)), \
+ "=q" ((USItype)(xl)) \
+ : "r" (__m0), \
+ "r" (__m1)); \
+ (xh) += ((((SItype) __m0 >> 31) & __m1) \
+ + (((SItype) __m1 >> 31) & __m0)); \
+ } while (0)
+#define UMUL_TIME 8
+#define smul_ppmm(xh, xl, m0, m1) \
+ __asm__ ("mul %0,%2,%3" \
+ : "=r" ((SItype)(xh)), \
+ "=q" ((SItype)(xl)) \
+ : "r" (m0), \
+ "r" (m1))
+#define SMUL_TIME 4
+#define sdiv_qrnnd(q, r, nh, nl, d) \
+ __asm__ ("div %0,%2,%4" \
+ : "=r" ((SItype)(q)), "=q" ((SItype)(r)) \
+ : "r" ((SItype)(nh)), "1" ((SItype)(nl)), "r" ((SItype)(d)))
+#define UDIV_TIME 100
+#endif
+#endif /* Power architecture variants. */
+
+#if defined (__pyr__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("addw %5,%1
+ addwc %3,%0" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%0" ((USItype)(ah)), \
+ "g" ((USItype)(bh)), \
+ "%1" ((USItype)(al)), \
+ "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subw %5,%1
+ subwb %3,%0" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "0" ((USItype)(ah)), \
+ "g" ((USItype)(bh)), \
+ "1" ((USItype)(al)), \
+ "g" ((USItype)(bl)))
+/* This insn works on Pyramids with AP, XP, or MI CPUs, but not with SP. */
+#define umul_ppmm(w1, w0, u, v) \
+ ({union {UDItype __ll; \
+ struct {USItype __h, __l;} __i; \
+ } __xx; \
+ __asm__ ("movw %1,%R0
+ uemul %2,%0" \
+ : "=&r" (__xx.__ll) \
+ : "g" ((USItype) (u)), \
+ "g" ((USItype)(v))); \
+ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
+#endif /* __pyr__ */
+
+#if defined (__ibm032__) /* RT/ROMP */ && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("a %1,%5
+ ae %0,%3" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%0" ((USItype)(ah)), \
+ "r" ((USItype)(bh)), \
+ "%1" ((USItype)(al)), \
+ "r" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("s %1,%5
+ se %0,%3" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "0" ((USItype)(ah)), \
+ "r" ((USItype)(bh)), \
+ "1" ((USItype)(al)), \
+ "r" ((USItype)(bl)))
+#define umul_ppmm(ph, pl, m0, m1) \
+ do { \
+ USItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ( \
+ "s r2,r2
+ mts r10,%2
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ m r2,%3
+ cas %0,r2,r0
+ mfs r10,%1" \
+ : "=r" ((USItype)(ph)), \
+ "=r" ((USItype)(pl)) \
+ : "%r" (__m0), \
+ "r" (__m1) \
+ : "r2"); \
+ (ph) += ((((SItype) __m0 >> 31) & __m1) \
+ + (((SItype) __m1 >> 31) & __m0)); \
+ } while (0)
+#define UMUL_TIME 20
+#define UDIV_TIME 200
+#define count_leading_zeros(count, x) \
+ do { \
+ if ((x) >= 0x10000) \
+ __asm__ ("clz %0,%1" \
+ : "=r" ((USItype)(count)) \
+ : "r" ((USItype)(x) >> 16)); \
+ else \
+ { \
+ __asm__ ("clz %0,%1" \
+ : "=r" ((USItype)(count)) \
+ : "r" ((USItype)(x))); \
+ (count) += 16; \
+ } \
+ } while (0)
+#endif /* RT/ROMP */
+
+#if defined (__sh2__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ( \
+ "dmulu.l %2,%3
+ sts macl,%1
+ sts mach,%0" \
+ : "=r" ((USItype)(w1)), \
+ "=r" ((USItype)(w0)) \
+ : "r" ((USItype)(u)), \
+ "r" ((USItype)(v)) \
+ : "macl", "mach")
+#define UMUL_TIME 5
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("addcc %r4,%5,%1
+ addx %r2,%3,%0" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "%rJ" ((USItype)(ah)), \
+ "rI" ((USItype)(bh)), \
+ "%rJ" ((USItype)(al)), \
+ "rI" ((USItype)(bl)) \
+ __CLOBBER_CC)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subcc %r4,%5,%1
+ subx %r2,%3,%0" \
+ : "=r" ((USItype)(sh)), \
+ "=&r" ((USItype)(sl)) \
+ : "rJ" ((USItype)(ah)), \
+ "rI" ((USItype)(bh)), \
+ "rJ" ((USItype)(al)), \
+ "rI" ((USItype)(bl)) \
+ __CLOBBER_CC)
+#if defined (__sparc_v8__)
+/* Don't match immediate range because, 1) it is not often useful,
+ 2) the 'I' flag thinks of the range as a 13 bit signed interval,
+ while we want to match a 13 bit interval, sign extended to 32 bits,
+ but INTERPRETED AS UNSIGNED. */
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("umul %2,%3,%1;rd %%y,%0" \
+ : "=r" ((USItype)(w1)), \
+ "=r" ((USItype)(w0)) \
+ : "r" ((USItype)(u)), \
+ "r" ((USItype)(v)))
+#define UMUL_TIME 5
+#ifndef SUPERSPARC /* SuperSPARC's udiv only handles 53 bit dividends */
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ do { \
+ USItype __q; \
+ __asm__ ("mov %1,%%y;nop;nop;nop;udiv %2,%3,%0" \
+ : "=r" ((USItype)(__q)) \
+ : "r" ((USItype)(n1)), \
+ "r" ((USItype)(n0)), \
+ "r" ((USItype)(d))); \
+ (r) = (n0) - __q * (d); \
+ (q) = __q; \
+ } while (0)
+#define UDIV_TIME 25
+#endif /* SUPERSPARC */
+#else /* ! __sparc_v8__ */
+#if defined (__sparclite__)
+/* This has hardware multiply but not divide. It also has two additional
+ instructions scan (ffs from high bit) and divscc. */
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("umul %2,%3,%1;rd %%y,%0" \
+ : "=r" ((USItype)(w1)), \
+ "=r" ((USItype)(w0)) \
+ : "r" ((USItype)(u)), \
+ "r" ((USItype)(v)))
+#define UMUL_TIME 5
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ __asm__ ("! Inlined udiv_qrnnd
+ wr %%g0,%2,%%y ! Not a delayed write for sparclite
+ tst %%g0
+ divscc %3,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%%g1
+ divscc %%g1,%4,%0
+ rd %%y,%1
+ bl,a 1f
+ add %1,%4,%1
+1: ! End of inline udiv_qrnnd" \
+ : "=r" ((USItype)(q)), \
+ "=r" ((USItype)(r)) \
+ : "r" ((USItype)(n1)), \
+ "r" ((USItype)(n0)), \
+ "rI" ((USItype)(d)) \
+ : "%g1" __AND_CLOBBER_CC)
+#define UDIV_TIME 37
+#define count_leading_zeros(count, x) \
+ __asm__ ("scan %1,0,%0" \
+ : "=r" ((USItype)(x)) \
+ : "r" ((USItype)(count)))
+/* Early sparclites return 63 for an argument of 0, but they warn that future
+ implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0
+ undefined. */
+#endif /* __sparclite__ */
+#endif /* __sparc_v8__ */
+/* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd. */
+#ifndef umul_ppmm
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("! Inlined umul_ppmm
+ wr %%g0,%2,%%y ! SPARC has 0-3 delay insn after a wr
+ sra %3,31,%%g2 ! Don't move this insn
+ and %2,%%g2,%%g2 ! Don't move this insn
+ andcc %%g0,0,%%g1 ! Don't move this insn
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,%3,%%g1
+ mulscc %%g1,0,%%g1
+ add %%g1,%%g2,%0
+ rd %%y,%1" \
+ : "=r" ((USItype)(w1)), \
+ "=r" ((USItype)(w0)) \
+ : "%rI" ((USItype)(u)), \
+ "r" ((USItype)(v)) \
+ : "%g1", "%g2" __AND_CLOBBER_CC)
+#define UMUL_TIME 39 /* 39 instructions */
+#endif
+#ifndef udiv_qrnnd
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ do { USItype __r; \
+ (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \
+ (r) = __r; \
+ } while (0)
+extern USItype __udiv_qrnnd ();
+#define UDIV_TIME 140
+#endif /* LONGLONG_STANDALONE */
+#endif /* udiv_qrnnd */
+#endif /* __sparc__ */
+
+#if defined (__vax__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("addl2 %5,%1
+ adwc %3,%0" \
+ : "=g" ((USItype)(sh)), \
+ "=&g" ((USItype)(sl)) \
+ : "%0" ((USItype)(ah)), \
+ "g" ((USItype)(bh)), \
+ "%1" ((USItype)(al)), \
+ "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subl2 %5,%1
+ sbwc %3,%0" \
+ : "=g" ((USItype)(sh)), \
+ "=&g" ((USItype)(sl)) \
+ : "0" ((USItype)(ah)), \
+ "g" ((USItype)(bh)), \
+ "1" ((USItype)(al)), \
+ "g" ((USItype)(bl)))
+#define umul_ppmm(xh, xl, m0, m1) \
+ do { \
+ union {UDItype __ll; \
+ struct {USItype __l, __h;} __i; \
+ } __xx; \
+ USItype __m0 = (m0), __m1 = (m1); \
+ __asm__ ("emul %1,%2,$0,%0" \
+ : "=g" (__xx.__ll) \
+ : "g" (__m0), \
+ "g" (__m1)); \
+ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+ (xh) += ((((SItype) __m0 >> 31) & __m1) \
+ + (((SItype) __m1 >> 31) & __m0)); \
+ } while (0)
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+ do { \
+ union {DItype __ll; \
+ struct {SItype __l, __h;} __i; \
+ } __xx; \
+ __xx.__i.__h = n1; __xx.__i.__l = n0; \
+ __asm__ ("ediv %3,%2,%0,%1" \
+ : "=g" (q), "=g" (r) \
+ : "g" (__xx.__ll), "g" (d)); \
+ } while (0)
+#endif /* __vax__ */
+
+#if defined (__z8000__) && W_TYPE_SIZE == 16
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("add %H1,%H5\n\tadc %H0,%H3" \
+ : "=r" ((unsigned int)(sh)), \
+ "=&r" ((unsigned int)(sl)) \
+ : "%0" ((unsigned int)(ah)), \
+ "r" ((unsigned int)(bh)), \
+ "%1" ((unsigned int)(al)), \
+ "rQR" ((unsigned int)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub %H1,%H5\n\tsbc %H0,%H3" \
+ : "=r" ((unsigned int)(sh)), \
+ "=&r" ((unsigned int)(sl)) \
+ : "0" ((unsigned int)(ah)), \
+ "r" ((unsigned int)(bh)), \
+ "1" ((unsigned int)(al)), \
+ "rQR" ((unsigned int)(bl)))
+#define umul_ppmm(xh, xl, m0, m1) \
+ do { \
+ union {long int __ll; \
+ struct {unsigned int __h, __l;} __i; \
+ } __xx; \
+ unsigned int __m0 = (m0), __m1 = (m1); \
+ __asm__ ("mult %S0,%H3" \
+ : "=r" (__xx.__i.__h), \
+ "=r" (__xx.__i.__l) \
+ : "%1" (__m0), \
+ "rQR" (__m1)); \
+ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+ (xh) += ((((signed int) __m0 >> 15) & __m1) \
+ + (((signed int) __m1 >> 15) & __m0)); \
+ } while (0)
+#endif /* __z8000__ */
+
+#endif /* __GNUC__ */
+
+
+#if !defined (umul_ppmm) && defined (__umulsidi3)
+#define umul_ppmm(ph, pl, m0, m1) \
+ { \
+ UDWtype __ll = __umulsidi3 (m0, m1); \
+ ph = (UWtype) (__ll >> W_TYPE_SIZE); \
+ pl = (UWtype) __ll; \
+ }
+#endif
+
+#if !defined (__umulsidi3)
+#define __umulsidi3(u, v) \
+ ({UWtype __hi, __lo; \
+ umul_ppmm (__hi, __lo, u, v); \
+ ((UDWtype) __hi << W_TYPE_SIZE) | __lo; })
+#endif
+
+/* If this machine has no inline assembler, use C macros. */
+
+#if !defined (add_ssaaaa)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ do { \
+ UWtype __x; \
+ __x = (al) + (bl); \
+ (sh) = (ah) + (bh) + (__x < (al)); \
+ (sl) = __x; \
+ } while (0)
+#endif
+
+#if !defined (sub_ddmmss)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ do { \
+ UWtype __x; \
+ __x = (al) - (bl); \
+ (sh) = (ah) - (bh) - (__x > (al)); \
+ (sl) = __x; \
+ } while (0)
+#endif
+
+#if !defined (umul_ppmm)
+#define umul_ppmm(w1, w0, u, v) \
+ do { \
+ UWtype __x0, __x1, __x2, __x3; \
+ UHWtype __ul, __vl, __uh, __vh; \
+ UWtype __u = (u), __v = (v); \
+ \
+ __ul = __ll_lowpart (__u); \
+ __uh = __ll_highpart (__u); \
+ __vl = __ll_lowpart (__v); \
+ __vh = __ll_highpart (__v); \
+ \
+ __x0 = (UWtype) __ul * __vl; \
+ __x1 = (UWtype) __ul * __vh; \
+ __x2 = (UWtype) __uh * __vl; \
+ __x3 = (UWtype) __uh * __vh; \
+ \
+ __x1 += __ll_highpart (__x0);/* this can't give carry */ \
+ __x1 += __x2; /* but this indeed can */ \
+ if (__x1 < __x2) /* did we get it? */ \
+ __x3 += __ll_B; /* yes, add it in the proper pos. */ \
+ \
+ (w1) = __x3 + __ll_highpart (__x1); \
+ (w0) = (__ll_lowpart (__x1) << W_TYPE_SIZE/2) + __ll_lowpart (__x0);\
+ } while (0)
+#endif
+
+#if !defined (umul_ppmm)
+#define smul_ppmm(w1, w0, u, v) \
+ do { \
+ UWtype __w1; \
+ UWtype __m0 = (u), __m1 = (v); \
+ umul_ppmm (__w1, w0, __m0, __m1); \
+ (w1) = __w1 - (-(__m0 >> (W_TYPE_SIZE - 1)) & __m1) \
+ - (-(__m1 >> (W_TYPE_SIZE - 1)) & __m0); \
+ } while (0)
+#endif
+
+/* Define this unconditionally, so it can be used for debugging. */
+#define __udiv_qrnnd_c(q, r, n1, n0, d) \
+ do { \
+ UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \
+ __d1 = __ll_highpart (d); \
+ __d0 = __ll_lowpart (d); \
+ \
+ __r1 = (n1) % __d1; \
+ __q1 = (n1) / __d1; \
+ __m = (UWtype) __q1 * __d0; \
+ __r1 = __r1 * __ll_B | __ll_highpart (n0); \
+ if (__r1 < __m) \
+ { \
+ __q1--, __r1 += (d); \
+ if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
+ if (__r1 < __m) \
+ __q1--, __r1 += (d); \
+ } \
+ __r1 -= __m; \
+ \
+ __r0 = __r1 % __d1; \
+ __q0 = __r1 / __d1; \
+ __m = (UWtype) __q0 * __d0; \
+ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \
+ if (__r0 < __m) \
+ { \
+ __q0--, __r0 += (d); \
+ if (__r0 >= (d)) \
+ if (__r0 < __m) \
+ __q0--, __r0 += (d); \
+ } \
+ __r0 -= __m; \
+ \
+ (q) = (UWtype) __q1 * __ll_B | __q0; \
+ (r) = __r0; \
+ } while (0)
+
+/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through
+ __udiv_w_sdiv (defined in libgcc or elsewhere). */
+#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd)
+#define udiv_qrnnd(q, r, nh, nl, d) \
+ do { \
+ UWtype __r; \
+ (q) = __MPN(udiv_w_sdiv) (&__r, nh, nl, d); \
+ (r) = __r; \
+ } while (0)
+#endif
+
+/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */
+#if !defined (udiv_qrnnd)
+#define UDIV_NEEDS_NORMALIZATION 1
+#define udiv_qrnnd __udiv_qrnnd_c
+#endif
+
+#if !defined (count_leading_zeros)
+extern
+#ifdef __STDC__
+const
+#endif
+unsigned char __clz_tab[];
+#define count_leading_zeros(count, x) \
+ do { \
+ UWtype __xr = (x); \
+ UWtype __a; \
+ \
+ if (W_TYPE_SIZE <= 32) \
+ { \
+ __a = __xr < ((UWtype) 1 << 2*__BITS4) \
+ ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \
+ : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 : 3*__BITS4);\
+ } \
+ else \
+ { \
+ for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \
+ if (((__xr >> __a) & 0xff) != 0) \
+ break; \
+ } \
+ \
+ (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \
+ } while (0)
+/* This version gives a well-defined value for zero. */
+#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE
+#endif
+
+#if !defined (count_trailing_zeros)
+/* Define count_trailing_zeros using count_leading_zeros. The latter might be
+ defined in asm, but if it is not, the C version above is good enough. */
+#define count_trailing_zeros(count, x) \
+ do { \
+ UWtype __ctz_x = (x); \
+ UWtype __ctz_c; \
+ count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \
+ (count) = W_TYPE_SIZE - 1 - __ctz_c; \
+ } while (0)
+#endif
+
+#ifndef UDIV_NEEDS_NORMALIZATION
+#define UDIV_NEEDS_NORMALIZATION 0
+#endif
diff --git a/mpi/mpi-add.c b/mpi/mpi-add.c
new file mode 100644
index 000000000..047a2fa35
--- /dev/null
+++ b/mpi/mpi-add.c
@@ -0,0 +1,221 @@
+/* mpi-add.c - MPI functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mpi-internal.h"
+
+
+/****************
+ * Add the unsigned integer V to the mpi-integer U and store the
+ * result in W. U and V may be the same.
+ */
+void
+mpi_add_ui(MPI w, MPI u, unsigned long v )
+{
+ mpi_ptr_t wp, up;
+ mpi_size_t usize, wsize;
+ int usign, wsign;
+
+ usize = u->nlimbs;
+ usign = u->sign;
+ wsign = 0;
+
+ /* If not space for W (and possible carry), increase space. */
+ wsize = usize + 1;
+ if( w->alloced < wsize )
+ mpi_resize(w, wsize);
+
+ /* These must be after realloc (U may be the same as W). */
+ up = u->d;
+ wp = w->d;
+
+ if( !usize ) { /* simple */
+ wp[0] = v;
+ wsize = v? 1:0;
+ }
+ else if( !usign ) { /* mpi is not negative */
+ mpi_limb_t cy;
+ cy = mpihelp_add_1(wp, up, usize, v);
+ wp[usize] = cy;
+ wsize = usize + cy;
+ }
+ else { /* The signs are different. Need exact comparison to determine
+ * which operand to subtract from which. */
+ if( usize == 1 && up[0] < v ) {
+ wp[0] = v - up[0];
+ wsize = 1;
+ }
+ else {
+ mpihelp_sub_1(wp, up, usize, v);
+ /* Size can decrease with at most one limb. */
+ wsize = (usize - (wp[usize-1]? 0:1));
+ wsign = 1;
+ }
+ }
+
+ w->nlimbs = wsize;
+ w->sign = wsign;
+}
+
+
+void
+mpi_add(MPI w, MPI u, MPI v)
+{
+ mpi_ptr_t wp, up, vp;
+ mpi_size_t usize, vsize, wsize;
+ int usign, vsign, wsign;
+
+ usize = u->nlimbs;
+ vsize = v->nlimbs;
+ usign = u->sign;
+ vsign = v->sign;
+
+ if( usize < vsize ) { /* Swap U and V. */
+ { MPI t; t = u; u = v; v = t; }
+ { mpi_size_t t = usize; usize = vsize; vsize = t; }
+ { int t = usign; usign = vsign; vsign = t; }
+ }
+
+ /* If not space for w (and possible carry), increase space. */
+ wsize = usize + 1;
+ if( w->alloced < wsize )
+ mpi_resize(w, wsize);
+ wsign = 0;
+
+ /* These must be after realloc (u or v may be the same as w). */
+ up = u->d;
+ vp = v->d;
+ wp = w->d;
+
+ if( !vsize ) { /* simple */
+ MPN_COPY(wp, up, usize );
+ wsize = usize;
+ wsign = usign;
+ }
+ else if( usign != vsign ) { /* different sign */
+ /* This test is right since USIZE >= VSIZE */
+ if( usize != vsize ) {
+ mpihelp_sub(wp, up, usize, vp, vsize);
+ wsize = usize;
+ MPN_NORMALIZE(wp, wsize);
+ wsign = usign;
+ }
+ else if( mpihelp_cmp(up, vp, usize) < 0 ) {
+ mpihelp_sub_n(wp, vp, up, usize);
+ wsize = usize;
+ MPN_NORMALIZE(wp, wsize);
+ if( !usign )
+ wsign = 1;
+ }
+ else {
+ mpihelp_sub_n(wp, up, vp, usize);
+ wsize = usize;
+ MPN_NORMALIZE(wp, wsize);
+ if( usign )
+ wsign = 1;
+ }
+ }
+ else { /* U and V have same sign. Add them. */
+ mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize);
+ wp[usize] = cy;
+ wsize = usize + cy;
+ if( usign )
+ wsize = 1;
+ }
+
+ w->nlimbs = wsize;
+ w->sign = wsign;
+}
+
+
+/****************
+ * Subtract the unsigned integer V from the mpi-integer U and store the
+ * result in W.
+ */
+void
+mpi_sub_ui(MPI w, MPI u, unsigned long v )
+{
+ mpi_ptr_t wp, up;
+ mpi_size_t usize, wsize;
+ int usign, wsign;
+
+ usize = u->nlimbs;
+ usign = u->sign;
+ wsign = 0;
+
+ /* If not space for W (and possible carry), increase space. */
+ wsize = usize + 1;
+ if( w->alloced < wsize )
+ mpi_resize(w, wsize);
+
+ /* These must be after realloc (U may be the same as W). */
+ up = u->d;
+ wp = w->d;
+
+ if( !usize ) { /* simple */
+ wp[0] = v;
+ wsize = v? 1:0;
+ wsign = 1;
+ }
+ else if( usign ) { /* mpi and v are negative */
+ mpi_limb_t cy;
+ cy = mpihelp_add_1(wp, up, usize, v);
+ wp[usize] = cy;
+ wsize = usize + cy;
+ }
+ else { /* The signs are different. Need exact comparison to determine
+ * which operand to subtract from which. */
+ if( usize == 1 && up[0] < v ) {
+ wp[0] = v - up[0];
+ wsize = 1;
+ wsign = 1;
+ }
+ else {
+ mpihelp_sub_1(wp, up, usize, v);
+ /* Size can decrease with at most one limb. */
+ wsize = (usize - (wp[usize-1]? 1:0));
+ }
+ }
+
+ w->nlimbs = wsize;
+ w->sign = wsign;
+}
+
+void
+mpi_sub(MPI w, MPI u, MPI v)
+{
+ if( w == v ) {
+ MPI vv = mpi_copy(v);
+ vv->sign = !vv->sign;
+ mpi_add( w, u, vv );
+ m_free(vv);
+ }
+ else {
+ /* fixme: this is not thread-save (we temp. modify v) */
+ v->sign = !v->sign;
+ mpi_add( w, u, v );
+ v->sign = !v->sign;
+ }
+}
+
+
diff --git a/mpi/mpi-bit.c b/mpi/mpi-bit.c
new file mode 100644
index 000000000..9cb346aa4
--- /dev/null
+++ b/mpi/mpi-bit.c
@@ -0,0 +1,133 @@
+/* mpi-bit.c - MPI bit level fucntions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "mpi-internal.h"
+
+
+/****************
+ * Return the number of bits in A.
+ * fixme: we should not count leading zero bits
+ */
+unsigned
+mpi_get_nbits( MPI a )
+{
+ return a->nlimbs * BITS_PER_MPI_LIMB;
+}
+
+
+/****************
+ * Test wether bit N is set.
+ */
+int
+mpi_test_bit( MPI a, unsigned n )
+{
+ unsigned limbno, bitno;
+ mpi_limb_t limb;
+
+ limbno = n / BITS_PER_MPI_LIMB;
+ bitno = n % BITS_PER_MPI_LIMB;
+
+ if( limbno >= a->nlimbs )
+ return 0; /* too far left: this is a 0 */
+ limb = a->d[limbno];
+ return (limb & (1 << bitno))? 1: 0;
+}
+
+
+/****************
+ * Set bit N of A.
+ */
+void
+mpi_set_bit( MPI a, unsigned n )
+{
+ unsigned limbno, bitno;
+
+ limbno = n / BITS_PER_MPI_LIMB;
+ bitno = n % BITS_PER_MPI_LIMB;
+
+ if( limbno >= a->nlimbs ) { /* resize */
+ if( a->alloced >= limbno )
+ mpi_resize(a, limbno+1 );
+ a->nlimbs = limbno+1;
+ }
+ a->d[limbno] |= (1<<bitno);
+}
+
+/****************
+ * Clear bit N of A.
+ */
+void
+mpi_clear_bit( MPI a, unsigned n )
+{
+ unsigned limbno, bitno;
+
+ limbno = n / BITS_PER_MPI_LIMB;
+ bitno = n % BITS_PER_MPI_LIMB;
+
+ if( limbno >= a->nlimbs )
+ return; /* don't need to clear this bit, it's to far to left */
+ a->d[limbno] &= ~(1 << bitno);
+}
+
+
+void
+mpi_set_bytes( MPI a, unsigned nbits, byte (*fnc)(int), int opaque )
+{
+ byte *p;
+ unsigned nlimbs, nlimbs2, xbits, xbytes;
+ unsigned n;
+ int i;
+
+ nlimbs = nbits / BITS_PER_MPI_LIMB;
+ xbits = nbits % BITS_PER_MPI_LIMB;
+ nlimbs2 = xbits? (nlimbs+1):nlimbs;
+ xbytes = xbits / 8;
+ xbits = xbits % 8;
+ if( a->alloced < nlimbs2 )
+ mpi_resize(a, nlimbs2 );
+ a->nlimbs = nlimbs2;
+ for(n=0; n < nlimbs; n++ ) {
+ p = (byte*)(a->d+n);
+ #ifdef HAVE_LITTLE_ENDIAN
+ for(i=0; i < BYTES_PER_MPI_LIMB; i++ )
+ p[i] = fnc(opaque);
+ #else
+ for(i=BYTES_PER_MPI_LIMB-1; i>=0; i-- )
+ p[i] = fnc(opaque);
+ #endif
+ }
+ if( xbytes ) {
+ p = (byte*)(a->d+n);
+ #ifdef HAVE_LITTLE_ENDIAN
+ for(i=0; i < xbytes; i++ )
+ p[i] = fnc(opaque);
+ #else
+ for(i=xbytes-1; i>=0; i-- )
+ p[i] = fnc(opaque);
+ #endif
+ }
+ assert(!xbits);
+}
+
+
diff --git a/mpi/mpi-cmp.c b/mpi/mpi-cmp.c
new file mode 100644
index 000000000..83e85ceb0
--- /dev/null
+++ b/mpi/mpi-cmp.c
@@ -0,0 +1,72 @@
+/* mpi-cmp.c - MPI functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+
+int
+mpi_cmp_ui( MPI u, unsigned long v )
+{
+ mpi_limb_t limb = v;
+
+ if( !u->nlimbs && !limb )
+ return 0;
+ if( u->sign )
+ return -1;
+ if( u->nlimbs > 1 )
+ return 1;
+
+ if( u->d[0] == limb )
+ return 0;
+ else if( u->d[0] > limb )
+ return 1;
+ else
+ return -1;
+}
+
+int
+mpi_cmp( MPI u, MPI v )
+{
+ mpi_size_t usize = u->nlimbs;
+ mpi_size_t vsize = v->nlimbs;
+ int cmp;
+
+ /* FIXME: are the numbers always normalized? */
+ if( !u->sign && v->sign )
+ return 1;
+ else if( u->sign && !v->sign )
+ return -1;
+ else if( usize != vsize && !u->sign && !v->sign )
+ return usize - vsize;
+ else if( usize != vsize && u->sign && v->sign )
+ return vsize + usize;
+ else if( !usize )
+ return 0;
+ else if( !(cmp=mpihelp_cmp( u->d, v->d, usize )) )
+ return 0;
+ else if( (cmp < 0?1:0) == (u->sign?1:0))
+ return 1;
+ else
+ return -1;
+}
+
+
diff --git a/mpi/mpi-div.c b/mpi/mpi-div.c
new file mode 100644
index 000000000..2955575a8
--- /dev/null
+++ b/mpi/mpi-div.c
@@ -0,0 +1,282 @@
+/* mpi-div.c - MPI functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+#include "longlong.h"
+
+
+
+void
+mpi_fdiv_r( MPI rem, MPI dividend, MPI divisor )
+{
+ int divisor_sign = divisor->sign;
+ MPI temp_divisor = NULL;
+
+ /* We need the original value of the divisor after the remainder has been
+ * preliminary calculated. We have to copy it to temporary space if it's
+ * the same variable as REM. */
+ if( rem == divisor ) {
+ temp_divisor = mpi_copy( divisor );
+ divisor = temp_divisor;
+ }
+
+ mpi_tdiv_r( rem, dividend, divisor );
+
+ if( ((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs )
+ mpi_add( rem, rem, divisor);
+
+ if( temp_divisor )
+ mpi_free(temp_divisor);
+}
+
+
+
+/****************
+ * Division rounding the quotient towards -infinity.
+ * The remainder gets the same sign as the denominator.
+ * rem is optional
+ */
+
+ulong
+mpi_fdiv_r_ui( MPI rem, MPI dividend, ulong divisor )
+{
+ mpi_limb_t rlimb;
+
+ rlimb = mpihelp_mod_1( dividend->d, dividend->nlimbs, divisor );
+ if( rlimb && dividend->sign )
+ rlimb = divisor - rlimb;
+
+ if( rem ) {
+ rem->d[0] = rlimb;
+ rem->nlimbs = rlimb? 1:0;
+ }
+ return rlimb;
+}
+
+
+void
+mpi_fdiv_q( MPI quot, MPI dividend, MPI divisor )
+{
+ MPI tmp = mpi_alloc( mpi_get_nlimbs(quot) );
+ mpi_fdiv_qr( quot, tmp, dividend, divisor);
+ mpi_free(tmp);
+}
+
+void
+mpi_fdiv_qr( MPI quot, MPI rem, MPI dividend, MPI divisor )
+{
+ int divisor_sign = divisor->sign;
+ MPI temp_divisor = NULL;
+
+ if( quot == divisor || rem == divisor ) {
+ temp_divisor = mpi_copy( divisor );
+ divisor = temp_divisor;
+ }
+
+ mpi_tdiv_qr( quot, rem, dividend, divisor );
+
+ if( (divisor_sign ^ dividend->sign) && rem->nlimbs ) {
+ mpi_sub_ui( quot, quot, 1 );
+ mpi_add( rem, rem, divisor);
+ }
+
+ if( temp_divisor )
+ mpi_free(temp_divisor);
+}
+
+
+/* If den == quot, den needs temporary storage.
+ * If den == rem, den needs temporary storage.
+ * If num == quot, num needs temporary storage.
+ * If den has temporary storage, it can be normalized while being copied,
+ * i.e no extra storage should be allocated.
+ */
+
+void
+mpi_tdiv_r( MPI rem, MPI num, MPI den)
+{
+ mpi_tdiv_qr(NULL, rem, num, den );
+}
+
+void
+mpi_tdiv_qr( MPI quot, MPI rem, MPI num, MPI den)
+{
+ mpi_ptr_t np, dp;
+ mpi_ptr_t qp, rp;
+ mpi_size_t nsize = num->nlimbs;
+ mpi_size_t dsize = den->nlimbs;
+ mpi_size_t qsize, rsize;
+ mpi_size_t sign_remainder = num->sign;
+ mpi_size_t sign_quotient = num->sign ^ den->sign;
+ unsigned normalization_steps;
+ mpi_limb_t q_limb;
+ mpi_ptr_t marker[5];
+ int markidx=0;
+
+ /* Ensure space is enough for quotient and remainder.
+ * We need space for an extra limb in the remainder, because it's
+ * up-shifted (normalized) below. */
+ rsize = nsize + 1;
+ if( rem->alloced < rsize )
+ mpi_resize( rem, rsize);
+
+ qsize = rsize - dsize; /* qsize cannot be bigger than this. */
+ if( qsize <= 0 ) {
+ if( num != rem ) {
+ rem->nlimbs = num->nlimbs;
+ rem->sign = num->sign;
+ MPN_COPY(rem->d, num->d, nsize);
+ }
+ if( quot ) {
+ /* This needs to follow the assignment to rem, in case the
+ * numerator and quotient are the same. */
+ quot->nlimbs = 0;
+ quot->sign = 0;
+ }
+ return;
+ }
+
+ if( quot && quot->alloced < qsize )
+ mpi_resize( quot, qsize);
+
+ /* Read pointers here, when reallocation is finished. */
+ np = num->d;
+ dp = den->d;
+ rp = rem->d;
+
+ /* Optimize division by a single-limb divisor. */
+ if( dsize == 1 ) {
+ mpi_limb_t rlimb;
+ if( quot ) {
+ qp = quot->d;
+ rlimb = mpihelp_divmod_1( qp, np, nsize, dp[0] );
+ qsize -= qp[qsize - 1] == 0;
+ quot->nlimbs = qsize;
+ quot->sign = sign_quotient;
+ }
+ else
+ rlimb = mpihelp_mod_1( np, nsize, dp[0] );
+ rp[0] = rlimb;
+ rsize = rlimb != 0?1:0;
+ rem->nlimbs = rsize;
+ rem->sign = sign_remainder;
+ return;
+ }
+
+
+ if( quot ) {
+ qp = quot->d;
+ /* Make sure QP and NP point to different objects. Otherwise the
+ * numerator would be gradually overwritten by the quotient limbs. */
+ if(qp == np) { /* Copy NP object to temporary space. */
+ np = marker[markidx++] = mpi_alloc_limb_space(nsize);
+ MPN_COPY(np, qp, nsize);
+ }
+ }
+ else /* Put quotient at top of remainder. */
+ qp = rp + dsize;
+
+ count_leading_zeros( normalization_steps, dp[dsize - 1] );
+
+ /* Normalize the denominator, i.e. make its most significant bit set by
+ * shifting it NORMALIZATION_STEPS bits to the left. Also shift the
+ * numerator the same number of steps (to keep the quotient the same!).
+ */
+ if( normalization_steps ) {
+ mpi_ptr_t tp;
+ mpi_limb_t nlimb;
+
+ /* Shift up the denominator setting the most significant bit of
+ * the most significant word. Use temporary storage not to clobber
+ * the original contents of the denominator. */
+ tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
+ mpihelp_lshift( tp, dp, dsize, normalization_steps );
+ dp = tp;
+
+ /* Shift up the numerator, possibly introducing a new most
+ * significant word. Move the shifted numerator in the remainder
+ * meanwhile. */
+ nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps);
+ if( nlimb ) {
+ rp[nsize] = nlimb;
+ rsize = nsize + 1;
+ }
+ else
+ rsize = nsize;
+ }
+ else {
+ /* The denominator is already normalized, as required. Copy it to
+ * temporary space if it overlaps with the quotient or remainder. */
+ if( dp == rp || (quot && (dp == qp))) {
+ mpi_ptr_t tp;
+
+ tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
+ MPN_COPY( tp, dp, dsize );
+ dp = tp;
+ }
+
+ /* Move the numerator to the remainder. */
+ if( rp != np )
+ MPN_COPY(rp, np, nsize);
+
+ rsize = nsize;
+ }
+
+ q_limb = mpihelp_divrem( qp, 0, rp, rsize, dp, dsize );
+
+ if( quot ) {
+ qsize = rsize - dsize;
+ if(q_limb) {
+ qp[qsize] = q_limb;
+ qsize += 1;
+ }
+
+ quot->nlimbs = qsize;
+ quot->sign = sign_quotient;
+ }
+
+ rsize = dsize;
+ MPN_NORMALIZE (rp, rsize);
+
+ if( normalization_steps && rsize ) {
+ mpihelp_rshift(rp, rp, rsize, normalization_steps);
+ rsize -= rp[rsize - 1] == 0?1:0;
+ }
+
+ rem->nlimbs = rsize;
+ rem->sign = sign_remainder;
+ while( markidx )
+ mpi_free_limb_space(marker[--markidx]);
+}
+
+
+/****************
+ * Check wether dividend is divisible by divisor
+ * (note: divisor must fit into a limb)
+ */
+int
+mpi_divisible_ui(MPI dividend, ulong divisor )
+{
+ return !mpihelp_mod_1( dividend->d, dividend->nlimbs, divisor );
+}
+
diff --git a/mpi/mpi-gcd.c b/mpi/mpi-gcd.c
new file mode 100644
index 000000000..f31e917f6
--- /dev/null
+++ b/mpi/mpi-gcd.c
@@ -0,0 +1,54 @@
+/* mpi-gcd.c - MPI functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+
+/****************
+ * Find the greatest common divisor G of A and B.
+ * Return: true if this 1, false in all other cases
+ */
+int
+mpi_gcd( MPI g, MPI xa, MPI xb )
+{
+ MPI a, b;
+
+ a = mpi_copy(xa);
+ b = mpi_copy(xb);
+
+ /* TAOCP Vol II, 4.5.2, Algorithm A */
+ a->sign = 0;
+ b->sign = 0;
+ while( mpi_cmp_ui( b, 0 ) ) {
+ mpi_fdiv_r( g, a, b ); /* g used as temorary variable */
+ mpi_set(a,b);
+ mpi_set(b,g);
+ }
+ mpi_set(g, a);
+
+ mpi_free(a);
+ mpi_free(b);
+ return !mpi_cmp_ui( g, 1);
+}
+
+
+
diff --git a/mpi/mpi-internal.h b/mpi/mpi-internal.h
new file mode 100644
index 000000000..b5c00b6c4
--- /dev/null
+++ b/mpi/mpi-internal.h
@@ -0,0 +1,198 @@
+/* mpi-internal.h - Internal to the Multi Precision Integers
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef G10_MPI_INTERNAL_H
+#define G10_MPI_INTERNAL_H
+
+#include "mpi.h"
+
+
+
+typedef mpi_limb_t *mpi_ptr_t; /* pointer to a limb */
+typedef int mpi_size_t; /* (must be a signed type) */
+
+#define ABS(x) (x >= 0 ? x : -x)
+#define MIN(l,o) ((l) < (o) ? (l) : (o))
+#define MAX(h,i) ((h) > (i) ? (h) : (i))
+#define RESIZE_IF_NEEDED(a,b) \
+ do { \
+ if( (a)->alloced < (b) ) \
+ mpi_resize((a), (b)); \
+ } while(0)
+
+/* Copy N limbs from S to D. */
+#define MPN_COPY( d, s, n) \
+ do { \
+ mpi_size_t _i; \
+ for( _i = 0; _i < (n); _i++ ) \
+ (d)[_i] = (s)[_i]; \
+ } while(0)
+
+#define MPN_COPY_DECR( d, s, n ) \
+ do { \
+ mpi_size_t _i; \
+ for( _i = (n)-1; _i >= 0; _i--) \
+ (d)[_i] = (s)[_i]; \
+ } while(0)
+
+/* Zero N limbs at D */
+#define MPN_ZERO(d, n) \
+ do { \
+ int _i; \
+ for( _i = 0; _i < (n); _i++ ) \
+ (d)[_i] = 0; \
+ } while (0)
+
+#define MPN_NORMALIZE(d, n) \
+ do { \
+ while( (n) > 0 ) { \
+ if( (d)[(n)-1] ) \
+ break; \
+ (n)--; \
+ } \
+ } while(0)
+
+#define MPN_NORMALIZE_NOT_ZERO(d, n) \
+ do { \
+ for(;;) { \
+ if( (d)[(n)-1] ) \
+ break; \
+ (n)--; \
+ } \
+ } while(0)
+
+#define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace) \
+ do { \
+ if( (size) < KARATSUBA_THRESHOLD ) \
+ mul_n_basecase (prodp, up, vp, size); \
+ else \
+ mul_n (prodp, up, vp, size, tspace); \
+ } while (0);
+
+
+/* Divide the two-limb number in (NH,,NL) by D, with DI being the largest
+ * limb not larger than (2**(2*BITS_PER_MP_LIMB))/D - (2**BITS_PER_MP_LIMB).
+ * If this would yield overflow, DI should be the largest possible number
+ * (i.e., only ones). For correct operation, the most significant bit of D
+ * has to be set. Put the quotient in Q and the remainder in R.
+ */
+#define UDIV_QRNND_PREINV(q, r, nh, nl, d, di) \
+ do { \
+ mpi_limb_t _q, _ql, _r; \
+ mpi_limb_t _xh, _xl; \
+ umul_ppmm (_q, _ql, (nh), (di)); \
+ _q += (nh); /* DI is 2**BITS_PER_MPI_LIMB too small */ \
+ umul_ppmm (_xh, _xl, _q, (d)); \
+ sub_ddmmss (_xh, _r, (nh), (nl), _xh, _xl); \
+ if( _xh ) { \
+ sub_ddmmss (_xh, _r, _xh, _r, 0, (d)); \
+ _q++; \
+ if( _xh) { \
+ sub_ddmmss (_xh, _r, _xh, _r, 0, (d)); \
+ _q++; \
+ } \
+ } \
+ if( _r >= (d) ) { \
+ _r -= (d); \
+ _q++; \
+ } \
+ (r) = _r; \
+ (q) = _q; \
+ } while (0)
+
+
+/*-- mpiutil.c --*/
+#ifdef M_DEBUG
+ #define mpi_alloc_limb_space(n) mpi_debug_alloc_limb_space((n), M_DBGINFO( __LINE__ ) )
+ #define mpi_free_limb_space(n) mpi_debug_free_limb_space((n), M_DBGINFO( __LINE__ ) )
+ mpi_ptr_t mpi_debug_alloc_limb_space( unsigned nlimbs, const char *info );
+ void mpi_debug_free_limb_space( mpi_ptr_t a, const char *info );
+#else
+ mpi_ptr_t mpi_alloc_limb_space( unsigned nlimbs );
+ void mpi_free_limb_space( mpi_ptr_t a );
+#endif
+void mpi_assign_limb_space( MPI a, mpi_ptr_t ap, unsigned nlimbs );
+
+/*-- mpihelp-add.c --*/
+mpi_limb_t mpihelp_add_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_size_t s1_size, mpi_limb_t s2_limb );
+mpi_limb_t mpihelp_add_n( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_ptr_t s2_ptr, mpi_size_t size);
+mpi_limb_t mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
+ mpi_ptr_t s2_ptr, mpi_size_t s2_size);
+
+/*-- mpihelp-sub.c --*/
+mpi_limb_t mpihelp_sub_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_size_t s1_size, mpi_limb_t s2_limb );
+mpi_limb_t mpihelp_sub_n( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_ptr_t s2_ptr, mpi_size_t size);
+mpi_limb_t mpihelp_sub(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
+ mpi_ptr_t s2_ptr, mpi_size_t s2_size);
+
+/*-- mpihelp-cmp.c --*/
+int mpihelp_cmp( mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size );
+
+/*-- mpihelp-mul.c --*/
+mpi_limb_t mpihelp_addmul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_size_t s1_size, mpi_limb_t s2_limb);
+mpi_limb_t mpihelp_submul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_size_t s1_size, mpi_limb_t s2_limb);
+mpi_limb_t mpihelp_mul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_size_t s1_size, mpi_limb_t s2_limb);
+void mpihelp_mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp,
+ mpi_size_t size);
+mpi_limb_t mpihelp_mul( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize,
+ mpi_ptr_t vp, mpi_size_t vsize);
+
+/*-- mpihelp-div.c --*/
+mpi_limb_t mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+ mpi_limb_t divisor_limb);
+mpi_limb_t mpihelp_divrem( mpi_ptr_t qp, mpi_size_t qextra_limbs,
+ mpi_ptr_t np, mpi_size_t nsize,
+ mpi_ptr_t dp, mpi_size_t dsize);
+mpi_limb_t mpihelp_divmod_1( mpi_ptr_t quot_ptr,
+ mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+ mpi_limb_t divisor_limb);
+
+/*-- mpihelp-shift.c --*/
+mpi_limb_t mpihelp_lshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
+ unsigned cnt);
+mpi_limb_t mpihelp_rshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
+ unsigned cnt);
+
+
+/* Define stuff for longlong.h. */
+#define W_TYPE_SIZE BITS_PER_MPI_LIMB
+ typedef mpi_limb_t UWtype;
+ typedef unsigned int UHWtype;
+#if defined (__GNUC__)
+ typedef unsigned int UQItype __attribute__ ((mode (QI)));
+ typedef int SItype __attribute__ ((mode (SI)));
+ typedef unsigned int USItype __attribute__ ((mode (SI)));
+ typedef int DItype __attribute__ ((mode (DI)));
+ typedef unsigned int UDItype __attribute__ ((mode (DI)));
+#else
+ typedef unsigned char UQItype;
+ typedef long SItype;
+ typedef unsigned long USItype;
+#endif
+
+
+#endif /*G10_MPI_INTERNAL_H*/
diff --git a/mpi/mpi-inv.c b/mpi/mpi-inv.c
new file mode 100644
index 000000000..acde6055a
--- /dev/null
+++ b/mpi/mpi-inv.c
@@ -0,0 +1,127 @@
+/* mpi-inv.c - MPI functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+
+/****************
+ * Calculate the multiplicative inverse X of U mod V
+ * That is: Find the solution for
+ * 1 = (u*x) mod v
+ * This has only a unique solution if U and V are relatively prime.
+ * Returns 0 if a solution was found.
+ */
+int
+mpi_inv_mod( MPI x, MPI u, MPI v )
+{
+ #if 0
+ /* Extended Euclid's algorithm (See TAOPC Vol II, 4.52. Alg X) */
+ MPI u1, u2, u3, v1, v2, v3, q, t1, t2, t3;
+
+ u1 = mpi_alloc_set_ui(1);
+ u2 = mpi_alloc_set_ui(0);
+ u3 = mpi_copy(u);
+ v1 = mpi_alloc_set_ui(0);
+ v2 = mpi_alloc_set_ui(1);
+ v3 = mpi_copy(v);
+ q = mpi_alloc( mpi_get_nlimbs(u) );
+ t1 = mpi_alloc( mpi_get_nlimbs(u) );
+ t2 = mpi_alloc( mpi_get_nlimbs(u) );
+ t3 = mpi_alloc( mpi_get_nlimbs(u) );
+ while( mpi_cmp_ui( v3, 0 ) ) {
+ /*log_debug("----------------------\n");
+ log_mpidump("q =", u1);
+ log_mpidump("u1=", u1);
+ log_mpidump("u2=", u2);
+ log_mpidump("u3=", u3);
+ log_mpidump("v1=", v1);
+ log_mpidump("v2=", v2);
+ log_mpidump("v3=", v3); */
+ mpi_fdiv_q( q, u3, v3 );
+ mpi_mul(t1, v1, q); mpi_mul(t2, v2, q); mpi_mul(t3, v3, q);
+ mpi_sub(t1, u1, t1); mpi_sub(t2, u2, t2); mpi_sub(t3, u3, t3);
+
+ mpi_set(u1, v1); mpi_set(u2, v2); mpi_set(u3, v3);
+ mpi_set(v1, t1); mpi_set(v2, t2); mpi_set(v3, t3);
+ }
+ mpi_set(x, u3);
+
+ mpi_free(u1);
+ mpi_free(u2);
+ mpi_free(u3);
+ mpi_free(v1);
+ mpi_free(v2);
+ mpi_free(v3);
+ mpi_free(q);
+ mpi_free(t1);
+ mpi_free(t2);
+ mpi_free(t3);
+ #endif
+
+ /*****************************
+ * 1. Init: g0 = u g1 = v v0 = 0 v1 = 1
+ * 2. Test: if g1 is 0 terminate. Result = v0 < 0: v0 + n
+ * else: v0
+ * 3. Divide: div,rem = g0 / g1
+ * t1 = v0 - div * v1
+ * v0 = v1
+ * v1 = t1
+ * g0 = g1
+ * g1 = rem
+ * continue with step 2.
+ */
+ MPI g0, g1, v0, v1, div, rem, t1;
+
+ g0 = mpi_copy(v);
+ g1 = mpi_copy(u);
+ v0 = mpi_alloc_set_ui( 0 );
+ v1 = mpi_alloc_set_ui( 1 );
+ div = mpi_alloc(mpi_get_nlimbs(v));
+ rem = mpi_alloc(mpi_get_nlimbs(v));
+ t1 = mpi_alloc(mpi_get_nlimbs(v));
+ while( mpi_cmp_ui( g1, 0) ) {
+ mpi_fdiv_qr(div, rem, g0, g1);
+ mpi_mul(t1, div, v1);
+ mpi_sub(t1, v0, t1);
+ mpi_set(v0, v1);
+ mpi_set(v1, t1);
+ mpi_set(g0, g1);
+ mpi_set(g1, rem);
+
+ }
+ if( mpi_cmp_ui( v0, 0) < 0 )
+ mpi_add( x, v0, v);
+ else
+ mpi_set( x, v0);
+
+ mpi_free(g0);
+ mpi_free(g1);
+ mpi_free(v0);
+ mpi_free(v1);
+ mpi_free(div);
+ mpi_free(rem);
+ mpi_free(t1);
+ return 0;
+}
+
+
+
diff --git a/mpi/mpi-mul.c b/mpi/mpi-mul.c
new file mode 100644
index 000000000..03f2b4b44
--- /dev/null
+++ b/mpi/mpi-mul.c
@@ -0,0 +1,178 @@
+/* mpi-mul.c - MPI functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+
+
+void
+mpi_mul_ui( MPI prod, MPI mult, unsigned long small_mult )
+{
+ mpi_size_t size, prod_size;
+ mpi_ptr_t prod_ptr;
+ mpi_limb_t cy;
+ int sign;
+
+ size = mult->nlimbs;
+ sign = mult->sign;
+
+ if( !size || !small_mult ) {
+ prod->nlimbs = 0;
+ prod->sign = 0;
+ return;
+ }
+
+ prod_size = size + 1;
+ if( prod->alloced < prod_size )
+ mpi_resize( prod, prod_size );
+ prod_ptr = prod->d;
+
+ cy = mpihelp_mul_1( prod_ptr, mult->d, size, (mpi_limb_t)small_mult );
+ if( cy )
+ prod_ptr[size++] = cy;
+ prod->nlimbs = size;
+ prod->sign = sign;
+}
+
+
+void
+mpi_mul_2exp( MPI w, MPI u, unsigned long cnt)
+{
+ mpi_size_t usize, wsize, limb_cnt;
+ mpi_ptr_t wp;
+ mpi_limb_t wlimb;
+ int usign, wsign;
+
+ usize = u->nlimbs;
+ usign = u->sign;
+
+ if( !usize ) {
+ w->nlimbs = 0;
+ w->sign = 0;
+ return;
+ }
+
+ limb_cnt = cnt / BITS_PER_MPI_LIMB;
+ wsize = usize + limb_cnt + 1;
+ if( w->alloced < wsize )
+ mpi_resize(w, wsize );
+ wp = w->d;
+ wsize = usize + limb_cnt;
+ wsign = usign;
+
+ cnt %= BITS_PER_MPI_LIMB;
+ if( cnt ) {
+ wlimb = mpihelp_lshift( wp + limb_cnt, u->d, usize, cnt );
+ if( wlimb ) {
+ wp[wsize] = wlimb;
+ wsize++;
+ }
+ }
+ else {
+ MPN_COPY_DECR( wp + limb_cnt, u->d, usize );
+ }
+
+ /* Zero all whole limbs at low end. Do it here and not before calling
+ * mpn_lshift, not to lose for U == W. */
+ MPN_ZERO( wp, limb_cnt );
+
+ w->nlimbs = wsize;
+ w->sign = wsign;
+}
+
+
+
+void
+mpi_mul( MPI w, MPI u, MPI v)
+{
+ mpi_size_t usize, vsize, wsize;
+ mpi_ptr_t up, vp, wp;
+ mpi_limb_t cy;
+ int usign, vsign, sign_product;
+ int assign_wp=0;
+ mpi_ptr_t tmp_limb=NULL;
+
+ if( u->nlimbs < v->nlimbs ) { /* Swap U and V. */
+ usize = v->nlimbs;
+ usign = v->sign;
+ up = v->d;
+ vsize = u->nlimbs;
+ vsign = u->sign;
+ vp = u->d;
+ }
+ else {
+ usize = u->nlimbs;
+ usign = u->sign;
+ up = u->d;
+ vsize = v->nlimbs;
+ vsign = v->sign;
+ vp = v->d;
+ }
+ sign_product = usign ^ vsign;
+ wp = w->d;
+
+ /* Ensure W has space enough to store the result. */
+ wsize = usize + vsize;
+ if( w->alloced < wsize ) {
+ if( wp == up || wp == vp ) {
+ wp = mpi_alloc_limb_space( wsize );
+ assign_wp = 1;
+ }
+ else {
+ mpi_resize(w, wsize );
+ wp = w->d;
+ }
+ }
+ else { /* Make U and V not overlap with W. */
+ if( wp == up ) {
+ /* W and U are identical. Allocate temporary space for U. */
+ up = tmp_limb = mpi_alloc_limb_space( usize );
+ /* Is V identical too? Keep it identical with U. */
+ if( wp == vp )
+ vp = up;
+ /* Copy to the temporary space. */
+ MPN_COPY( up, wp, usize );
+ }
+ else if( wp == vp ) {
+ /* W and V are identical. Allocate temporary space for V. */
+ vp = tmp_limb = mpi_alloc_limb_space( vsize );
+ /* Copy to the temporary space. */
+ MPN_COPY( vp, wp, vsize );
+ }
+ }
+
+ if( !vsize )
+ wsize = 0;
+ else {
+ cy = mpihelp_mul( wp, up, usize, vp, vsize );
+ wsize -= cy? 0:1;
+ }
+
+ if( assign_wp )
+ mpi_assign_limb_space( w, wp, wsize );
+ w->nlimbs = wsize;
+ w->sign = sign_product;
+ if( tmp_limb )
+ mpi_free_limb_space( tmp_limb );
+}
+
+
diff --git a/mpi/mpi-pow.c b/mpi/mpi-pow.c
new file mode 100644
index 000000000..14fe4de47
--- /dev/null
+++ b/mpi/mpi-pow.c
@@ -0,0 +1,247 @@
+/* mpi-pow.c - MPI functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+#include "longlong.h"
+#include <assert.h>
+
+
+/****************
+ * RES = BASE ^ EXP mod MOD
+ */
+void
+mpi_powm( MPI res, MPI base, MPI exp, MPI mod)
+{
+ mpi_ptr_t rp, ep, mp, bp;
+ mpi_size_t esize, msize, bsize, rsize;
+ int esign, msign, bsign, rsign;
+ mpi_size_t size;
+ int mod_shift_cnt;
+ int negative_result;
+ mpi_ptr_t mp_marker=NULL, bp_marker=NULL, ep_marker=NULL;
+ mpi_ptr_t xp_marker=NULL;
+ int assign_rp=0;
+
+ esize = exp->nlimbs;
+ msize = mod->nlimbs;
+ size = 2 * msize;
+ esign = exp->sign;
+ msign = mod->sign;
+
+ rp = res->d;
+ ep = exp->d;
+
+ if( !msize )
+ msize = 1 / msize; /* provoke a signal */
+
+ if( !esize ) {
+ /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0
+ * depending on if MOD equals 1. */
+ rp[0] = 1;
+ res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1;
+ res->sign = 0;
+ goto leave;
+ }
+
+ /* Normalize MOD (i.e. make its most significant bit set) as required by
+ * mpn_divrem. This will make the intermediate values in the calculation
+ * slightly larger, but the correct result is obtained after a final
+ * reduction using the original MOD value. */
+ mp = mp_marker = mpi_alloc_limb_space(msize);
+ count_leading_zeros( mod_shift_cnt, mod->d[msize-1] );
+ if( mod_shift_cnt )
+ mpihelp_lshift( mp, mod->d, msize, mod_shift_cnt );
+ else
+ MPN_COPY( mp, mod->d, msize );
+
+ bsize = base->nlimbs;
+ bsign = base->sign;
+ if( bsize > msize ) { /* The base is larger than the module. Reduce it. */
+ /* Allocate (BSIZE + 1) with space for remainder and quotient.
+ * (The quotient is (bsize - msize + 1) limbs.) */
+ bp = bp_marker = mpi_alloc_limb_space( bsize + 1);
+ MPN_COPY( bp, base->d, bsize );
+ /* We don't care about the quotient, store it above the remainder,
+ * at BP + MSIZE. */
+ mpihelp_divrem( bp + msize, 0, bp, bsize, mp, msize );
+ bsize = msize;
+ /* Canonicalize the base, since we are going to multiply with it
+ * quite a few times. */
+ MPN_NORMALIZE( bp, bsize );
+ }
+ else
+ bp = base->d;
+
+ if( !bsize ) {
+ res->nlimbs = 0;
+ res->sign = 0;
+ goto leave;
+ }
+
+ if( res->alloced < size ) {
+ /* We have to allocate more space for RES. If any of the input
+ * parameters are identical to RES, defer deallocation of the old
+ * space. */
+ if( rp == ep || rp == mp || rp == bp ) {
+ rp = mpi_alloc_limb_space( size );
+ assign_rp = 1;
+ }
+ else {
+ mpi_resize( res, size );
+ rp = res->d;
+ }
+ }
+ else { /* Make BASE, EXP and MOD not overlap with RES. */
+ if( rp == bp ) {
+ /* RES and BASE are identical. Allocate temp. space for BASE. */
+ assert( !bp_marker );
+ bp = bp_marker = mpi_alloc_limb_space( bsize );
+ MPN_COPY(bp, rp, bsize);
+ }
+ if( rp == ep ) {
+ /* RES and EXP are identical. Allocate temp. space for EXP. */
+ ep = ep_marker = mpi_alloc_limb_space( esize );
+ MPN_COPY(ep, rp, esize);
+ }
+ if( rp == mp ) {
+ /* RES and MOD are identical. Allocate temporary space for MOD.*/
+ assert( !mp_marker );
+ mp = mp_marker = mpi_alloc_limb_space( msize );
+ MPN_COPY(mp, rp, msize);
+ }
+ }
+
+ MPN_COPY( rp, bp, bsize );
+ rsize = bsize;
+ rsign = bsign;
+
+ {
+ mpi_size_t i;
+ mpi_ptr_t xp = xp_marker = mpi_alloc_limb_space( 2 * (msize + 1) );
+ int c;
+ mpi_limb_t e;
+ mpi_limb_t carry_limb;
+
+ negative_result = (ep[0] & 1) && base->sign;
+
+ i = esize - 1;
+ e = ep[i];
+ count_leading_zeros (c, e);
+ e = (e << c) << 1; /* shift the exp bits to the left, lose msb */
+ c = BITS_PER_MPI_LIMB - 1 - c;
+
+ /* Main loop.
+ *
+ * Make the result be pointed to alternately by XP and RP. This
+ * helps us avoid block copying, which would otherwise be necessary
+ * with the overlap restrictions of mpihelp_divmod. With 50% probability
+ * the result after this loop will be in the area originally pointed
+ * by RP (==RES->d), and with 50% probability in the area originally
+ * pointed to by XP.
+ */
+ for(;;) {
+ while( c ) {
+ mpi_ptr_t tp;
+ mpi_size_t xsize;
+
+ mpihelp_mul_n(xp, rp, rp, rsize);
+ xsize = 2 * rsize;
+ if( xsize > msize ) {
+ mpihelp_divrem(xp + msize, 0, xp, xsize, mp, msize);
+ xsize = msize;
+ }
+
+ tp = rp; rp = xp; xp = tp;
+ rsize = xsize;
+
+ if( (mpi_limb_signed_t)e < 0 ) {
+ mpihelp_mul( xp, rp, rsize, bp, bsize );
+ xsize = rsize + bsize;
+ if( xsize > msize ) {
+ mpihelp_divrem(xp + msize, 0, xp, xsize, mp, msize);
+ xsize = msize;
+ }
+
+ tp = rp; rp = xp; xp = tp;
+ rsize = xsize;
+ }
+ e <<= 1;
+ c--;
+ }
+
+ i--;
+ if( i < 0 )
+ break;
+ e = ep[i];
+ c = BITS_PER_MPI_LIMB;
+ }
+
+ /* We shifted MOD, the modulo reduction argument, left MOD_SHIFT_CNT
+ * steps. Adjust the result by reducing it with the original MOD.
+ *
+ * Also make sure the result is put in RES->d (where it already
+ * might be, see above).
+ */
+ if( mod_shift_cnt ) {
+ carry_limb = mpihelp_lshift( res->d, rp, rsize, mod_shift_cnt);
+ rp = res->d;
+ if( carry_limb ) {
+ rp[rsize] = carry_limb;
+ rsize++;
+ }
+ }
+ else {
+ MPN_COPY( res->d, rp, rsize);
+ rp = res->d;
+ }
+
+ if( rsize >= msize ) {
+ mpihelp_divrem(rp + msize, 0, rp, rsize, mp, msize);
+ rsize = msize;
+ }
+
+ /* Remove any leading zero words from the result. */
+ if( mod_shift_cnt )
+ mpihelp_rshift( rp, rp, rsize, mod_shift_cnt);
+ MPN_NORMALIZE (rp, rsize);
+ }
+
+ if( negative_result && rsize ) {
+ if( mod_shift_cnt )
+ mpihelp_rshift( mp, mp, msize, mod_shift_cnt);
+ mpihelp_sub( rp, mp, msize, rp, rsize);
+ rsize = msize;
+ rsign = msign;
+ MPN_NORMALIZE(rp, rsize);
+ }
+ res->nlimbs = rsize;
+ res->sign = rsign;
+
+ leave:
+ if( assign_rp ) mpi_assign_limb_space( res, rp, size );
+ if( mp_marker ) mpi_free_limb_space( mp_marker );
+ if( bp_marker ) mpi_free_limb_space( bp_marker );
+ if( ep_marker ) mpi_free_limb_space( ep_marker );
+ if( xp_marker ) mpi_free_limb_space( xp_marker );
+}
+
diff --git a/mpi/mpi-scan.c b/mpi/mpi-scan.c
new file mode 100644
index 000000000..8626032a0
--- /dev/null
+++ b/mpi/mpi-scan.c
@@ -0,0 +1,88 @@
+/* mpi-scan.c - MPI functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+
+/****************
+ * Scan through an mpi and return byte for byte. a -1 is returned to indicate
+ * the end of the mpi. Scanning is done from the lsb to the msb, returned
+ * values are in the range of 0 .. 255.
+ *
+ * FIXME: This code is VERY ugly!
+ */
+int
+mpi_getbyte( MPI a, unsigned index )
+{
+ int i, j;
+ unsigned n;
+ mpi_ptr_t ap;
+ mpi_limb_t limb;
+
+ ap = a->d;
+ for(n=0,i=0; i < a->nlimbs; i++ ) {
+ limb = ap[i];
+ for( j=0; j < BYTES_PER_MPI_LIMB; j++, n++ )
+ if( n == index )
+ return (limb >> j*8) & 0xff;
+ }
+ return -1;
+}
+
+
+/****************
+ * Put a value at position INDEX into A. index counts from lsb to msb
+ */
+void
+mpi_putbyte( MPI a, unsigned index, int c )
+{
+ int i, j;
+ unsigned n;
+ mpi_ptr_t ap;
+ mpi_limb_t limb;
+
+#if BYTES_PER_MPI_LIMB != 4
+ #error please enhance this function, its ugly - i know.
+#endif
+ c &= 0xff;
+ ap = a->d;
+ for(n=0,i=0; i < a->alloced; i++ ) {
+ limb = ap[i];
+ for( j=0; j < BYTES_PER_MPI_LIMB; j++, n++ )
+ if( n == index ) {
+ if( j == 0 )
+ limb = (limb & 0xffffff00) | c;
+ else if( j == 1 )
+ limb = (limb & 0xffff00ff) | (c<<8);
+ else if( j == 2 )
+ limb = (limb & 0xff00ffff) | (c<<16);
+ else
+ limb = (limb & 0x00ffffff) | (c<<24);
+ if( a->nlimbs <= i )
+ a->nlimbs = i+1;
+ ap[i] = limb;
+ return;
+ }
+ }
+ abort(); /* index out of range */
+}
+
diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c
new file mode 100644
index 000000000..23454c0f9
--- /dev/null
+++ b/mpi/mpicoder.c
@@ -0,0 +1,392 @@
+/* mpicoder.c - Coder for the external representation of MPIs
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "mpi.h"
+#include "iobuf.h"
+#include "memory.h"
+#include "util.h"
+
+#ifdef M_DEBUG
+ #undef mpi_decode
+ #undef mpi_decode_buffer
+#endif
+
+#define MAX_EXTERN_MPI_BITS 16384
+
+/****************
+ * write an mpi to out.
+ */
+int
+mpi_encode( IOBUF out, MPI a )
+{
+ u16 dummy;
+ return mpi_encode_csum( out, a, &dummy );
+}
+
+int
+mpi_encode_csum( IOBUF out, MPI a, u16 *csum )
+{
+ int i;
+ byte c;
+ unsigned nbits = a->nlimbs * BITS_PER_MPI_LIMB;
+ mpi_limb_t limb;
+
+#if BYTES_PER_MPI_LIMB != 4
+ #error Make this function work with other LIMB sizes
+#endif
+ if( nbits > MAX_EXTERN_MPI_BITS )
+ log_bug("mpi_encode: mpi too large (%u bits)\n", nbits);
+ iobuf_put(out, (c=nbits >>8) ); *csum += c;
+ iobuf_put(out, (c=nbits) ); *csum += c;
+ for(i=a->nlimbs-1; i >= 0; i-- ) {
+ limb = a->d[i];
+ iobuf_put(out, (c=limb >> 24) ); *csum += c;
+ iobuf_put(out, (c=limb >> 16) ); *csum += c;
+ iobuf_put(out, (c=limb >> 8) ); *csum += c;
+ iobuf_put(out, (c=limb ) ); *csum += c;
+ }
+ return 0;
+}
+
+/****************
+ * encode the MPI into a newly allocated buffer, the buffer is
+ * so constructed, that it can be used for mpi_write. The caller
+ * must free the returned buffer. The buffer is allocated in the same
+ * type of memory space as A is.
+ */
+byte *
+mpi_encode_buffer( MPI a )
+{
+ abort();
+ return NULL;
+}
+
+/****************
+ * write an mpi to out. This is a special function to handle
+ * encrypted values. It simply writes the buffer a to OUT.
+ * A is a special buffer, starting with 2 bytes giving it's length
+ * (in big endian order) and 2 bytes giving it's length in bits (also
+ * big endian)
+ */
+int
+mpi_write( IOBUF out, byte *a)
+{
+ u16 dummy;
+ return mpi_write_csum( out, a, &dummy );
+}
+
+int
+mpi_write_csum( IOBUF out, byte *a, u16 *csum)
+{
+ int rc;
+ unsigned n;
+
+ n = *a++ << 8;
+ n |= *a++;
+ rc = iobuf_write(out, a, n );
+ for( ; n; n--, a++ )
+ *csum += *a;
+ return rc;
+}
+
+/****************
+ * Decode an external representation and return an MPI
+ * The external format is a 16 bit unsigned value stored in network byte order,
+ * giving the number of bits for the following integer. The integer is stored
+ * with MSB first (left padded with zeroes to align on a byte boundary).
+ */
+MPI
+#ifdef M_DEBUG
+mpi_debug_decode(IOBUF inp, unsigned *ret_nread, const char *info)
+#else
+mpi_decode(IOBUF inp, unsigned *ret_nread)
+#endif
+{
+ int c, i, j;
+ unsigned nbits, nbytes, nlimbs, nread=0;
+ mpi_limb_t a;
+ MPI val = MPI_NULL;
+
+ if( (c = iobuf_get(inp)) == -1 )
+ goto leave;
+ nbits = c << 8;
+ if( (c = iobuf_get(inp)) == -1 )
+ goto leave;
+ nbits |= c;
+ if( nbits > MAX_EXTERN_MPI_BITS ) {
+ log_error("mpi too large (%u bits)\n", nbits);
+ goto leave;
+ }
+ nread = 2;
+
+ nbytes = (nbits+7) / 8;
+ nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+ #ifdef M_DEBUG
+ val = mpi_debug_alloc( nlimbs, info );
+ #else
+ val = mpi_alloc( nlimbs );
+ #endif
+ i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
+ i %= BYTES_PER_MPI_LIMB;
+ j= val->nlimbs = nlimbs;
+ val->sign = 0;
+ for( ; j > 0; j-- ) {
+ a = 0;
+ for(; i < BYTES_PER_MPI_LIMB; i++ ) {
+ a <<= 8;
+ a |= iobuf_get(inp) & 0xff; nread++;
+ }
+ i = 0;
+ val->d[j-1] = a;
+ }
+
+ leave:
+ if( nread > *ret_nread )
+ log_error("Ooops: mpi crosses packet border");
+ else
+ *ret_nread = nread;
+ return val;
+}
+
+
+/****************
+ * Decode an MPI from the buffer, the buffer starts with two bytes giving
+ * the length of the data to follow, the original data follows.
+ * The MPI is alloced from secure MPI space
+ */
+MPI
+#ifdef M_DEBUG
+mpi_debug_decode_buffer(byte *buffer, const char *info )
+#else
+mpi_decode_buffer(byte *buffer )
+#endif
+{
+ int i, j;
+ u16 buflen;
+ unsigned nbits, nbytes, nlimbs;
+ mpi_limb_t a;
+ byte *p = buffer;
+ MPI val;
+
+ if( !buffer )
+ log_bug("mpi_decode_buffer: no buffer\n");
+ buflen = *p++ << 8;
+ buflen |= *p++;
+ nbits = *p++ << 8;
+ nbits |= *p++;
+ nbytes = (nbits+7) / 8;
+ if( nbytes+2 != buflen )
+ log_bug("mpi_decode_buffer: length conflict\n");
+ nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+ #ifdef M_DEBUG
+ val = mpi_debug_alloc_secure( nlimbs, info );
+ #else
+ val = mpi_alloc_secure( nlimbs );
+ #endif
+ i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
+ i %= BYTES_PER_MPI_LIMB;
+ j= val->nlimbs = nlimbs;
+ val->sign = 0;
+ for( ; j > 0; j-- ) {
+ a = 0;
+ for(; i < BYTES_PER_MPI_LIMB; i++ ) {
+ a <<= 8;
+ a |= *p++;
+ }
+ i = 0;
+ val->d[j-1] = a;
+ }
+ return val;
+}
+
+
+/****************
+ * Read a MPI from the external medium and return it in a newly allocated
+ * buffer (This buffer is allocated in the secure memory space, because
+ * we properly need this to decipher this string).
+ * Return: the allocated string and in RET_NREAD the number of bytes
+ * read (including the 2 length bytes), the returned buffer will
+ * be prefixed with two bytes describing the length of the following
+ * data.
+ */
+byte *
+mpi_read(IOBUF inp, unsigned *ret_nread)
+{
+ int c;
+ u16 buflen;
+ unsigned nbits, nbytes, nread;
+ byte *p, *buf;
+
+ if( (c = iobuf_get(inp)) == -1 )
+ return NULL;
+ nbits = c << 8;
+ if( (c = iobuf_get(inp)) == -1 )
+ return NULL;
+ nbits |= c;
+ if( nbits > MAX_EXTERN_MPI_BITS ) {
+ log_error("mpi too large (%u bits)\n", nbits);
+ return NULL;
+ }
+ nread = 2;
+
+ nbytes = (nbits+7) / 8;
+ buflen = nbytes + 2;
+ p = buf = m_alloc_secure( buflen+2 );
+ *p++ = buflen >> 8;
+ *p++ = buflen & 0xff;
+ *p++ = nbits >> 8;
+ *p++ = nbits & 0xff;
+ for( ; nbytes ; nbytes--, nread++ )
+ *p++ = iobuf_get(inp) & 0xff;
+
+ if( nread > *ret_nread )
+ log_error("Ooops: mpi crosses packet border");
+ else
+ *ret_nread = nread;
+ return buf;
+}
+
+
+/****************
+ * Make a mpi from a character string.
+ */
+int
+mpi_fromstr(MPI val, const char *str)
+{
+ int hexmode=0, sign=0, prepend_zero=0, i, j, c, c1, c2;
+ unsigned nbits, nbytes, nlimbs;
+ mpi_limb_t a;
+
+ if( *str == '-' ) {
+ sign = 1;
+ str++;
+ }
+ if( *str == '0' && str[1] == 'x' )
+ hexmode = 1;
+ else
+ return 1; /* other bases are not yet supported */
+ str += 2;
+
+ nbits = strlen(str)*4;
+ if( nbits % 8 )
+ prepend_zero = 1;
+ nbytes = (nbits+7) / 8;
+ nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+ if( val->alloced < nlimbs )
+ mpi_resize(val, nlimbs );
+ i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
+ i %= BYTES_PER_MPI_LIMB;
+ j= val->nlimbs = nlimbs;
+ val->sign = sign;
+ for( ; j > 0; j-- ) {
+ a = 0;
+ for(; i < BYTES_PER_MPI_LIMB; i++ ) {
+ if( prepend_zero ) {
+ c1 = '0';
+ prepend_zero = 0;
+ }
+ else
+ c1 = *str++;
+ assert(c1);
+ c2 = *str++;
+ assert(c2);
+ if( c1 >= '0' && c1 <= '9' )
+ c = c1 - '0';
+ else if( c1 >= 'a' && c1 <= 'f' )
+ c = c1 - 'a' + 10;
+ else if( c1 >= 'A' && c1 <= 'F' )
+ c = c1 - 'A' + 10;
+ else {
+ mpi_clear(val);
+ return 1;
+ }
+ c <<= 4;
+ if( c2 >= '0' && c2 <= '9' )
+ c |= c2 - '0';
+ else if( c2 >= 'a' && c2 <= 'f' )
+ c |= c2 - 'a' + 10;
+ else if( c2 >= 'A' && c2 <= 'F' )
+ c |= c2 - 'A' + 10;
+ else {
+ mpi_clear(val);
+ return 1;
+ }
+ a <<= 8;
+ a |= c;
+ }
+ i = 0;
+ val->d[j-1] = a;
+ }
+
+ return 0;
+}
+
+
+/****************
+ * print an MPI to the give stream and return the number of characters
+ * printed.
+ */
+int
+mpi_print( FILE *fp, MPI a, int mode )
+{
+ int i, n=0;
+
+ if( a == MPI_NULL )
+ return fprintf(fp, "[MPI_NULL]");
+ if( !mode )
+ n += fprintf(fp, "[%d bits]", a->nlimbs * BITS_PER_MPI_LIMB );
+ else {
+ if( a->sign )
+ putc('-', fp);
+ for(i=a->nlimbs; i > 0 ; i-- ) {
+ n += fprintf(fp, i!=a->nlimbs? "%0" STR2(BYTES_PER_MPI_LIMB2)
+ "lX":"%lX", (unsigned long)a->d[i-1] );
+ }
+ if( !a->nlimbs )
+ putc('0', fp );
+ }
+ return n;
+}
+
+
+/****************
+ * Special function to get the low 8 bytes from a mpi,
+ * this can be used as a keyid, KEYID is an 2 element array.
+ * Does return the low 4 bytes.
+ */
+u32
+mpi_get_keyid( MPI a, u32 *keyid )
+{
+#if BYTES_PER_MPI_LIMB != 4
+ #error Make this function work with other LIMB sizes
+#endif
+ if( keyid ) {
+ keyid[0] = a->nlimbs >= 2? a->d[1] : 0;
+ keyid[1] = a->nlimbs >= 1? a->d[0] : 0;
+ }
+ return a->nlimbs >= 1? a->d[0] : 0;
+}
+
+
diff --git a/mpi/mpih-add.c b/mpi/mpih-add.c
new file mode 100644
index 000000000..90ce8d76a
--- /dev/null
+++ b/mpi/mpih-add.c
@@ -0,0 +1,109 @@
+/* mpihelp-add.c - MPI helper functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mpi-internal.h"
+
+/****************
+ * Add to S1_PTR with size S1_SIZE the limb S2_LIMB and
+ * store the result in RES_PTR. Return the carry
+ * S1_SIZE must be > 0.
+ */
+/*_EXTERN_INLINE */
+mpi_limb_t
+mpihelp_add_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_size_t s1_size, mpi_limb_t s2_limb)
+{
+ mpi_limb_t x;
+
+ x = *s1_ptr++;
+ s2_limb += x;
+ *res_ptr++ = s2_limb;
+ if( s2_limb < x ) { /* sum is less than the left operand: handle carry */
+ while( --s1_size ) {
+ x = *s1_ptr++ + 1; /* add carry */
+ *res_ptr++ = x; /* and store */
+ if( x ) /* not 0 (no overflow): we can stop */
+ goto leave;
+ }
+ return 1; /* return carry (size of s1 to small) */
+ }
+
+ leave:
+ if( res_ptr != s1_ptr ) { /* not the same variable */
+ mpi_size_t i; /* copy the rest */
+ for( i=0; i < s1_size-1; i++ )
+ res_ptr[i] = s1_ptr[i];
+ }
+ return 0; /* no carry */
+}
+
+
+/* FIXME: this should be done in assembly */
+mpi_limb_t
+mpihelp_add_n( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_ptr_t s2_ptr, mpi_size_t size)
+{
+ mpi_limb_t x, y, cy;
+ mpi_size_t j;
+
+ /* The loop counter and index J goes from -SIZE to -1. This way
+ the loop becomes faster. */
+ j = -size;
+
+ /* Offset the base pointers to compensate for the negative indices. */
+ s1_ptr -= j;
+ s2_ptr -= j;
+ res_ptr -= j;
+
+ cy = 0;
+ do {
+ y = s2_ptr[j];
+ x = s1_ptr[j];
+ y += cy; /* add previous carry to one addend */
+ cy = y < cy? 1:0; /* get out carry from that addition */
+ y += x; /* add other addend */
+ cy += y < x? 1:0; /* get out carry from that add, combine */
+ res_ptr[j] = y;
+ } while( ++j );
+
+ return cy;
+}
+
+
+/*_EXTERN_INLINE*/
+mpi_limb_t
+mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
+ mpi_ptr_t s2_ptr, mpi_size_t s2_size)
+{
+ mpi_limb_t cy = 0;
+
+ if( s2_size )
+ cy = mpihelp_add_n( res_ptr, s1_ptr, s2_ptr, s2_size );
+
+ if( s1_size - s2_size )
+ cy = mpihelp_add_1( res_ptr + s2_size, s1_ptr + s2_size,
+ s1_size - s2_size, cy);
+ return cy;
+}
+
diff --git a/mpi/mpih-cmp.c b/mpi/mpih-cmp.c
new file mode 100644
index 000000000..821c0ce8c
--- /dev/null
+++ b/mpi/mpih-cmp.c
@@ -0,0 +1,53 @@
+/* mpihelp-sub.c - MPI helper functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mpi-internal.h"
+
+/****************
+ * Compare OP1_PTR/OP1_SIZE with OP2_PTR/OP2_SIZE.
+ * There are no restrictions on the relative sizes of
+ * the two arguments.
+ * Return 1 if OP1 > OP2, 0 if they are equal, and -1 if OP1 < OP2.
+ */
+int
+mpihelp_cmp( mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size )
+{
+ mpi_size_t i;
+ mpi_limb_t op1_word, op2_word;
+
+ for( i = size - 1; i >= 0 ; i--) {
+ op1_word = op1_ptr[i];
+ op2_word = op2_ptr[i];
+ if( op1_word != op2_word )
+ goto diff;
+ }
+ return 0;
+
+ diff:
+ /* This can *not* be simplified to
+ * op2_word - op2_word
+ * since that expression might give signed overflow. */
+ return (op1_word > op2_word) ? 1 : -1;
+}
+
diff --git a/mpi/mpih-div.c b/mpi/mpih-div.c
new file mode 100644
index 000000000..ca939a750
--- /dev/null
+++ b/mpi/mpih-div.c
@@ -0,0 +1,528 @@
+/* mpihelp-div.c - MPI helper functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+#include "longlong.h"
+
+#ifndef UMUL_TIME
+ #define UMUL_TIME 1
+#endif
+#ifndef UDIV_TIME
+ #define UDIV_TIME UMUL_TIME
+#endif
+
+/* FIXME: We should be using invert_limb (or invert_normalized_limb)
+ * here (not udiv_qrnnd).
+ */
+
+mpi_limb_t
+mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+ mpi_limb_t divisor_limb)
+{
+ mpi_size_t i;
+ mpi_limb_t n1, n0, r;
+ int dummy;
+
+ /* Botch: Should this be handled at all? Rely on callers? */
+ if( !dividend_size )
+ return 0;
+
+ /* If multiplication is much faster than division, and the
+ * dividend is large, pre-invert the divisor, and use
+ * only multiplications in the inner loop.
+ *
+ * This test should be read:
+ * Does it ever help to use udiv_qrnnd_preinv?
+ * && Does what we save compensate for the inversion overhead?
+ */
+ if( UDIV_TIME > (2 * UMUL_TIME + 6)
+ && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME ) {
+ int normalization_steps;
+
+ count_leading_zeros( normalization_steps, divisor_limb );
+ if( normalization_steps ) {
+ mpi_limb_t divisor_limb_inverted;
+
+ divisor_limb <<= normalization_steps;
+
+ /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The
+ * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+ * most significant bit (with weight 2**N) implicit.
+ *
+ * Special case for DIVISOR_LIMB == 100...000.
+ */
+ if( !(divisor_limb << 1) )
+ divisor_limb_inverted = ~(mpi_limb_t)0;
+ else
+ udiv_qrnnd(divisor_limb_inverted, dummy,
+ -divisor_limb, 0, divisor_limb);
+
+ n1 = dividend_ptr[dividend_size - 1];
+ r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+ /* Possible optimization:
+ * if (r == 0
+ * && divisor_limb > ((n1 << normalization_steps)
+ * | (dividend_ptr[dividend_size - 2] >> ...)))
+ * ...one division less...
+ */
+ for( i = dividend_size - 2; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ UDIV_QRNND_PREINV(dummy, r, r,
+ ((n1 << normalization_steps)
+ | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+ divisor_limb, divisor_limb_inverted);
+ n1 = n0;
+ }
+ UDIV_QRNND_PREINV(dummy, r, r,
+ n1 << normalization_steps,
+ divisor_limb, divisor_limb_inverted);
+ return r >> normalization_steps;
+ }
+ else {
+ mpi_limb_t divisor_limb_inverted;
+
+ /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The
+ * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+ * most significant bit (with weight 2**N) implicit.
+ *
+ * Special case for DIVISOR_LIMB == 100...000.
+ */
+ if( !(divisor_limb << 1) )
+ divisor_limb_inverted = ~(mpi_limb_t)0;
+ else
+ udiv_qrnnd(divisor_limb_inverted, dummy,
+ -divisor_limb, 0, divisor_limb);
+
+ i = dividend_size - 1;
+ r = dividend_ptr[i];
+
+ if( r >= divisor_limb )
+ r = 0;
+ else
+ i--;
+
+ for( ; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ UDIV_QRNND_PREINV(dummy, r, r,
+ n0, divisor_limb, divisor_limb_inverted);
+ }
+ return r;
+ }
+ }
+ else {
+ if( UDIV_NEEDS_NORMALIZATION ) {
+ int normalization_steps;
+
+ count_leading_zeros(normalization_steps, divisor_limb);
+ if( normalization_steps ) {
+ divisor_limb <<= normalization_steps;
+
+ n1 = dividend_ptr[dividend_size - 1];
+ r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+ /* Possible optimization:
+ * if (r == 0
+ * && divisor_limb > ((n1 << normalization_steps)
+ * | (dividend_ptr[dividend_size - 2] >> ...)))
+ * ...one division less...
+ */
+ for(i = dividend_size - 2; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ udiv_qrnnd (dummy, r, r,
+ ((n1 << normalization_steps)
+ | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+ divisor_limb);
+ n1 = n0;
+ }
+ udiv_qrnnd (dummy, r, r,
+ n1 << normalization_steps,
+ divisor_limb);
+ return r >> normalization_steps;
+ }
+ }
+ /* No normalization needed, either because udiv_qrnnd doesn't require
+ * it, or because DIVISOR_LIMB is already normalized. */
+ i = dividend_size - 1;
+ r = dividend_ptr[i];
+
+ if(r >= divisor_limb)
+ r = 0;
+ else
+ i--;
+
+ for(; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ udiv_qrnnd (dummy, r, r, n0, divisor_limb);
+ }
+ return r;
+ }
+}
+
+/* Divide num (NP/NSIZE) by den (DP/DSIZE) and write
+ * the NSIZE-DSIZE least significant quotient limbs at QP
+ * and the DSIZE long remainder at NP. If QEXTRA_LIMBS is
+ * non-zero, generate that many fraction bits and append them after the
+ * other quotient limbs.
+ * Return the most significant limb of the quotient, this is always 0 or 1.
+ *
+ * Preconditions:
+ * 0. NSIZE >= DSIZE.
+ * 1. The most significant bit of the divisor must be set.
+ * 2. QP must either not overlap with the input operands at all, or
+ * QP + DSIZE >= NP must hold true. (This means that it's
+ * possible to put the quotient in the high part of NUM, right after the
+ * remainder in NUM.
+ * 3. NSIZE >= DSIZE, even if QEXTRA_LIMBS is non-zero.
+ */
+
+mpi_limb_t
+mpihelp_divrem( mpi_ptr_t qp, mpi_size_t qextra_limbs,
+ mpi_ptr_t np, mpi_size_t nsize,
+ mpi_ptr_t dp, mpi_size_t dsize)
+{
+ mpi_limb_t most_significant_q_limb = 0;
+
+ switch(dsize) {
+ case 0:
+ /* We are asked to divide by zero, so go ahead and do it! (To make
+ the compiler not remove this statement, return the value.) */
+ return 1 / dsize;
+
+ case 1:
+ {
+ mpi_size_t i;
+ mpi_limb_t n1;
+ mpi_limb_t d;
+
+ d = dp[0];
+ n1 = np[nsize - 1];
+
+ if( n1 >= d ) {
+ n1 -= d;
+ most_significant_q_limb = 1;
+ }
+
+ qp += qextra_limbs;
+ for( i = nsize - 2; i >= 0; i--)
+ udiv_qrnnd( qp[i], n1, n1, np[i], d );
+ qp -= qextra_limbs;
+
+ for( i = qextra_limbs - 1; i >= 0; i-- )
+ udiv_qrnnd (qp[i], n1, n1, 0, d);
+
+ np[0] = n1;
+ }
+ break;
+
+ case 2:
+ {
+ mpi_size_t i;
+ mpi_limb_t n1, n0, n2;
+ mpi_limb_t d1, d0;
+
+ np += nsize - 2;
+ d1 = dp[1];
+ d0 = dp[0];
+ n1 = np[1];
+ n0 = np[0];
+
+ if( n1 >= d1 && (n1 > d1 || n0 >= d0) ) {
+ sub_ddmmss (n1, n0, n1, n0, d1, d0);
+ most_significant_q_limb = 1;
+ }
+
+ for( i = qextra_limbs + nsize - 2 - 1; i >= 0; i-- ) {
+ mpi_limb_t q;
+ mpi_limb_t r;
+
+ if( i >= qextra_limbs )
+ np--;
+ else
+ np[0] = 0;
+
+ if( n1 == d1 ) {
+ /* Q should be either 111..111 or 111..110. Need special
+ * treatment of this rare case as normal division would
+ * give overflow. */
+ q = ~(mpi_limb_t)0;
+
+ r = n0 + d1;
+ if( r < d1 ) { /* Carry in the addition? */
+ add_ssaaaa( n1, n0, r - d0, np[0], 0, d0 );
+ qp[i] = q;
+ continue;
+ }
+ n1 = d0 - (d0 != 0?1:0);
+ n0 = -d0;
+ }
+ else {
+ udiv_qrnnd (q, r, n1, n0, d1);
+ umul_ppmm (n1, n0, d0, q);
+ }
+
+ n2 = np[0];
+ q_test:
+ if( n1 > r || (n1 == r && n0 > n2) ) {
+ /* The estimated Q was too large. */
+ q--;
+ sub_ddmmss (n1, n0, n1, n0, 0, d0);
+ r += d1;
+ if( r >= d1 ) /* If not carry, test Q again. */
+ goto q_test;
+ }
+
+ qp[i] = q;
+ sub_ddmmss (n1, n0, r, n2, n1, n0);
+ }
+ np[1] = n1;
+ np[0] = n0;
+ }
+ break;
+
+ default:
+ {
+ mpi_size_t i;
+ mpi_limb_t dX, d1, n0;
+
+ np += nsize - dsize;
+ dX = dp[dsize - 1];
+ d1 = dp[dsize - 2];
+ n0 = np[dsize - 1];
+
+ if( n0 >= dX ) {
+ if(n0 > dX || mpihelp_cmp(np, dp, dsize - 1) >= 0 ) {
+ mpihelp_sub_n(np, np, dp, dsize);
+ n0 = np[dsize - 1];
+ most_significant_q_limb = 1;
+ }
+ }
+
+ for( i = qextra_limbs + nsize - dsize - 1; i >= 0; i--) {
+ mpi_limb_t q;
+ mpi_limb_t n1, n2;
+ mpi_limb_t cy_limb;
+
+ if( i >= qextra_limbs ) {
+ np--;
+ n2 = np[dsize];
+ }
+ else {
+ n2 = np[dsize - 1];
+ MPN_COPY_DECR (np + 1, np, dsize);
+ np[0] = 0;
+ }
+
+ if( n0 == dX ) {
+ /* This might over-estimate q, but it's probably not worth
+ * the extra code here to find out. */
+ q = ~(mpi_limb_t)0;
+ }
+ else {
+ mpi_limb_t r;
+
+ udiv_qrnnd(q, r, n0, np[dsize - 1], dX);
+ umul_ppmm(n1, n0, d1, q);
+
+ while( n1 > r || (n1 == r && n0 > np[dsize - 2])) {
+ q--;
+ r += dX;
+ if( r < dX ) /* I.e. "carry in previous addition?" */
+ break;
+ n1 -= n0 < d1;
+ n0 -= d1;
+ }
+ }
+
+ /* Possible optimization: We already have (q * n0) and (1 * n1)
+ * after the calculation of q. Taking advantage of that, we
+ * could make this loop make two iterations less. */
+ cy_limb = mpihelp_submul_1(np, dp, dsize, q);
+
+ if( n2 != cy_limb ) {
+ mpihelp_add_n(np, np, dp, dsize);
+ q--;
+ }
+
+ qp[i] = q;
+ n0 = np[dsize - 1];
+ }
+ }
+ }
+
+ return most_significant_q_limb;
+}
+
+
+/****************
+ * Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB.
+ * Write DIVIDEND_SIZE limbs of quotient at QUOT_PTR.
+ * Return the single-limb remainder.
+ * There are no constraints on the value of the divisor.
+ *
+ * QUOT_PTR and DIVIDEND_PTR might point to the same limb.
+ */
+
+mpi_limb_t
+mpihelp_divmod_1( mpi_ptr_t quot_ptr,
+ mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+ mpi_limb_t divisor_limb)
+{
+ mpi_size_t i;
+ mpi_limb_t n1, n0, r;
+ int dummy;
+
+ if( !dividend_size )
+ return 0;
+
+ /* If multiplication is much faster than division, and the
+ * dividend is large, pre-invert the divisor, and use
+ * only multiplications in the inner loop.
+ *
+ * This test should be read:
+ * Does it ever help to use udiv_qrnnd_preinv?
+ * && Does what we save compensate for the inversion overhead?
+ */
+ if( UDIV_TIME > (2 * UMUL_TIME + 6)
+ && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME ) {
+ int normalization_steps;
+
+ count_leading_zeros( normalization_steps, divisor_limb );
+ if( normalization_steps ) {
+ mpi_limb_t divisor_limb_inverted;
+
+ divisor_limb <<= normalization_steps;
+
+ /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The
+ * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+ * most significant bit (with weight 2**N) implicit.
+ */
+ /* Special case for DIVISOR_LIMB == 100...000. */
+ if( !(divisor_limb << 1) )
+ divisor_limb_inverted = ~(mpi_limb_t)0;
+ else
+ udiv_qrnnd(divisor_limb_inverted, dummy,
+ -divisor_limb, 0, divisor_limb);
+
+ n1 = dividend_ptr[dividend_size - 1];
+ r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+ /* Possible optimization:
+ * if (r == 0
+ * && divisor_limb > ((n1 << normalization_steps)
+ * | (dividend_ptr[dividend_size - 2] >> ...)))
+ * ...one division less...
+ */
+ for( i = dividend_size - 2; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ UDIV_QRNND_PREINV( quot_ptr[i + 1], r, r,
+ ((n1 << normalization_steps)
+ | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+ divisor_limb, divisor_limb_inverted);
+ n1 = n0;
+ }
+ UDIV_QRNND_PREINV( quot_ptr[0], r, r,
+ n1 << normalization_steps,
+ divisor_limb, divisor_limb_inverted);
+ return r >> normalization_steps;
+ }
+ else {
+ mpi_limb_t divisor_limb_inverted;
+
+ /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The
+ * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+ * most significant bit (with weight 2**N) implicit.
+ */
+ /* Special case for DIVISOR_LIMB == 100...000. */
+ if( !(divisor_limb << 1) )
+ divisor_limb_inverted = ~(mpi_limb_t) 0;
+ else
+ udiv_qrnnd(divisor_limb_inverted, dummy,
+ -divisor_limb, 0, divisor_limb);
+
+ i = dividend_size - 1;
+ r = dividend_ptr[i];
+
+ if( r >= divisor_limb )
+ r = 0;
+ else
+ quot_ptr[i--] = 0;
+
+ for( ; i >= 0; i-- ) {
+ n0 = dividend_ptr[i];
+ UDIV_QRNND_PREINV( quot_ptr[i], r, r,
+ n0, divisor_limb, divisor_limb_inverted);
+ }
+ return r;
+ }
+ }
+ else {
+ if(UDIV_NEEDS_NORMALIZATION) {
+ int normalization_steps;
+
+ count_leading_zeros (normalization_steps, divisor_limb);
+ if( normalization_steps ) {
+ divisor_limb <<= normalization_steps;
+
+ n1 = dividend_ptr[dividend_size - 1];
+ r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+ /* Possible optimization:
+ * if (r == 0
+ * && divisor_limb > ((n1 << normalization_steps)
+ * | (dividend_ptr[dividend_size - 2] >> ...)))
+ * ...one division less...
+ */
+ for( i = dividend_size - 2; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ udiv_qrnnd (quot_ptr[i + 1], r, r,
+ ((n1 << normalization_steps)
+ | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+ divisor_limb);
+ n1 = n0;
+ }
+ udiv_qrnnd (quot_ptr[0], r, r,
+ n1 << normalization_steps,
+ divisor_limb);
+ return r >> normalization_steps;
+ }
+ }
+ /* No normalization needed, either because udiv_qrnnd doesn't require
+ * it, or because DIVISOR_LIMB is already normalized. */
+ i = dividend_size - 1;
+ r = dividend_ptr[i];
+
+ if(r >= divisor_limb)
+ r = 0;
+ else
+ quot_ptr[i--] = 0;
+
+ for(; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ udiv_qrnnd( quot_ptr[i], r, r, n0, divisor_limb );
+ }
+ return r;
+ }
+}
+
+
diff --git a/mpi/mpih-mul.c b/mpi/mpih-mul.c
new file mode 100644
index 000000000..c579a93fe
--- /dev/null
+++ b/mpi/mpih-mul.c
@@ -0,0 +1,557 @@
+/* mpihelp-mul.c - MPI helper functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+#include "longlong.h"
+
+/* If KARATSUBA_THRESHOLD is not already defined, define it to a
+ * value which is good on most machines. */
+#ifndef KARATSUBA_THRESHOLD
+ #define KARATSUBA_THRESHOLD 32
+#endif
+
+/* The code can't handle KARATSUBA_THRESHOLD smaller than 2. */
+#if KARATSUBA_THRESHOLD < 2
+ #undef KARATSUBA_THRESHOLD
+ #define KARATSUBA_THRESHOLD 2
+#endif
+
+
+#define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace) \
+ do { \
+ if( (size) < KARATSUBA_THRESHOLD ) \
+ mul_n_basecase (prodp, up, vp, size); \
+ else \
+ mul_n (prodp, up, vp, size, tspace); \
+ } while (0);
+
+#define MPN_SQR_N_RECURSE(prodp, up, size, tspace) \
+ do { \
+ if ((size) < KARATSUBA_THRESHOLD) \
+ sqr_n_basecase (prodp, up, size); \
+ else \
+ sqr_n (prodp, up, size, tspace); \
+ } while (0);
+
+
+
+mpi_limb_t
+mpihelp_addmul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_size_t s1_size, mpi_limb_t s2_limb)
+{
+ mpi_limb_t cy_limb;
+ mpi_size_t j;
+ mpi_limb_t prod_high, prod_low;
+ mpi_limb_t x;
+
+ /* The loop counter and index J goes from -SIZE to -1. This way
+ * the loop becomes faster. */
+ j = -s1_size;
+ res_ptr -= j;
+ s1_ptr -= j;
+
+ cy_limb = 0;
+ do {
+ umul_ppmm( prod_high, prod_low, s1_ptr[j], s2_limb );
+
+ prod_low += cy_limb;
+ cy_limb = (prod_low < cy_limb?1:0) + prod_high;
+
+ x = res_ptr[j];
+ prod_low = x + prod_low;
+ cy_limb += prod_low < x?1:0;
+ res_ptr[j] = prod_low;
+ } while ( ++j );
+ return cy_limb;
+}
+
+
+mpi_limb_t
+mpihelp_submul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_size_t s1_size, mpi_limb_t s2_limb)
+{
+ mpi_limb_t cy_limb;
+ mpi_size_t j;
+ mpi_limb_t prod_high, prod_low;
+ mpi_limb_t x;
+
+ /* The loop counter and index J goes from -SIZE to -1. This way
+ * the loop becomes faster. */
+ j = -s1_size;
+ res_ptr -= j;
+ s1_ptr -= j;
+
+ cy_limb = 0;
+ do {
+ umul_ppmm( prod_high, prod_low, s1_ptr[j], s2_limb);
+
+ prod_low += cy_limb;
+ cy_limb = (prod_low < cy_limb?1:0) + prod_high;
+
+ x = res_ptr[j];
+ prod_low = x - prod_low;
+ cy_limb += prod_low > x?1:0;
+ res_ptr[j] = prod_low;
+ } while( ++j );
+
+ return cy_limb;
+}
+
+mpi_limb_t
+mpihelp_mul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
+ mpi_limb_t s2_limb)
+{
+ mpi_limb_t cy_limb;
+ mpi_size_t j;
+ mpi_limb_t prod_high, prod_low;
+
+ /* The loop counter and index J goes from -S1_SIZE to -1. This way
+ * the loop becomes faster. */
+ j = -s1_size;
+
+ /* Offset the base pointers to compensate for the negative indices. */
+ s1_ptr -= j;
+ res_ptr -= j;
+
+ cy_limb = 0;
+ do {
+ umul_ppmm( prod_high, prod_low, s1_ptr[j], s2_limb );
+ prod_low += cy_limb;
+ cy_limb = (prod_low < cy_limb?1:0) + prod_high;
+ res_ptr[j] = prod_low;
+ } while( ++j );
+
+ return cy_limb;
+}
+
+
+/* Multiply the natural numbers u (pointed to by UP) and v (pointed to by VP),
+ * both with SIZE limbs, and store the result at PRODP. 2 * SIZE limbs are
+ * always stored. Return the most significant limb.
+ *
+ * Argument constraints:
+ * 1. PRODP != UP and PRODP != VP, i.e. the destination
+ * must be distinct from the multiplier and the multiplicand.
+ *
+ *
+ * Handle simple cases with traditional multiplication.
+ *
+ * This is the most critical code of multiplication. All multiplies rely
+ * on this, both small and huge. Small ones arrive here immediately. Huge
+ * ones arrive here as this is the base case for Karatsuba's recursive
+ * algorithm below.
+ */
+
+static mpi_limb_t
+mul_n_basecase( mpi_ptr_t prodp, mpi_ptr_t up,
+ mpi_ptr_t vp, mpi_size_t size)
+{
+ mpi_size_t i;
+ mpi_limb_t cy;
+ mpi_limb_t v_limb;
+
+ /* Multiply by the first limb in V separately, as the result can be
+ * stored (not added) to PROD. We also avoid a loop for zeroing. */
+ v_limb = vp[0];
+ if( v_limb <= 1 ) {
+ if( v_limb == 1 )
+ MPN_COPY( prodp, up, size );
+ else
+ MPN_ZERO( prodp, size );
+ cy = 0;
+ }
+ else
+ cy = mpihelp_mul_1( prodp, up, size, v_limb );
+
+ prodp[size] = cy;
+ prodp++;
+
+ /* For each iteration in the outer loop, multiply one limb from
+ * U with one limb from V, and add it to PROD. */
+ for( i = 1; i < size; i++ ) {
+ v_limb = vp[i];
+ if( v_limb <= 1 ) {
+ cy = 0;
+ if( v_limb == 1 )
+ cy = mpihelp_add_n(prodp, prodp, up, size);
+ }
+ else
+ cy = mpihelp_addmul_1(prodp, up, size, v_limb);
+
+ prodp[size] = cy;
+ prodp++;
+ }
+
+ return cy;
+}
+
+
+static void
+mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp,
+ mpi_size_t size, mpi_ptr_t tspace )
+{
+ if( size & 1 ) {
+ /* The size is odd, the code code below doesn't handle that.
+ * Multiply the least significant (size - 1) limbs with a recursive
+ * call, and handle the most significant limb of S1 and S2
+ * separately.
+ * A slightly faster way to do this would be to make the Karatsuba
+ * code below behave as if the size were even, and let it check for
+ * odd size in the end. I.e., in essence move this code to the end.
+ * Doing so would save us a recursive call, and potentially make the
+ * stack grow a lot less.
+ */
+ mpi_size_t esize = size - 1; /* even size */
+ mpi_limb_t cy_limb;
+
+ MPN_MUL_N_RECURSE( prodp, up, vp, esize, tspace );
+ cy_limb = mpihelp_addmul_1( prodp + esize, up, esize, vp[esize] );
+ prodp[esize + esize] = cy_limb;
+ cy_limb = mpihelp_addmul_1( prodp + esize, vp, size, up[esize] );
+ prodp[esize + size] = cy_limb;
+ }
+ else {
+ /* Anatolij Alekseevich Karatsuba's divide-and-conquer algorithm.
+ *
+ * Split U in two pieces, U1 and U0, such that
+ * U = U0 + U1*(B**n),
+ * and V in V1 and V0, such that
+ * V = V0 + V1*(B**n).
+ *
+ * UV is then computed recursively using the identity
+ *
+ * 2n n n n
+ * UV = (B + B )U V + B (U -U )(V -V ) + (B + 1)U V
+ * 1 1 1 0 0 1 0 0
+ *
+ * Where B = 2**BITS_PER_MP_LIMB.
+ */
+ mpi_size_t hsize = size >> 1;
+ mpi_limb_t cy;
+ int negflg;
+
+ /* Product H. ________________ ________________
+ * |_____U1 x V1____||____U0 x V0_____|
+ * Put result in upper part of PROD and pass low part of TSPACE
+ * as new TSPACE.
+ */
+ MPN_MUL_N_RECURSE(prodp + size, up + hsize, vp + hsize, hsize, tspace);
+
+ /* Product M. ________________
+ * |_(U1-U0)(V0-V1)_|
+ */
+ if( mpihelp_cmp(up + hsize, up, hsize) >= 0 ) {
+ mpihelp_sub_n(prodp, up + hsize, up, hsize);
+ negflg = 0;
+ }
+ else {
+ mpihelp_sub_n(prodp, up, up + hsize, hsize);
+ negflg = 1;
+ }
+ if( mpihelp_cmp(vp + hsize, vp, hsize) >= 0 ) {
+ mpihelp_sub_n(prodp + hsize, vp + hsize, vp, hsize);
+ negflg ^= 1;
+ }
+ else {
+ mpihelp_sub_n(prodp + hsize, vp, vp + hsize, hsize);
+ /* No change of NEGFLG. */
+ }
+ /* Read temporary operands from low part of PROD.
+ * Put result in low part of TSPACE using upper part of TSPACE
+ * as new TSPACE.
+ */
+ MPN_MUL_N_RECURSE(tspace, prodp, prodp + hsize, hsize, tspace + size);
+
+ /* Add/copy product H. */
+ MPN_COPY (prodp + hsize, prodp + size, hsize);
+ cy = mpihelp_add_n( prodp + size, prodp + size,
+ prodp + size + hsize, hsize);
+
+ /* Add product M (if NEGFLG M is a negative number) */
+ if(negflg)
+ cy -= mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace, size);
+ else
+ cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size);
+
+ /* Product L. ________________ ________________
+ * |________________||____U0 x V0_____|
+ * Read temporary operands from low part of PROD.
+ * Put result in low part of TSPACE using upper part of TSPACE
+ * as new TSPACE.
+ */
+ MPN_MUL_N_RECURSE(tspace, up, vp, hsize, tspace + size);
+
+ /* Add/copy Product L (twice) */
+
+ cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size);
+ if( cy )
+ mpihelp_add_1(prodp + hsize + size, prodp + hsize + size, hsize, cy);
+
+ MPN_COPY(prodp, tspace, hsize);
+ cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize, hsize);
+ if( cy )
+ mpihelp_add_1(prodp + size, prodp + size, size, 1);
+ }
+}
+
+
+static void
+sqr_n_basecase( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size )
+{
+ mpi_size_t i;
+ mpi_limb_t cy_limb;
+ mpi_limb_t v_limb;
+
+ /* Multiply by the first limb in V separately, as the result can be
+ * stored (not added) to PROD. We also avoid a loop for zeroing. */
+ v_limb = up[0];
+ if( v_limb <= 1 ) {
+ if( v_limb == 1 )
+ MPN_COPY( prodp, up, size );
+ else
+ MPN_ZERO(prodp, size);
+ cy_limb = 0;
+ }
+ else
+ cy_limb = mpihelp_mul_1( prodp, up, size, v_limb );
+
+ prodp[size] = cy_limb;
+ prodp++;
+
+ /* For each iteration in the outer loop, multiply one limb from
+ * U with one limb from V, and add it to PROD. */
+ for( i=1; i < size; i++) {
+ v_limb = up[i];
+ if( v_limb <= 1 ) {
+ cy_limb = 0;
+ if( v_limb == 1 )
+ cy_limb = mpihelp_add_n(prodp, prodp, up, size);
+ }
+ else
+ cy_limb = mpihelp_addmul_1(prodp, up, size, v_limb);
+
+ prodp[size] = cy_limb;
+ prodp++;
+ }
+}
+
+
+static void
+sqr_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace)
+{
+ if( size & 1 ) {
+ /* The size is odd, the code code below doesn't handle that.
+ * Multiply the least significant (size - 1) limbs with a recursive
+ * call, and handle the most significant limb of S1 and S2
+ * separately.
+ * A slightly faster way to do this would be to make the Karatsuba
+ * code below behave as if the size were even, and let it check for
+ * odd size in the end. I.e., in essence move this code to the end.
+ * Doing so would save us a recursive call, and potentially make the
+ * stack grow a lot less.
+ */
+ mpi_size_t esize = size - 1; /* even size */
+ mpi_limb_t cy_limb;
+
+ MPN_SQR_N_RECURSE( prodp, up, esize, tspace );
+ cy_limb = mpihelp_addmul_1( prodp + esize, up, esize, up[esize] );
+ prodp[esize + esize] = cy_limb;
+ cy_limb = mpihelp_addmul_1( prodp + esize, up, size, up[esize] );
+
+ prodp[esize + size] = cy_limb;
+ }
+ else {
+ mpi_size_t hsize = size >> 1;
+ mpi_limb_t cy;
+
+ /* Product H. ________________ ________________
+ * |_____U1 x U1____||____U0 x U0_____|
+ * Put result in upper part of PROD and pass low part of TSPACE
+ * as new TSPACE.
+ */
+ MPN_SQR_N_RECURSE(prodp + size, up + hsize, hsize, tspace);
+
+ /* Product M. ________________
+ * |_(U1-U0)(U0-U1)_|
+ */
+ if( mpihelp_cmp( up + hsize, up, hsize) >= 0 )
+ mpihelp_sub_n( prodp, up + hsize, up, hsize);
+ else
+ mpihelp_sub_n (prodp, up, up + hsize, hsize);
+
+ /* Read temporary operands from low part of PROD.
+ * Put result in low part of TSPACE using upper part of TSPACE
+ * as new TSPACE. */
+ MPN_SQR_N_RECURSE(tspace, prodp, hsize, tspace + size);
+
+ /* Add/copy product H */
+ MPN_COPY(prodp + hsize, prodp + size, hsize);
+ cy = mpihelp_add_n(prodp + size, prodp + size,
+ prodp + size + hsize, hsize);
+
+ /* Add product M (if NEGFLG M is a negative number). */
+ cy -= mpihelp_sub_n (prodp + hsize, prodp + hsize, tspace, size);
+
+ /* Product L. ________________ ________________
+ * |________________||____U0 x U0_____|
+ * Read temporary operands from low part of PROD.
+ * Put result in low part of TSPACE using upper part of TSPACE
+ * as new TSPACE. */
+ MPN_SQR_N_RECURSE (tspace, up, hsize, tspace + size);
+
+ /* Add/copy Product L (twice). */
+ cy += mpihelp_add_n (prodp + hsize, prodp + hsize, tspace, size);
+ if( cy )
+ mpihelp_add_1(prodp + hsize + size, prodp + hsize + size,
+ hsize, cy);
+
+ MPN_COPY(prodp, tspace, hsize);
+ cy = mpihelp_add_n (prodp + hsize, prodp + hsize, tspace + hsize, hsize);
+ if( cy )
+ mpihelp_add_1 (prodp + size, prodp + size, size, 1);
+ }
+}
+
+
+/* This should be made into an inline function in gmp.h. */
+void
+mpihelp_mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size)
+{
+ if( up == vp ) {
+ if( size < KARATSUBA_THRESHOLD )
+ sqr_n_basecase( prodp, up, size );
+ else {
+ mpi_ptr_t tspace;
+ tspace = mpi_alloc_limb_space( 2 * size );
+ sqr_n( prodp, up, size, tspace );
+ mpi_free_limb_space( tspace );
+ }
+ }
+ else {
+ if( size < KARATSUBA_THRESHOLD )
+ mul_n_basecase( prodp, up, vp, size );
+ else {
+ mpi_ptr_t tspace;
+ tspace = mpi_alloc_limb_space( 2 * size );
+ mul_n (prodp, up, vp, size, tspace);
+ mpi_free_limb_space( tspace );
+ }
+ }
+}
+
+
+/* Multiply the natural numbers u (pointed to by UP, with USIZE limbs)
+ * and v (pointed to by VP, with VSIZE limbs), and store the result at
+ * PRODP. USIZE + VSIZE limbs are always stored, but if the input
+ * operands are normalized. Return the most significant limb of the
+ * result.
+ *
+ * NOTE: The space pointed to by PRODP is overwritten before finished
+ * with U and V, so overlap is an error.
+ *
+ * Argument constraints:
+ * 1. USIZE >= VSIZE.
+ * 2. PRODP != UP and PRODP != VP, i.e. the destination
+ * must be distinct from the multiplier and the multiplicand.
+ */
+
+mpi_limb_t
+mpihelp_mul( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize,
+ mpi_ptr_t vp, mpi_size_t vsize)
+{
+ mpi_ptr_t prod_endp = prodp + usize + vsize - 1;
+ mpi_limb_t cy;
+ mpi_ptr_t tspace;
+
+ if( vsize < KARATSUBA_THRESHOLD ) {
+ mpi_size_t i;
+ mpi_limb_t v_limb;
+
+ if( !vsize )
+ return 0;
+
+ /* Multiply by the first limb in V separately, as the result can be
+ * stored (not added) to PROD. We also avoid a loop for zeroing. */
+ v_limb = vp[0];
+ if( v_limb <= 1 ) {
+ if( v_limb == 1 )
+ MPN_COPY( prodp, up, usize );
+ else
+ MPN_ZERO( prodp, usize );
+ cy = 0;
+ }
+ else
+ cy = mpihelp_mul_1( prodp, up, usize, v_limb );
+
+ prodp[usize] = cy;
+ prodp++;
+
+ /* For each iteration in the outer loop, multiply one limb from
+ * U with one limb from V, and add it to PROD. */
+ for( i = 1; i < vsize; i++ ) {
+ v_limb = vp[i];
+ if( v_limb <= 1 ) {
+ cy = 0;
+ if( v_limb == 1 )
+ cy = mpihelp_add_n(prodp, prodp, up, usize);
+ }
+ else
+ cy = mpihelp_addmul_1(prodp, up, usize, v_limb);
+
+ prodp[usize] = cy;
+ prodp++;
+ }
+
+ return cy;
+ }
+
+ tspace = mpi_alloc_limb_space( 2 * vsize );
+ MPN_MUL_N_RECURSE( prodp, up, vp, vsize, tspace );
+
+ prodp += vsize;
+ up += vsize;
+ usize -= vsize;
+ if( usize >= vsize ) {
+ mpi_ptr_t tp = mpi_alloc_limb_space( 2 * vsize );
+ do {
+ MPN_MUL_N_RECURSE( tp, up, vp, vsize, tspace );
+ cy = mpihelp_add_n( prodp, prodp, tp, vsize );
+ mpihelp_add_1( prodp + vsize, tp + vsize, vsize, cy );
+ prodp += vsize;
+ up += vsize;
+ usize -= vsize;
+ } while( usize >= vsize );
+ mpi_free_limb_space( tp );
+ }
+
+ if( usize ) {
+ mpihelp_mul( tspace, vp, vsize, up, usize );
+ cy = mpihelp_add_n( prodp, prodp, tspace, vsize);
+ mpihelp_add_1( prodp + vsize, tspace + vsize, usize, cy );
+ }
+
+ mpi_free_limb_space( tspace );
+ return *prod_endp;
+}
+
+
diff --git a/mpi/mpih-shift.c b/mpi/mpih-shift.c
new file mode 100644
index 000000000..a8fe26aa2
--- /dev/null
+++ b/mpi/mpih-shift.c
@@ -0,0 +1,94 @@
+/* mpihelp-shift.c - MPI helper functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+
+/* Shift U (pointed to by UP and USIZE digits long) CNT bits to the left
+ * and store the USIZE least significant digits of the result at WP.
+ * Return the bits shifted out from the most significant digit.
+ *
+ * Argument constraints:
+ * 1. 0 < CNT < BITS_PER_MP_LIMB
+ * 2. If the result is to be written over the input, WP must be >= UP.
+ */
+
+mpi_limb_t
+mpihelp_lshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
+ unsigned int cnt)
+{
+ mpi_limb_t high_limb, low_limb;
+ unsigned sh_1, sh_2;
+ mpi_size_t i;
+ mpi_limb_t retval;
+
+ sh_1 = cnt;
+ wp += 1;
+ sh_2 = BITS_PER_MPI_LIMB - sh_1;
+ i = usize - 1;
+ low_limb = up[i];
+ retval = low_limb >> sh_2;
+ high_limb = low_limb;
+ while( --i >= 0 ) {
+ low_limb = up[i];
+ wp[i] = (high_limb << sh_1) | (low_limb >> sh_2);
+ high_limb = low_limb;
+ }
+ wp[i] = high_limb << sh_1;
+
+ return retval;
+}
+
+
+/* Shift U (pointed to by UP and USIZE limbs long) CNT bits to the right
+ * and store the USIZE least significant limbs of the result at WP.
+ * The bits shifted out to the right are returned.
+ *
+ * Argument constraints:
+ * 1. 0 < CNT < BITS_PER_MP_LIMB
+ * 2. If the result is to be written over the input, WP must be <= UP.
+ */
+
+mpi_limb_t
+mpihelp_rshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned cnt)
+{
+ mpi_limb_t high_limb, low_limb;
+ unsigned sh_1, sh_2;
+ mpi_size_t i;
+ mpi_limb_t retval;
+
+ sh_1 = cnt;
+ wp -= 1;
+ sh_2 = BITS_PER_MPI_LIMB - sh_1;
+ high_limb = up[0];
+ retval = high_limb << sh_2;
+ low_limb = high_limb;
+ for( i=1; i < usize; i++) {
+ high_limb = up[i];
+ wp[i] = (low_limb >> sh_1) | (high_limb << sh_2);
+ low_limb = high_limb;
+ }
+ wp[i] = low_limb >> sh_1;
+
+ return retval;
+}
+
diff --git a/mpi/mpih-sub.c b/mpi/mpih-sub.c
new file mode 100644
index 000000000..3831d81c3
--- /dev/null
+++ b/mpi/mpih-sub.c
@@ -0,0 +1,106 @@
+/* mpihelp-sub.c - MPI helper functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mpi-internal.h"
+
+
+/*_EXTERN_INLINE*/
+mpi_limb_t
+mpihelp_sub_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_size_t s1_size, mpi_limb_t s2_limb )
+{
+ mpi_limb_t x;
+
+ x = *s1_ptr++;
+ s2_limb = x - s2_limb;
+ *res_ptr++ = s2_limb;
+ if( s2_limb > x ) {
+ while( --s1_size ) {
+ x = *s1_ptr++;
+ *res_ptr++ = x - 1;
+ if( x )
+ goto leave;
+ }
+ return 1;
+ }
+
+ leave:
+ if( res_ptr != s1_ptr ) {
+ mpi_size_t i;
+ for( i=0; i < s1_size-1; i++ )
+ res_ptr[i] = s1_ptr[i];
+ }
+ return 0;
+}
+
+
+/* FIXME: this should be done in assembly */
+mpi_limb_t
+mpihelp_sub_n( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+ mpi_ptr_t s2_ptr, mpi_size_t size)
+{
+ mpi_limb_t x, y, cy;
+ mpi_size_t j;
+
+ /* The loop counter and index J goes from -SIZE to -1. This way
+ the loop becomes faster. */
+ j = -size;
+
+ /* Offset the base pointers to compensate for the negative indices. */
+ s1_ptr -= j;
+ s2_ptr -= j;
+ res_ptr -= j;
+
+ cy = 0;
+ do {
+ y = s2_ptr[j];
+ x = s1_ptr[j];
+ y += cy; /* add previous carry to subtrahend */
+ cy = y < cy ? 1:0; /* get out carry from that addition */
+ y = x - y; /* main subtract */
+ cy += y > x? 1:0; /* get out carry from the subtract, combine */
+ res_ptr[j] = y;
+ } while( ++j );
+
+ return cy;
+}
+
+
+/*_EXTERN_INLINE*/
+mpi_limb_t
+mpihelp_sub( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
+ mpi_ptr_t s2_ptr, mpi_size_t s2_size)
+{
+ mpi_limb_t cy = 0;
+
+ if( s2_size )
+ cy = mpihelp_sub_n(res_ptr, s1_ptr, s2_ptr, s2_size);
+
+ if( s1_size - s2_size )
+ cy = mpihelp_sub_1(res_ptr + s2_size, s1_ptr + s2_size,
+ s1_size - s2_size, cy);
+ return cy;
+}
+
+
diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c
new file mode 100644
index 000000000..752ce7f84
--- /dev/null
+++ b/mpi/mpiutil.c
@@ -0,0 +1,326 @@
+/* mpiutil.c - Utility functions for MPI
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "mpi.h"
+#include "mpi-internal.h"
+#include "memory.h"
+#include "util.h"
+
+
+#ifdef M_DEBUG
+ #undef mpi_alloc
+ #undef mpi_alloc_secure
+ #undef mpi_free
+#endif
+
+typedef struct unused_obj {
+ struct unused_obj *next;
+ unsigned length;
+ union {
+ MPI mpi;
+ mpi_limb_t *limb;
+ } u;
+} *unused_obj_t;
+
+static unused_obj_t unused_objs;
+static unused_obj_t unused_mpis;
+static unused_obj_t unused_limbs;
+
+
+MPI
+#ifdef M_DEBUG
+mpi_debug_alloc( unsigned nlimbs, const char *info )
+#else
+mpi_alloc( unsigned nlimbs )
+#endif
+{
+ MPI a;
+
+ if( unused_mpis ) {
+ unused_obj_t u;
+
+ if( DBG_MEMORY )
+ log_debug("mpi_alloc(%lu) reusing\n", nlimbs*BITS_PER_MPI_LIMB );
+ a = unused_mpis->u.mpi;
+ u = unused_mpis;
+ unused_mpis = unused_mpis->next;
+ u->next = unused_objs;
+ unused_objs = u;
+ }
+ else {
+ if( DBG_MEMORY )
+ log_debug("mpi_alloc(%lu) new\n", nlimbs*BITS_PER_MPI_LIMB );
+ #ifdef M_DEBUG
+ a = m_debug_alloc( sizeof *a, info );
+ #else
+ a = m_alloc( sizeof *a );
+ #endif
+ }
+ #ifdef M_DEBUG
+ a->d = mpi_debug_alloc_limb_space( nlimbs, info );
+ #else
+ a->d = mpi_alloc_limb_space( nlimbs );
+ #endif
+ a->alloced = nlimbs;
+ a->nlimbs = 0;
+ a->sign = 0;
+ return a;
+}
+
+void
+mpi_m_check( MPI a )
+{
+ m_check(a);
+ m_check(a->d);
+}
+
+MPI
+#ifdef M_DEBUG
+mpi_debug_alloc_secure( unsigned nlimbs, const char *info )
+#else
+mpi_alloc_secure( unsigned nlimbs )
+#endif
+{
+ MPI a;
+
+ a = m_alloc( sizeof *a );
+ #ifdef M_DEBUG
+ a->d = m_debug_alloc_secure( nlimbs * sizeof(mpi_limb_t), info );
+ #else
+ a->d = m_alloc_secure( nlimbs * sizeof(mpi_limb_t) );
+ #endif
+ a->alloced = nlimbs;
+ a->nlimbs = 0;
+ a->sign = 0;
+ return a;
+}
+
+
+mpi_ptr_t
+#ifdef M_DEBUG
+mpi_debug_alloc_limb_space( unsigned nlimbs, const char *info )
+#else
+mpi_alloc_limb_space( unsigned nlimbs )
+#endif
+{
+ unused_obj_t u;
+ size_t len = nlimbs * sizeof(mpi_limb_t);
+
+ for(u=unused_limbs; u; u = u->next )
+ if( u->length >= len ) {
+ u->length = 0;
+ if( DBG_MEMORY )
+ log_debug("mpi_alloc_limb_space(%lu) reusing\n", len*8 );
+ return u->u.limb;
+ }
+ if( DBG_MEMORY )
+ log_debug("mpi_alloc_limb_space(%u) new\n", len*8 );
+ #ifdef M_DEBUG
+ return m_debug_alloc( len, info );
+ #else
+ return m_alloc( len );
+ #endif
+}
+
+void
+#ifdef M_DEBUG
+mpi_debug_free_limb_space( mpi_ptr_t a, const char *info )
+#else
+mpi_free_limb_space( mpi_ptr_t a )
+#endif
+{
+ unused_obj_t u;
+
+ if( !a )
+ return;
+ if( DBG_MEMORY )
+ log_debug("mpi_free_limb_space of size %lu\n", (ulong)m_size(a)*8 );
+ for(u=unused_limbs; u; u = u->next )
+ if( !u->length ) {
+ u->length = m_size(a);
+ u->u.limb = a;
+ return;
+ }
+
+ if( (u=unused_objs) )
+ unused_objs = unused_objs->next;
+ else
+ u = m_alloc( sizeof *u );
+ u->length = m_size(a);
+ u->u.limb = a;
+ u->next = unused_limbs;
+ unused_limbs = u;
+}
+
+
+void
+mpi_assign_limb_space( MPI a, mpi_ptr_t ap, unsigned nlimbs )
+{
+ mpi_free_limb_space(a->d);
+ a->d = ap;
+ a->alloced = nlimbs;
+}
+
+
+
+/****************
+ * Resize the array of A to NLIMBS. the additional space is cleared
+ * (set to 0) [done by m_realloc()]
+ */
+void
+#ifdef M_DEBUG
+mpi_debug_resize( MPI a, unsigned nlimbs, const char *info )
+#else
+mpi_resize( MPI a, unsigned nlimbs )
+#endif
+{
+ if( nlimbs <= a->alloced )
+ return; /* no need to do it */
+ #ifdef M_DEBUG
+ if( a->d )
+ a->d = m_debug_realloc(a->d, nlimbs * sizeof(mpi_limb_t), info );
+ else
+ a->d = m_debug_alloc_clear( nlimbs * sizeof(mpi_limb_t), info );
+ #else
+ if( a->d )
+ a->d = m_realloc(a->d, nlimbs * sizeof(mpi_limb_t) );
+ else
+ a->d = m_alloc_clear( nlimbs * sizeof(mpi_limb_t) );
+ #endif
+ a->alloced = nlimbs;
+}
+
+void
+mpi_clear( MPI a )
+{
+ a->nlimbs = 0;
+}
+
+
+void
+#ifdef M_DEBUG
+mpi_debug_free( MPI a, const char *info )
+#else
+mpi_free( MPI a )
+#endif
+{
+ unused_obj_t u;
+
+ if( !a )
+ return;
+ if( DBG_MEMORY )
+ log_debug("mpi_free\n" );
+ #ifdef M_DEBUG
+ mpi_debug_free_limb_space(a->d, info);
+ #else
+ mpi_free_limb_space(a->d);
+ #endif
+
+ if( (u=unused_objs) )
+ unused_objs = unused_objs->next;
+ else
+ u = m_alloc( sizeof *u );
+ u->u.mpi = a;
+ u->next = unused_mpis;
+ unused_mpis = u;
+}
+
+
+MPI
+#ifdef M_DEBUG
+mpi_debug_copy( MPI a, const char *info )
+#else
+mpi_copy( MPI a )
+#endif
+{
+ int i;
+ MPI b;
+
+ if( a ) {
+ #ifdef M_DEBUG
+ b = mpi_debug_alloc( a->nlimbs, info );
+ #else
+ b = mpi_alloc( a->nlimbs );
+ #endif
+ b->nlimbs = a->nlimbs;
+ for(i=0; i < b->nlimbs; i++ )
+ b->d[i] = a->d[i];
+ }
+ else
+ b = NULL;
+ return b;
+}
+
+
+void
+mpi_set( MPI w, MPI u)
+{
+ mpi_ptr_t wp, up;
+ mpi_size_t usize = u->nlimbs;
+ int usign = u->sign;
+
+ RESIZE_IF_NEEDED(w, usize);
+ wp = w->d;
+ up = u->d;
+ MPN_COPY( wp, up, usize );
+ w->nlimbs = usize;
+ w->sign = usign;
+}
+
+
+void
+mpi_set_ui( MPI w, unsigned long u)
+{
+ RESIZE_IF_NEEDED(w, 1);
+ w->d[0] = u;
+ w->nlimbs = u? 1:0;
+ w->sign = 0;
+}
+
+
+MPI
+mpi_alloc_set_ui( unsigned long u)
+{
+ #ifdef M_DEBUG
+ MPI w = mpi_debug_alloc(1,"alloc_set_ui");
+ #else
+ MPI w = mpi_alloc(1);
+ #endif
+ w->d[0] = u;
+ w->nlimbs = u? 1:0;
+ w->sign = 0;
+ return w;
+}
+
+
+void
+mpi_swap( MPI a, MPI b)
+{
+ MPI x;
+
+ x = a; a = b; b = x;
+}
+
+
diff --git a/scripts/install-sh b/scripts/install-sh
new file mode 100755
index 000000000..e8436696c
--- /dev/null
+++ b/scripts/install-sh
@@ -0,0 +1,250 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/scripts/mkinstalldirs b/scripts/mkinstalldirs
new file mode 100755
index 000000000..d0fd194fd
--- /dev/null
+++ b/scripts/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644
index 000000000..9788f7023
--- /dev/null
+++ b/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 000000000..a23b8d349
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,12 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/include
+
+bin_PROGRAMS = mpicalc
+
+mpicalc_SOURCES = mpicalc.c
+
+
+LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil
+
+
diff --git a/tools/Makefile.in b/tools/Makefile.in
new file mode 100644
index 000000000..b9f55a889
--- /dev/null
+++ b/tools/Makefile.in
@@ -0,0 +1,252 @@
+# Makefile.in generated automatically by automake 1.0 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+INCLUDES = -I$(top_srcdir)/include
+
+bin_PROGRAMS = mpicalc
+
+mpicalc_SOURCES = mpicalc.c
+
+LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil
+mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
+CONFIG_HEADER = ../config.h
+PROGRAMS = $(bin_PROGRAMS)
+
+
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+mpicalc_OBJECTS = mpicalc.o
+EXTRA_mpicalc_SOURCES =
+mpicalc_LDADD = $(LDADD)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA)
+DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA)
+
+TAR = tar
+DEP_FILES = $(srcdir)/.deps/mpicalc.P
+SOURCES = $(mpicalc_SOURCES)
+OBJECTS = $(mpicalc_OBJECTS)
+
+default: all
+
+
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+ cd $(top_srcdir) && automake $(subdir)/Makefile
+
+Makefile: $(top_builddir)/config.status Makefile.in
+ cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+ rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+ $(mkinstalldirs) $(bindir)
+ list="$(bin_PROGRAMS)"; for p in $$list; do \
+ if test -f $$p; then \
+ $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ list="$(bin_PROGRAMS)"; for p in $$list; do \
+ rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+.c.o:
+ $(COMPILE) $<
+
+mostlyclean-compile:
+ rm -f *.o core
+
+clean-compile:
+
+distclean-compile:
+ rm -f *.tab.c
+
+maintainer-clean-compile:
+$(mpicalc_OBJECTS): ../config.h
+
+mpicalc: $(mpicalc_OBJECTS) $(mpicalc_DEPENDENCIES)
+ $(LINK) $(mpicalc_OBJECTS) $(mpicalc_LDADD) $(LIBS)
+
+ID: $(HEADERS) $(SOURCES)
+ here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
+
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
+ here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ rm -f TAGS ID
+
+maintainer-clean-tags:
+
+subdir = tools
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+distdir: $(DEP_DISTFILES)
+ @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \
+ test -f $(distdir)/$$file \
+ || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $(srcdir)/$$file $(distdir)/$$file; \
+ done
+
+# This fragment is probably only useful for maintainers. It relies on
+# GNU make and gcc. It is only included in the generated Makefile.in
+# if `automake' is not passed the `--include-deps' flag.
+
+MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+-include $(srcdir)/.deps/.P
+$(srcdir)/.deps/.P: $(BUILT_SOURCES)
+ cd $(srcdir) && test -d .deps || mkdir .deps
+ echo > $@
+
+-include $(DEP_FILES)
+$(DEP_FILES): $(srcdir)/.deps/.P
+
+$(srcdir)/.deps/%.P: $(srcdir)/%.c
+ @echo "mkdeps $< > $@"
+ @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \
+ $(MKDEP) $< | sed "$$re" > $@-tmp
+ @if test -n "$o"; then \
+ sed 's/\.o:/$$o:/' $@-tmp > $@; \
+ rm $@-tmp; \
+ else \
+ mv $@-tmp $@; \
+ fi
+
+# End of maintainer-only section
+info:
+
+dvi:
+
+check: all
+
+installcheck:
+
+install-exec: install-binPROGRAMS
+
+install-data:
+
+install: install-exec install-data all
+ @:
+
+uninstall: uninstall-binPROGRAMS
+
+all: $(PROGRAMS) Makefile
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
+installdirs:
+ $(mkinstalldirs) $(bindir)
+
+
+mostlyclean-generic:
+ test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ rm -f Makefile $(DISTCLEANFILES)
+ rm -f config.cache config.log $(CONFIG_HEADER) stamp-h
+
+maintainer-clean-generic:
+ test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean: mostlyclean-binPROGRAMS mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+clean: clean-binPROGRAMS clean-compile clean-tags clean-generic \
+ mostlyclean
+
+distclean: distclean-binPROGRAMS distclean-compile distclean-tags \
+ distclean-generic clean
+ rm -f config.status
+
+maintainer-clean: maintainer-clean-binPROGRAMS maintainer-clean-compile \
+ maintainer-clean-tags maintainer-clean-generic \
+ distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: default mostlyclean-binPROGRAMS distclean-binPROGRAMS \
+clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \
+install-binPROGRAMS mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info dvi check installcheck \
+install-exec install-data install uninstall all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tools/bftest.c b/tools/bftest.c
new file mode 100644
index 000000000..bbfcd5dd1
--- /dev/null
+++ b/tools/bftest.c
@@ -0,0 +1,85 @@
+/* bftest.c - Blowfish test program
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "blowfish.h"
+
+static void
+my_usage(void)
+{
+ fprintf(stderr, "usage: bftest [-e][-d] key\n");
+ exit(1);
+}
+
+const char *
+strusage( int level )
+{
+ return default_strusage(level);
+}
+
+int
+main(int argc, char **argv)
+{
+ int encode=0;
+ BLOWFISH_context ctx;
+ char buf[100];
+ char iv[BLOWFISH_BLOCKSIZE];
+ int n, size=8;
+
+ if( argc > 1 && !strcmp(argv[1], "-e") ) {
+ encode++;
+ argc--; argv++;
+ }
+ else if( argc > 1 && !strcmp(argv[1], "-E") ) {
+ encode++;
+ argc--; argv++;
+ size = 10;
+ }
+ else if( argc > 1 && !strcmp(argv[1], "-d") ) {
+ argc--; argv++;
+ }
+ else if( argc > 1 && !strcmp(argv[1], "-D") ) {
+ argc--; argv++;
+ size = 10;
+ }
+ if( argc != 2 )
+ my_usage();
+ argc--; argv++;
+
+ blowfish_setkey( &ctx, *argv, strlen(*argv) );
+ memset(iv,0, BLOWFISH_BLOCKSIZE);
+ blowfish_setiv( &ctx, iv );
+ while( (n = fread( buf, 1, size, stdin )) > 0 ) {
+ if( encode )
+ blowfish_encode_cfb( &ctx, buf, buf, n );
+ else
+ blowfish_decode_cfb( &ctx, buf, buf, n );
+ if( fwrite( buf, 1, n, stdout) != n )
+ log_fatal("write error\n");
+ }
+
+ return 0;
+}
+
diff --git a/tools/mpicalc.c b/tools/mpicalc.c
new file mode 100644
index 000000000..2402695d7
--- /dev/null
+++ b/tools/mpicalc.c
@@ -0,0 +1,341 @@
+/* mpitest.c - test the mpi functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This is a RPN calculator; values must be given in hex.
+ * Operaion is like dc(1) except that the input/output radix is
+ * always 16 and you can use a '-' to prefix a negative number.
+ * Addition operators: ++ and --. All operators must be delimeted by a blank
+ *
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "util.h"
+#include "mpi.h"
+
+#define STACKSIZE 100
+static MPI stack[STACKSIZE];
+static int stackidx;
+
+
+const char *
+strusage( int level )
+{
+ const char *p;
+ switch( level ) {
+ case 10:
+ case 0: p = "mpicalc - v" VERSION "; "
+ "Copyright 1997 Werner Koch (dd9jn)" ; break;
+ case 13: p = "mpicalc"; break;
+ case 14: p = VERSION; break;
+ case 1:
+ case 11: p = "Usage: mpicalc (-h for help)";
+ break;
+ case 2:
+ case 12: p =
+ "\nSyntax: mpicalc [options] [files]\n"
+ "MPI RPN calculator\n";
+ break;
+ default: p = default_strusage(level);
+ }
+ return p;
+}
+
+
+static void
+do_add(void)
+{
+ if( stackidx < 2 ) {
+ fputs("stack underflow\n",stderr);
+ return;
+ }
+ mpi_add( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
+ stackidx--;
+}
+
+static void
+do_sub(void)
+{
+ if( stackidx < 2 ) {
+ fputs("stack underflow\n", stderr);
+ return;
+ }
+ mpi_sub( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
+ stackidx--;
+}
+
+static void
+do_inc(void)
+{
+ if( stackidx < 1 ) {
+ fputs("stack underflow\n", stderr);
+ return;
+ }
+ mpi_add_ui( stack[stackidx-1], stack[stackidx-1], 1 );
+}
+
+static void
+do_dec(void)
+{
+ if( stackidx < 1 ) {
+ fputs("stack underflow\n", stderr);
+ return;
+ }
+ /* mpi_sub_ui( stack[stackidx-1], stack[stackidx-1], 1 ); */
+}
+
+static void
+do_mul(void)
+{
+ if( stackidx < 2 ) {
+ fputs("stack underflow\n", stderr);
+ return;
+ }
+ mpi_mul( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
+ stackidx--;
+}
+
+static void
+do_div(void)
+{
+ if( stackidx < 2 ) {
+ fputs("stack underflow\n", stderr);
+ return;
+ }
+ mpi_fdiv_q( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
+ stackidx--;
+}
+
+static void
+do_rem(void)
+{
+ if( stackidx < 2 ) {
+ fputs("stack underflow\n", stderr);
+ return;
+ }
+ mpi_fdiv_r( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] );
+ stackidx--;
+}
+
+static void
+do_powm(void)
+{
+ MPI a;
+ if( stackidx < 3 ) {
+ fputs("stack underflow\n", stderr);
+ return;
+ }
+ a= mpi_alloc(10);
+ mpi_powm( a, stack[stackidx-3], stack[stackidx-2], stack[stackidx-1] );
+ mpi_free(stack[stackidx-3]);
+ stack[stackidx-3] = a;
+ stackidx -= 2;
+}
+
+static void
+do_inv(void)
+{
+ MPI a = mpi_alloc(40);
+ if( stackidx < 2 ) {
+ fputs("stack underflow\n", stderr);
+ return;
+ }
+ mpi_inv_mod( a, stack[stackidx-2], stack[stackidx-1] );
+ mpi_set(stack[stackidx-2],a);
+ mpi_free(a);
+ stackidx--;
+}
+
+static void
+do_gcd(void)
+{
+ MPI a = mpi_alloc(40);
+ if( stackidx < 2 ) {
+ fputs("stack underflow\n", stderr);
+ return;
+ }
+ mpi_gcd( a, stack[stackidx-2], stack[stackidx-1] );
+ mpi_set(stack[stackidx-2],a);
+ mpi_free(a);
+ stackidx--;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ static ARGPARSE_OPTS opts[] = {
+ {0} };
+ ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
+ int i, c;
+ int state = 0;
+ char strbuf[1000];
+ int stridx=0;
+
+ while( arg_parse( &pargs, opts) ) {
+ switch( pargs.r_opt ) {
+ default : pargs.err = 2; break;
+ }
+ }
+ if( argc )
+ usage(1);
+
+
+ for(i=0; i < STACKSIZE; i++ )
+ stack[i] = NULL;
+ stackidx =0;
+
+ while( (c=getc(stdin)) != EOF ) {
+ if( !state ) { /* waiting */
+ if( isdigit(c) || (c >='A' && c <= 'F') ) {
+ state = 1;
+ ungetc(c, stdin);
+ strbuf[0] = '0';
+ strbuf[1] = 'x';
+ stridx=2;
+ }
+ else if( isspace(c) )
+ ;
+ else {
+ switch(c) {
+ case '+':
+ if( (c=getc(stdin)) == '+' )
+ do_inc();
+ else {
+ ungetc(c, stdin);
+ do_add();
+ }
+ break;
+ case '-':
+ if( (c=getc(stdin)) == '-' )
+ do_dec();
+ else if( isdigit(c) || (c >='A' && c <= 'F') ) {
+ state = 1;
+ ungetc(c, stdin);
+ strbuf[0] = '-';
+ strbuf[1] = '0';
+ strbuf[2] = 'x';
+ stridx=3;
+ }
+ else {
+ ungetc(c, stdin);
+ do_sub();
+ }
+ break;
+ case '*':
+ do_mul();
+ break;
+ case '/':
+ do_div();
+ break;
+ case '%':
+ do_rem();
+ break;
+ case '^':
+ do_powm();
+ break;
+ case 'I':
+ do_inv();
+ break;
+ case 'G':
+ do_gcd();
+ break;
+ case 'i': /* dummy */
+ if( !stackidx )
+ fputs("stack underflow\n", stderr);
+ else {
+ mpi_free(stack[stackidx-1]);
+ stackidx--;
+ }
+ break;
+ case 'd': /* duplicate the tos */
+ if( !stackidx )
+ fputs("stack underflow\n", stderr);
+ else if( stackidx < STACKSIZE ) {
+ mpi_free(stack[stackidx]);
+ stack[stackidx] = mpi_copy( stack[stackidx-1] );
+ stackidx++;
+ }
+ else
+ fputs("stack overflow\n", stderr);
+ break;
+ case 'c':
+ for(i=0; i < stackidx; i++ )
+ mpi_free(stack[i]), stack[i] = NULL;
+ stackidx = 0;
+ break;
+ case 'p': /* print the tos */
+ if( !stackidx )
+ puts("stack is empty");
+ else {
+ mpi_print(stdout, stack[stackidx-1], 1 );
+ putchar('\n');
+ }
+ break;
+ case 'f': /* print the stack */
+ for( i = stackidx-1 ; i >= 0; i-- ) {
+ printf("[%2d]: ", i );
+ mpi_print(stdout, stack[i], 1 );
+ putchar('\n');
+ }
+ break;
+ default:
+ fputs("invalid operator\n", stderr);
+ }
+ }
+ }
+ else if( state == 1 ) { /* in a number */
+ if( !(isdigit(c) || (c >='A' && c <= 'F')) ) { /* store the number */
+ state = 0;
+ ungetc(c, stdin);
+ if( stridx < 1000 )
+ strbuf[stridx] = 0;
+
+ if( stackidx < STACKSIZE ) {
+ if( !stack[stackidx] )
+ stack[stackidx] = mpi_alloc(10);
+ if( mpi_fromstr(stack[stackidx], strbuf) )
+ fputs("invalid number\n", stderr);
+ else
+ stackidx++;
+ }
+ else
+ fputs("stack overflow\n", stderr);
+ }
+ else { /* store digit */
+ if( stridx < 999 )
+ strbuf[stridx++] = c;
+ else if( stridx == 999 ) {
+ strbuf[stridx] = 0;
+ fputs("string too large - truncated\n", stderr);
+ stridx++;
+ }
+ }
+ }
+
+ }
+ for(i=0; i < stackidx; i++ )
+ mpi_free(stack[i]);
+ return 0;
+}
+
+
diff --git a/tools/primes.scm b/tools/primes.scm
new file mode 100644
index 000000000..0772cdcf9
--- /dev/null
+++ b/tools/primes.scm
@@ -0,0 +1,31 @@
+(define (prime? n)
+ (define (smallest-divisor n)
+ (find-divisor n 2))
+ (define (find-divisor n test)
+ (cond ((> (square test) n) n)
+ ((divides? test n) test)
+ (else (find-divisor n (+ test 1)))))
+ (define (divides? a b)
+ (= (remainder b a) 0))
+ (define (square n)
+ (* n n))
+ (= n (smallest-divisor n)))
+
+(define count 0)
+
+
+
+(define (display-prime n)
+ (display n)
+ (display ", ")
+ (cond ((> count 8) (display "\n") (let count 0))
+ (else (define count (+ count 1)))))
+
+
+(define (primes n limit)
+ (if (prime? n)
+ (display-prime n) )
+ (if (< n limit)
+ (primes (+ n 1) limit)) )
+
+(primes 3 5000)
diff --git a/util/Makefile.am b/util/Makefile.am
new file mode 100644
index 000000000..5fd3e59ca
--- /dev/null
+++ b/util/Makefile.am
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LIBRARIES = util
+
+
+util_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \
+ ttyio.c argparse.c memory.c errors.c iobuf.c
+
+
+
+
diff --git a/util/Makefile.in b/util/Makefile.in
new file mode 100644
index 000000000..ca24380d6
--- /dev/null
+++ b/util/Makefile.in
@@ -0,0 +1,248 @@
+# Makefile.in generated automatically by automake 1.0 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LIBRARIES = util
+
+util_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \
+ ttyio.c argparse.c memory.c errors.c iobuf.c
+mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
+CONFIG_HEADER = ../config.h
+LIBRARIES = $(noinst_LIBRARIES)
+
+noinst_LIBFILES = libutil.a
+
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+util_LIBADD =
+util_OBJECTS = logger.o fileutil.o miscutil.o strgutil.o ttyio.o \
+argparse.o memory.o errors.o iobuf.o
+EXTRA_util_SOURCES =
+LIBFILES = libutil.a
+AR = ar
+RANLIB = @RANLIB@
+DIST_COMMON = Makefile.am Makefile.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA)
+DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA)
+
+TAR = tar
+DEP_FILES = $(srcdir)/.deps/argparse.P $(srcdir)/.deps/errors.P \
+$(srcdir)/.deps/fileutil.P $(srcdir)/.deps/iobuf.P \
+$(srcdir)/.deps/logger.P $(srcdir)/.deps/memory.P \
+$(srcdir)/.deps/miscutil.P $(srcdir)/.deps/strgutil.P \
+$(srcdir)/.deps/ttyio.P
+SOURCES = $(util_SOURCES)
+OBJECTS = $(util_OBJECTS)
+
+default: all
+
+
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+ cd $(top_srcdir) && automake $(subdir)/Makefile
+
+Makefile: $(top_builddir)/config.status Makefile.in
+ cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+ rm -f $(noinst_LIBFILES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+ $(COMPILE) $<
+
+mostlyclean-compile:
+ rm -f *.o core
+
+clean-compile:
+
+distclean-compile:
+ rm -f *.tab.c
+
+maintainer-clean-compile:
+$(util_OBJECTS): ../config.h
+
+libutil.a: $(util_OBJECTS) $(util_LIBADD)
+ rm -f libutil.a
+ $(AR) cru libutil.a $(util_OBJECTS) $(util_LIBADD)
+ $(RANLIB) libutil.a
+
+ID: $(HEADERS) $(SOURCES)
+ here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
+
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
+ here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ rm -f TAGS ID
+
+maintainer-clean-tags:
+
+subdir = util
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+distdir: $(DEP_DISTFILES)
+ @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \
+ test -f $(distdir)/$$file \
+ || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $(srcdir)/$$file $(distdir)/$$file; \
+ done
+
+# This fragment is probably only useful for maintainers. It relies on
+# GNU make and gcc. It is only included in the generated Makefile.in
+# if `automake' is not passed the `--include-deps' flag.
+
+MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+-include $(srcdir)/.deps/.P
+$(srcdir)/.deps/.P: $(BUILT_SOURCES)
+ cd $(srcdir) && test -d .deps || mkdir .deps
+ echo > $@
+
+-include $(DEP_FILES)
+$(DEP_FILES): $(srcdir)/.deps/.P
+
+$(srcdir)/.deps/%.P: $(srcdir)/%.c
+ @echo "mkdeps $< > $@"
+ @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \
+ $(MKDEP) $< | sed "$$re" > $@-tmp
+ @if test -n "$o"; then \
+ sed 's/\.o:/$$o:/' $@-tmp > $@; \
+ rm $@-tmp; \
+ else \
+ mv $@-tmp $@; \
+ fi
+
+# End of maintainer-only section
+info:
+
+dvi:
+
+check: all
+
+installcheck:
+
+install-exec:
+
+install-data:
+
+install: install-exec install-data all
+ @:
+
+uninstall:
+
+all: $(LIBFILES) Makefile
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
+installdirs:
+
+
+mostlyclean-generic:
+ test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ rm -f Makefile $(DISTCLEANFILES)
+ rm -f config.cache config.log $(CONFIG_HEADER) stamp-h
+
+maintainer-clean-generic:
+ test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+ mostlyclean
+
+distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \
+ distclean-generic clean
+ rm -f config.status
+
+maintainer-clean: maintainer-clean-noinstLIBRARIES \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info dvi check installcheck \
+install-exec install-data install uninstall all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/util/argparse.c b/util/argparse.c
new file mode 100644
index 000000000..3d51d014c
--- /dev/null
+++ b/util/argparse.c
@@ -0,0 +1,653 @@
+/* [argparse.c wk 17.06.97] Argument Parser for option handling
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ * This file is part of WkLib.
+ *
+ * WkLib 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.
+ *
+ * WkLib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ *
+ * Note: This is an independent version of the one in WkLib
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+
+#ifdef DOCUMENTATION
+@Summary arg_parse
+ #include <wk/lib.h>
+
+ typedef struct {
+ char *argc; /* pointer to argc (value subject to change) */
+ char ***argv; /* pointer to argv (value subject to change) */
+ unsigned flags; /* Global flags (DO NOT CHANGE) */
+ int err; /* print error about last option */
+ /* 1 = warning, 2 = abort */
+ int r_opt; /* return option */
+ int r_type; /* type of return value (0 = no argument found)*/
+ union {
+ int ret_int;
+ long ret_long
+ ulong ret_ulong;
+ char *ret_str;
+ } r; /* Return values */
+ struct {
+ int index;
+ const char *last;
+ } internal; /* DO NOT CHANGE */
+ } ARGPARSE_ARGS;
+
+ typedef struct {
+ int short_opt;
+ const char *long_opt;
+ unsigned flags;
+ } ARGPARSE_OPTS;
+
+ int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
+
+@Description
+ This is my replacement for getopt(). See the example for a typical usage.
+ Global flags are:
+ Bit 0 : Do not remove options form argv
+ Bit 1 : Do not stop at last option but return other args
+ with r_opt set to -1.
+ Bit 2 : Assume options and real args are mixed.
+ Bit 3 : Do not use -- to stop option processing.
+ Bit 4 : Do not skip the first arg.
+ Bit 5 : allow usage of long option with only one dash
+ all other bits must be set to zero, this value is modified by the function
+ so assume this is write only.
+ Local flags (for each option):
+ Bit 2-0 : 0 = does not take an argument
+ 1 = takes int argument
+ 2 = takes string argument
+ 3 = takes long argument
+ 4 = takes ulong argument
+ Bit 3 : argument is optional (r_type will the be set to 0)
+ Bit 4 : allow 0x etc. prefixed values.
+ If can stop the option processing by setting opts to NULL, the function will
+ then return 0.
+@Return Value
+ Returns the args.r_opt or 0 if ready
+ r_opt may be -2 to indicate an unknown option.
+@See Also
+ ArgExpand
+@Notes
+ You do not need to process the options 'h', '--help' or '--version'
+ because this function includes standard help processing; but if you
+ specify '-h', '--help' or '--version' you have to do it yourself.
+ The option '--' stops argument processing; if bit 1 is set the function
+ continues to return normal arguments.
+ To process float args or unsigned args you must use a string args and do
+ the conversion yourself.
+@Example
+
+ ARGPARSE_OPTS opts[] = {
+ { 'v', "verbose", 0 },
+ { 'd', "debug", 0 },
+ { 'o', "output", 2 },
+ { 'c', "cross-ref", 2|8 },
+ { 'm', "my-option", 1|8 },
+ { 500, "have-no-short-option-for-this-long-option", 0 },
+ {0} };
+ ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
+
+ while( ArgParse( &pargs, &opts) ) {
+ switch( pargs.r_opt ) {
+ case 'v': opt.verbose++; break;
+ case 'd': opt.debug++; break;
+ case 'o': opt.outfile = pargs.r.ret_str; break;
+ case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
+ case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
+ case 500: opt.a_long_one++; break
+ default : pargs.err = 1; break; /* force warning output */
+ }
+ }
+ if( argc > 1 )
+ log_fatal( "Too many args");
+
+#endif /*DOCUMENTATION*/
+
+
+
+static void set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
+static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
+static void show_version(void);
+
+
+int
+arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+ int index;
+ int argc;
+ char **argv;
+ char *s, *s2;
+ int i;
+
+ if( !(arg->flags & (1<<15)) ) { /* initialize this instance */
+ arg->internal.index = 0;
+ arg->internal.last = NULL;
+ arg->internal.inarg = 0;
+ arg->internal.stopped= 0;
+ arg->err = 0;
+ arg->flags |= 1<<15; /* mark initialized */
+ if( *arg->argc < 0 )
+ log_bug("Invalid argument for ArgParse\n");
+ }
+ argc = *arg->argc;
+ argv = *arg->argv;
+ index = arg->internal.index;
+
+ if( arg->err ) { /* last option was erroneous */
+ if( arg->r_opt == -3 )
+ s = "Missing argument for option \"%.50s\"\n";
+ else
+ s = "Invalid option \"%.50s\"\n";
+ log_error(s, arg->internal.last? arg->internal.last:"[??]" );
+ if( arg->err != 1 )
+ exit(2);
+ arg->err = 0;
+ }
+
+ if( !index && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */
+ argc--; argv++; index++;
+ }
+
+ next_one:
+ if( !argc ) { /* no more args */
+ arg->r_opt = 0;
+ goto leave; /* ready */
+ }
+
+ s = *argv;
+ arg->internal.last = s;
+
+ if( arg->internal.stopped && (arg->flags & (1<<1)) ) {
+ arg->r_opt = -1; /* not an option but a argument */
+ arg->r_type = 2;
+ arg->r.ret_str = s;
+ argc--; argv++; index++; /* set to next one */
+ }
+ else if( arg->internal.stopped ) { /* ready */
+ arg->r_opt = 0;
+ goto leave;
+ }
+ else if( *s == '-' && s[1] == '-' ) { /* long option */
+ arg->internal.inarg = 0;
+ if( !s[2] && !(arg->flags & (1<<3)) ) { /* stop option processing */
+ arg->internal.stopped = 1;
+ argc--; argv++; index++;
+ goto next_one;
+ }
+
+ for(i=0; opts[i].short_opt; i++ )
+ if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+2) )
+ break;
+
+ if( !opts[i].short_opt && !strcmp( "help", s+2) )
+ show_help(opts, arg->flags);
+ else if( !opts[i].short_opt && !strcmp( "version", s+2) )
+ show_version();
+ else if( !opts[i].short_opt && !strcmp( "warranty", s+2) ) {
+ puts( strusage(10) );
+ puts( strusage(31) );
+ exit(0);
+ }
+
+ arg->r_opt = opts[i].short_opt;
+ if( !opts[i].short_opt ) {
+ arg->r_opt = -2; /* unknown option */
+ arg->r.ret_str = s+2;
+ }
+ else if( (opts[i].flags & 7) ) {
+ s2 = argv[1];
+ if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
+ arg->r_type = 0; /* because it is optional */
+ }
+ else if( !s2 ) {
+ arg->r_opt = -3; /* missing argument */
+ }
+ else if( *s2 == '-' && (opts[i].flags & 8) ) {
+ /* the argument is optional and the next seems to be
+ * an option. We do not check this possible option
+ * but assume no argument */
+ arg->r_type = 0;
+ }
+ else {
+ set_opt_arg(arg, opts[i].flags, s2);
+ argc--; argv++; index++; /* skip one */
+ }
+ }
+ else { /* does not take an argument */
+ arg->r_type = 0;
+ }
+ argc--; argv++; index++; /* set to next one */
+ }
+ else if( (*s == '-' && s[1]) || arg->internal.inarg ) { /* short option */
+ int dash_kludge = 0;
+ i = 0;
+ if( !arg->internal.inarg ) {
+ arg->internal.inarg++;
+ if( arg->flags & (1<<5) ) {
+ for(i=0; opts[i].short_opt; i++ )
+ if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+1)) {
+ dash_kludge=1;
+ break;
+ }
+ }
+ }
+ s += arg->internal.inarg;
+
+ if( !dash_kludge ) {
+ for(i=0; opts[i].short_opt; i++ )
+ if( opts[i].short_opt == *s )
+ break;
+ }
+
+ if( !opts[i].short_opt && *s == 'h' )
+ show_help(opts, arg->flags);
+
+ arg->r_opt = opts[i].short_opt;
+ if( !opts[i].short_opt ) {
+ arg->r_opt = -2; /* unknown option */
+ arg->internal.inarg++; /* point to the next arg */
+ arg->r.ret_str = s;
+ }
+ else if( (opts[i].flags & 7) ) {
+ if( s[1] && !dash_kludge ) {
+ s2 = s+1;
+ set_opt_arg(arg, opts[i].flags, s2);
+ }
+ else {
+ s2 = argv[1];
+ if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
+ arg->r_type = 0; /* because it is optional */
+ }
+ else if( !s2 ) {
+ arg->r_opt = -3; /* missing argument */
+ }
+ else if( *s2 == '-' && s2[1] && (opts[i].flags & 8) ) {
+ /* the argument is optional and the next seems to be
+ * an option. We do not check this possible option
+ * but assume no argument */
+ arg->r_type = 0;
+ }
+ else {
+ set_opt_arg(arg, opts[i].flags, s2);
+ argc--; argv++; index++; /* skip one */
+ }
+ }
+ s = "x"; /* so that !s[1] yields false */
+ }
+ else { /* does not take an argument */
+ arg->r_type = 0;
+ arg->internal.inarg++; /* point to the next arg */
+ }
+ if( !s[1] || dash_kludge ) { /* no more concatenated short options */
+ arg->internal.inarg = 0;
+ argc--; argv++; index++;
+ }
+ }
+ else if( arg->flags & (1<<2) ) {
+ arg->r_opt = -1; /* not an option but a argument */
+ arg->r_type = 2;
+ arg->r.ret_str = s;
+ argc--; argv++; index++; /* set to next one */
+ }
+ else {
+ arg->internal.stopped = 1; /* stop option processing */
+ goto next_one;
+ }
+
+ leave:
+ *arg->argc = argc;
+ *arg->argv = argv;
+ arg->internal.index = index;
+ return arg->r_opt;
+}
+
+
+
+static void
+set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
+{
+ int base = (flags & 16)? 0 : 10;
+
+ switch( arg->r_type = (flags & 7) ) {
+ case 1: /* takes int argument */
+ arg->r.ret_int = (int)strtol(s,NULL,base);
+ break;
+ default:
+ case 2: /* takes string argument */
+ arg->r.ret_str = s;
+ break;
+ case 3: /* takes long argument */
+ arg->r.ret_long= strtol(s,NULL,base);
+ break;
+ case 4: /* takes ulong argument */
+ arg->r.ret_ulong= strtoul(s,NULL,base);
+ break;
+ }
+}
+
+static void
+show_help( ARGPARSE_OPTS *opts, unsigned flags )
+{
+ const char *s;
+
+ puts( strusage(10) );
+ s = strusage(12);
+ if( *s == '\n' )
+ s++;
+ puts(s);
+ if( opts[0].description ) { /* auto format the option description */
+ int i,j, indent;
+ /* get max. length of long options */
+ for(i=indent=0; opts[i].short_opt; i++ ) {
+ if( opts[i].long_opt )
+ if( (j=strlen(opts[i].long_opt)) > indent && j < 35 )
+ indent = j;
+ }
+ /* example: " -v, --verbose Viele Sachen ausgeben" */
+ indent += 10;
+ puts("Options:");
+ for(i=0; opts[i].short_opt; i++ ) {
+ if( opts[i].short_opt < 256 )
+ printf(" -%c", opts[i].short_opt );
+ else
+ fputs(" ", stdout);
+ j = 3;
+ if( opts[i].long_opt )
+ j += printf("%c --%s ", opts[i].short_opt < 256?',':' ',
+ opts[i].long_opt );
+ for(;j < indent; j++ )
+ putchar(' ');
+ if( (s = opts[i].description) ) {
+ for(; *s; s++ ) {
+ if( *s == '\n' ) {
+ if( s[1] ) {
+ putchar('\n');
+ for(j=0;j < indent; j++ )
+ putchar(' ');
+ }
+ }
+ else
+ putchar(*s);
+ }
+ }
+ putchar('\n');
+ }
+ if( flags & 32 )
+ puts("\n(A single dash may be used instead of the double ones)");
+ }
+ fflush(stdout);
+ exit(0);
+}
+
+static void
+show_version()
+{
+ const char *s;
+ printf("%s version %s (%s", strusage(13), strusage(14), strusage(45) );
+ if( (s = strusage(24)) && *s ) {
+ #ifdef DEBUG
+ printf(", %s, dbg)\n", s);
+ #else
+ printf(", %s)\n", s);
+ #endif
+ }
+ else {
+ #ifdef DEBUG
+ printf(", dbg)\n");
+ #else
+ printf(")\n");
+ #endif
+ }
+ fflush(stdout);
+ exit(0);
+}
+
+
+
+void
+usage( int level )
+{
+ static int sentinel=0;
+
+ if( sentinel )
+ return;
+
+ sentinel++;
+ if( !level ) {
+ fputs( strusage(level), stderr ); putc( '\n', stderr );
+ fputs( strusage(31), stderr);
+ #if DEBUG
+ fprintf(stderr, "%s (%s - Debug)\n", strusage(32), strusage(24) );
+ #else
+ fprintf(stderr, "%s (%s)\n", strusage(32), strusage(24) );
+ #endif
+ fflush(stderr);
+ }
+ else if( level == 1 ) {
+ fputs(strusage(level),stderr);putc('\n',stderr);
+ exit(2);}
+ else if( level == 2 ) {
+ puts(strusage(level)); exit(0);}
+ sentinel--;
+}
+
+
+const char *
+default_strusage( int level )
+{
+ const char *p;
+ switch( level ) {
+ case 0: p = strusage(10); break;
+ case 1: p = strusage(11); break;
+ case 2: p = strusage(12); break;
+ case 10: p = "WkLib"
+ #if DOS386 && __WATCOMC__
+ " (DOS4G)"
+ #elif DOS386
+ " (DOSX)"
+ #elif DOS16RM
+ " (DOS16RM)"
+ #elif M_I86VM
+ " (VCM)"
+ #elif UNIX || POSIX
+ " (Posix)"
+ #elif OS2
+ " (OS/2)"
+ #elif WINNT && __CYGWIN32__
+ " (CygWin)"
+ #elif WINNT
+ " (WinNT)"
+ #elif NETWARE
+ " (Netware)"
+ #elif VMS
+ " (VMS)"
+ #endif
+ "; Copyright (c) 1997 by Werner Koch (dd9jn)" ; break;
+ case 11: p = "usage: ?"; break;
+ case 16:
+ case 15: p = "[Untitled]"; break;
+ case 23: p = "[unknown]"; break;
+ case 24: p = ""; break;
+ case 12: p =
+ "This is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n\n"
+ "WkLib is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,"
+ " USA.\n" ;
+ break;
+ case 22:
+ #if MSDOS
+ #if USE_EMS
+ p = "MSDOS+EMS";
+ #else
+ p = "MSDOS";
+ #endif
+ #elif OS2
+ p = "OS/2";
+ #elif WINNT && __CYGWIN32__
+ p = "CygWin";
+ #elif WINNT
+ p = "WinNT";
+ #elif DOS386
+ p = "DOS386";
+ #elif EMX
+ p = "EMX";
+ #elif DOS16RM
+ p = "DOS16RM";
+ #elif NETWARE
+ p = "Netware";
+ #elif __linux__
+ p = "Linux";
+ #elif UNIX || M_UNIX || M_XENIX
+ p = "UNIX";
+ #elif VMS
+ p = "VMS";
+ #else
+ p = "UnknownOS";
+ #endif
+ break;
+ case 31: p =
+ "This program comes with ABSOLUTELY NO WARRANTY.\n"
+ "This is free software, and you are welcome to redistribute it\n"
+ "under certain conditions. See the file COPYING for details.\n";
+ break;
+ case 32: p = "["
+ #if MSDOS
+ "MSDOS Version"
+ #elif DOS386 && __ZTC__
+ "32-Bit MSDOS Version (Zortech's DOSX)"
+ #elif DOS386
+ "32-Bit MSDOS Version"
+ #elif OS20 && EMX
+ "OS/2 2.x EMX Version"
+ #elif OS20
+ "OS/2 2.x Version"
+ #elif OS2
+ "OS/2 1.x Version"
+ #elif WINNT && __CYGWIN32__
+ "Cygnus WinAPI Version"
+ #elif WINNT
+ "Windoze NT Version"
+ #elif EMX
+ "EMX Version"
+ #elif NETWARE
+ "NLM Version"
+ #elif DOS16RM
+ "DOS16RM Version"
+ #elif __linux__
+ "Linux Version"
+ #elif VMS
+ "OpenVMS Version"
+ #elif POSIX
+ "POSIX Version"
+ #elif M_UNIX || M_XENIX
+ "*IX Version"
+ #endif
+ "]";
+ break;
+ case 33: p =
+ #ifdef MULTI_THREADED
+ "mt"
+ #else
+ ""
+ #endif
+ ; break;
+ case 42:
+ case 43:
+ case 44:
+ case 45: p = ""; break;
+ default: p = "?";
+ }
+
+ return p;
+}
+
+
+
+#ifdef TEST
+static struct {
+ int verbose;
+ int debug;
+ char *outfile;
+ char *crf;
+ int myopt;
+ int echo;
+ int a_long_one;
+}opt;
+
+int
+main(int argc, char **argv)
+{
+ ARGPARSE_OPTS opts[] = {
+ { 'v', "verbose", 0 , "Laut sein"},
+ { 'e', "echo" , 0 , "Zeile ausgeben, damit wir sehen, was wir einegegeben haben"},
+ { 'd', "debug", 0 , "Debug\nfalls mal etasws\nSchief geht"},
+ { 'o', "output", 2 },
+ { 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" },
+ { 'm', "my-option", 1|8 },
+ { 500, "a-long-option", 0 },
+ {0} };
+ ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 };
+ int i;
+
+ while( ArgParse( &pargs, opts) ) {
+ switch( pargs.r_opt ) {
+ case -1 : printf( "arg='%s'\n", pargs.r.ret_str); break;
+ case 'v': opt.verbose++; break;
+ case 'e': opt.echo++; break;
+ case 'd': opt.debug++; break;
+ case 'o': opt.outfile = pargs.r.ret_str; break;
+ case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
+ case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
+ case 500: opt.a_long_one++; break;
+ default : pargs.err = 1; break; /* force warning output */
+ }
+ }
+ for(i=0; i < argc; i++ )
+ printf("%3d -> (%s)\n", i, argv[i] );
+ puts("Options:");
+ if( opt.verbose )
+ printf(" verbose=%d\n", opt.verbose );
+ if( opt.debug )
+ printf(" debug=%d\n", opt.debug );
+ if( opt.outfile )
+ printf(" outfile='%s'\n", opt.outfile );
+ if( opt.crf )
+ printf(" crffile='%s'\n", opt.crf );
+ if( opt.myopt )
+ printf(" myopt=%d\n", opt.myopt );
+ if( opt.a_long_one )
+ printf(" a-long-one=%d\n", opt.a_long_one );
+ if( opt.echo )
+ printf(" echo=%d\n", opt.echo );
+ return 0;
+}
+#endif
+
+/**** bottom of file ****/
diff --git a/util/errors.c b/util/errors.c
new file mode 100644
index 000000000..1e4579fc4
--- /dev/null
+++ b/util/errors.c
@@ -0,0 +1,69 @@
+/* errors.c - error strings
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "errors.h"
+
+const char *
+g10_errstr( int err )
+{
+ static char buf[50];
+ const char *p;
+
+ #define X(n,s) case G10ERR_##n : p = s; break;
+ switch( err ) {
+ X(GENERAL, "General error")
+ X(UNKNOWN_PACKET, "Unknown packet type")
+ X(UNKNOWN_VERSION,"Unknown version")
+ X(PUBKEY_ALGO ,"Unknown pubkey algorithm")
+ X(DIGEST_ALGO ,"Unknown digest algorithm")
+ X(BAD_PUBKEY ,"Bad public key")
+ X(BAD_SECKEY ,"Bad secret key")
+ X(BAD_SIGN ,"Bad signature")
+ X(CHECKSUM , "Checksum error")
+ X(BAD_PASS , "Bad passphrase")
+ X(NO_PUBKEY ,"Public key not found")
+ X(CIPHER_ALGO ,"Unknown cipher algorithm")
+ X(KEYRING_OPEN ,"Can't open the keyring")
+ X(BAD_RING ,"Broken keyring")
+ X(NO_USER_ID ,"No such user id found")
+ X(NO_SECKEY ,"Secret key not available")
+ X(WRONG_SECKEY ,"Wrong secret key used")
+ X(UNSUPPORTED ,"Not supported")
+ X(BAD_KEY ,"Bad key")
+ X(READ_FILE ,"File read error")
+ X(WRITE_FILE ,"File write error")
+ X(COMPR_ALGO ,"Unknown compress algorithm")
+ X(OPEN_FILE ,"File open error")
+ X(CREATE_FILE ,"File create error")
+ X(PASSPHRASE ,"Invalid passphrase")
+ X(NI_PUBKEY ,"Unimplemented pubkey algorithm")
+ X(NI_CIPHER ,"Unimplemented cipher algorithm")
+
+ default: p = buf; sprintf(buf, "Error code %d", err); break;
+ }
+ #undef X
+ return p;
+}
+
diff --git a/util/fileutil.c b/util/fileutil.c
new file mode 100644
index 000000000..e2ea9b20e
--- /dev/null
+++ b/util/fileutil.c
@@ -0,0 +1,31 @@
+/* fileutil.c - file utilities
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include "util.h"
+#include "memory.h"
+#include "ttyio.h"
+
+
diff --git a/util/iobuf.c b/util/iobuf.c
new file mode 100644
index 000000000..12fc74ff6
--- /dev/null
+++ b/util/iobuf.c
@@ -0,0 +1,762 @@
+/* iobuf.c - file handling
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "memory.h"
+#include "util.h"
+#include "iobuf.h"
+
+typedef struct {
+ FILE *fp; /* open file handle */
+ char fname[1]; /* name of the file */
+} file_filter_ctx_t ;
+
+typedef struct {
+ int usage;
+ size_t size;
+ size_t count;
+ int eof;
+} block_filter_ctx_t;
+
+static int underflow(IOBUF a);
+
+/****************
+ * Read data from a file into buf which has an allocated length of *LEN.
+ * return the number of read bytes in *LEN. OPAQUE is the FILE * of
+ * the stream. A is not used.
+ * control maybe:
+ * IOBUFCTRL_INIT: called just before the function is linked into the
+ * list of function. This can be used to prepare internal
+ * data structures of the function.
+ * IOBUFCTRL_FREE: called just before the function is removed from the
+ * list of functions and can be used to release internal
+ * data structures or close a file etc.
+ * IOBUFCTRL_UNDERFLOW: called by iobuf_underflow to fill the buffer
+ * with new stuff. *RET_LEN is the available size of the
+ * buffer, and should be set to the number of bytes
+ * which were put into the buffer. The function
+ * returns 0 to indicate success, -1 on EOF and
+ * G10ERR_xxxxx for other errors.
+ *
+ * IOBUFCTRL_FLUSH: called by iobuf_flush() to write out the collected stuff.
+ * *RET_LAN is the number of bytes in BUF.
+ *
+ */
+static int
+file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
+{
+ file_filter_ctx_t *a = opaque;
+ FILE *fp = a->fp;
+ size_t size = *ret_len;
+ size_t nbytes = 0;
+ int c, rc = 0;
+ char *p;
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ assert( size ); /* need a buffer */
+ for(; size; size-- ) {
+ if( (c=getc(fp)) == EOF ) {
+ if( ferror(fp) ) {
+ log_error("%s: read error: %s\n",
+ a->fname, strerror(errno));
+ rc = G10ERR_READ_FILE;
+ }
+ else if( !nbytes )
+ rc = -1; /* okay: we can return EOF now. */
+ break;
+ }
+ buf[nbytes++] = c & 0xff;
+ }
+ *ret_len = nbytes;
+ }
+ else if( control == IOBUFCTRL_FLUSH ) {
+ for(p=buf; nbytes < size; nbytes++, p++ ) {
+ if( putc(*p, fp) == EOF ) {
+ log_error("%s: write error: %s\n",
+ a->fname, strerror(errno));
+ rc = G10ERR_WRITE_FILE;
+ break;
+ }
+ }
+ *ret_len = nbytes;
+ }
+ else if( control == IOBUFCTRL_INIT ) {
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "file_filter";
+ }
+ else if( control == IOBUFCTRL_FREE ) {
+ if( fp != stdin && fp != stdout )
+ fclose(fp);
+ fp = NULL;
+ m_free(a); /* we can free our context now */
+ }
+
+ return rc;
+}
+
+
+/****************
+ * This is used to implement the block write mode.
+ * Block reading is done on a byte by byte basis in readbyte(),
+ * without a filter
+ */
+static int
+block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
+{
+ block_filter_ctx_t *a = opaque;
+ size_t size = *ret_len;
+ int c, rc = 0;
+ char *p;
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ size_t n=0;
+
+ p = buf;
+ assert( size ); /* need a buffer */
+ if( a->eof ) /* don't read any further */
+ rc = -1;
+ while( !rc && size ) {
+ if( !a->size ) { /* get the length bytes */
+ c = iobuf_get(chain);
+ a->size = c << 8;
+ c = iobuf_get(chain);
+ a->size |= c;
+ if( c == -1 ) {
+ log_error("block_filter: error reading length info\n");
+ rc = G10ERR_READ_FILE;
+ }
+ if( !a->size ) {
+ a->eof = 1;
+ if( !n )
+ rc = -1;
+ break;
+ }
+ }
+
+ for(; !rc && size && a->size; size--, a->size-- ) {
+ if( (c=iobuf_get(chain)) == -1 ) {
+ log_error("block_filter %p: read error (size=%lu,a->size=%lu)\n",
+ a, (ulong)size, (ulong)a->size);
+ rc = G10ERR_READ_FILE;
+ }
+ else {
+ *p++ = c;
+ n++;
+ }
+ }
+ }
+ *ret_len = n;
+ }
+ else if( control == IOBUFCTRL_FLUSH ) {
+ size_t avail, n;
+
+ for(p=buf; !rc && size; ) {
+ n = size;
+ avail = a->size - a->count;
+ if( !avail ) {
+ if( n > a->size ) {
+ iobuf_put( chain, (a->size >> 8) & 0xff );
+ iobuf_put( chain, a->size & 0xff );
+ avail = a->size;
+ a->count = 0;
+ }
+ else {
+ iobuf_put( chain, (n >> 8) & 0xff );
+ iobuf_put( chain, n & 0xff );
+ avail = n;
+ a->count = a->size - n;
+ }
+ }
+ if( n > avail )
+ n = avail;
+ if( iobuf_write(chain, p, n ) )
+ rc = G10ERR_WRITE_FILE;
+ a->count += n;
+ p += n;
+ size -= n;
+ }
+ }
+ else if( control == IOBUFCTRL_INIT ) {
+ if( DBG_IOBUF )
+ log_debug("init block_filter %p\n", a );
+ if( a->usage == 1 )
+ a->count = a->size = 0;
+ else
+ a->count = a->size; /* force first length bytes */
+ a->eof = 0;
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "block_filter";
+ }
+ else if( control == IOBUFCTRL_FREE ) {
+ if( a->usage == 2 ) { /* write the end markers */
+ iobuf_writebyte(chain, 0);
+ iobuf_writebyte(chain, 0);
+ }
+ else if( a->size ) {
+ log_error("block_filter: pending bytes!\n");
+ }
+ if( DBG_IOBUF )
+ log_debug("free block_filter %p\n", a );
+ m_free(a); /* we can free our context now */
+ }
+
+ return rc;
+}
+
+
+
+/****************
+ * Allocate a new io buffer, with no function assigned.
+ * Usage is the desired usage: 1 for input, 2 for output, 3 for temp buffer
+ * BUFSIZE is a suggested buffer size.
+ */
+IOBUF
+iobuf_alloc(int usage, size_t bufsize)
+{
+ IOBUF a;
+ static int number=0;
+
+ a = m_alloc_clear(sizeof *a);
+ a->usage = usage;
+ a->d.buf = m_alloc( bufsize );
+ a->d.size = bufsize;
+ a->no = ++number;
+ a->subno = 0;
+ return a;
+}
+
+
+int
+iobuf_close( IOBUF a )
+{
+ IOBUF a2;
+ size_t dummy_len;
+ int rc=0;
+
+ for( ; a; a = a2 ) {
+ a2 = a->chain;
+ if( a->usage == 2 && (rc=iobuf_flush(a)) )
+ log_error("iobuf_flush failed on close: %s\n", g10_errstr(rc));
+
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: close '%s'\n", a->no, a->subno, a->desc );
+ if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE,
+ a->chain, NULL, &dummy_len)) )
+ log_error("IOBUFCTRL_FREE failed on close: %s\n", g10_errstr(rc) );
+ m_free(a->recorder.buf);
+ m_free(a->d.buf);
+ m_free(a);
+ }
+ return rc;
+}
+
+int
+iobuf_cancel( IOBUF a )
+{
+ /* FIXME: do an unlink if usage is 2 */
+ return iobuf_close(a);
+}
+
+
+/****************
+ * create a temporary iobuf, which can be used to collect stuff
+ * in an iobuf and later be written by iobuf_write_temp() to another
+ * iobuf.
+ */
+IOBUF
+iobuf_temp()
+{
+ IOBUF a;
+
+ a = iobuf_alloc(3, 8192 );
+
+ return a;
+}
+
+
+/****************
+ * Create a head iobuf for reading from a file
+ * returns: NULL if an error occures and sets errno
+ */
+IOBUF
+iobuf_open( const char *fname )
+{
+ IOBUF a;
+ FILE *fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+
+ if( !fname ) {
+ fp = stdin; /* fixme: set binary mode for msdoze */
+ fname = "[stdin]";
+ }
+ else if( !(fp = fopen(fname, "rb")) )
+ return NULL;
+ a = iobuf_alloc(1, 8192 );
+ fcx = m_alloc( sizeof *fcx + strlen(fname) );
+ fcx->fp = fp;
+ strcpy(fcx->fname, fname );
+ a->filter = file_filter;
+ a->filter_ov = fcx;
+ file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
+ file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: open '%s'\n", a->no, a->subno, fname );
+
+ return a;
+}
+
+/****************
+ * create a iobuf for writing to a file; the file will be created.
+ */
+IOBUF
+iobuf_create( const char *fname )
+{
+ IOBUF a;
+ FILE *fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+
+ if( !fname ) {
+ fp = stdout;
+ fname = "[stdout]";
+ }
+ else if( !(fp = fopen(fname, "wb")) )
+ return NULL;
+ a = iobuf_alloc(2, 8192 );
+ fcx = m_alloc( sizeof *fcx + strlen(fname) );
+ fcx->fp = fp;
+ strcpy(fcx->fname, fname );
+ a->filter = file_filter;
+ a->filter_ov = fcx;
+ file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
+ file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: create '%s'\n", a->no, a->subno, a->desc );
+
+ return a;
+}
+
+/****************
+ * Register an i/o filter.
+ */
+int
+iobuf_push_filter( IOBUF a,
+ int (*f)(void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *len), void *ov )
+{
+ IOBUF b;
+ size_t dummy_len=0;
+ int rc=0;
+
+ if( a->usage == 2 && (rc=iobuf_flush(a)) )
+ return rc;
+ /* make a copy of the current stream, so that
+ * A is the new stream and B the original one.
+ * The contents of the buffers are transferred to the
+ * new stream.
+ */
+ b = m_alloc(sizeof *b);
+ memcpy(b, a, sizeof *b );
+ /* remove the filter stuff from the new stream */
+ a->filter = NULL;
+ a->filter_ov = NULL;
+ if( a->usage == 2 ) { /* allocate a fresh buffer for the original stream */
+ b->d.buf = m_alloc( a->d.size );
+ b->d.len = 0;
+ b->d.start = 0;
+ }
+ else { /* allocate a fresh buffer for the new stream */
+ a->d.buf = m_alloc( a->d.size );
+ a->d.len = 0;
+ a->d.start = 0;
+ }
+ /* disable nlimit for the new stream */
+ a->nlimit = a->nbytes = 0;
+ /* disable recorder for the original stream */
+ b->recorder.buf = NULL;
+ /* make a link from the new stream to the original stream */
+ a->chain = b;
+
+ /* setup the function on the new stream */
+ a->filter = f;
+ a->filter_ov = ov;
+
+ a->subno = b->subno + 1;
+ f( ov, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &dummy_len );
+
+ if( DBG_IOBUF ) {
+ log_debug("iobuf-%d.%d: push '%s'\n", a->no, a->subno, a->desc );
+ for(b=a; b; b = b->chain )
+ log_debug("\tchain: %d.%d '%s'\n", b->no, b->subno, b->desc );
+ }
+
+ /* now we can initialize the new function if we have one */
+ if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_INIT, a->chain,
+ NULL, &dummy_len)) )
+ log_error("IOBUFCTRL_INIT failed: %s\n", g10_errstr(rc) );
+ return rc;
+}
+
+/****************
+ * Remove an i/o filter.
+ */
+int
+iobuf_pop_filter( IOBUF a, int (*f)(void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *len), void *ov )
+{
+ IOBUF b;
+ size_t dummy_len=0;
+ int rc=0;
+
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: pop '%s'\n", a->no, a->subno, a->desc );
+ if( !a->filter ) { /* this is simple */
+ b = a->chain;
+ assert(b);
+ m_free(a->d.buf);
+ memcpy(a,b, sizeof *a);
+ m_free(b);
+ return 0;
+ }
+ for(b=a ; b; b = b->chain )
+ if( b->filter == f && (!ov || b->filter_ov == ov) )
+ break;
+ if( !b )
+ log_bug("iobuf_pop_filter(): filter function not found\n");
+
+ /* flush this stream if it is an output stream */
+ if( a->usage == 2 && (rc=iobuf_flush(b)) ) {
+ log_error("iobuf_flush failed in pop_filter: %s\n", g10_errstr(rc));
+ return rc;
+ }
+ /* and tell the filter to free it self */
+ if( (rc = b->filter(b->filter_ov, IOBUFCTRL_FREE, b->chain,
+ NULL, &dummy_len)) ) {
+ log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
+ return rc;
+ }
+
+ /* and look how to remove it */
+ if( a == b && !b->chain )
+ log_bug("can't remove the last filter from the chain\n");
+ else if( a == b ) { /* remove the first iobuf from the chain */
+ /* everything from b is copied to a. This is save because
+ * a flush has been done on the to be removed entry
+ */
+ b = a->chain;
+ m_free(a->d.buf);
+ memcpy(a,b, sizeof *a);
+ m_free(b);
+ }
+ else if( !b->chain ) { /* remove the last iobuf from the chain */
+ log_bug("Ohh jeee, trying to a head filter\n");
+ }
+ else { /* remove an intermediate iobuf from the chain */
+ log_bug("Ohh jeee, trying to remove an intermediate filter\n");
+ }
+
+ return rc;
+}
+
+
+
+/****************
+ * read underflow: read more bytes into the buffer and return
+ * the first byte or -1 on EOF.
+ */
+static int
+underflow(IOBUF a)
+{
+ size_t len;
+ int rc;
+
+ /*log_debug("iobuf-%d.%d: underflow: start=%lu len=%lu\n",
+ a->no, a->subno, (ulong)a->d.start, (ulong)a->d.len );*/
+ assert( a->d.start == a->d.len );
+ if( a->usage == 3 )
+ return -1; /* EOF because a temp buffer can't do an underflow */
+ if( a->filter_eof ) {
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: filter eof\n", a->no, a->subno );
+ return -1;
+ }
+
+ if( a->filter ) {
+ len = a->d.size;
+ rc = a->filter( a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain,
+ a->d.buf, &len );
+ if( a->usage == 1 && rc == -1 ) { /* EOF: we can remove the filter */
+ size_t dummy_len;
+
+ /* and tell the filter to free it self */
+ if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain,
+ NULL, &dummy_len)) )
+ log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
+ a->filter = NULL;
+ a->desc = NULL;
+ a->filter_ov = NULL;
+ a->filter_eof = 1;
+ }
+
+ if( !len )
+ return -1;
+ a->d.len = len;
+ a->d.start = 0;
+ return a->d.buf[a->d.start++];
+ }
+ else
+ return -1; /* no filter; return EOF */
+}
+
+
+void
+iobuf_clear_eof(IOBUF a)
+{
+ assert(a->usage == 1);
+
+ if( a->filter )
+ log_info("iobuf-%d.%d: clear_eof '%s' with enabled filter\n", a->no, a->subno, a->desc );
+ if( !a->filter_eof )
+ log_info("iobuf-%d.%d: clear_eof '%s' with no EOF pending\n", a->no, a->subno, a->desc );
+ iobuf_pop_filter(a, NULL, NULL);
+}
+
+
+int
+iobuf_flush(IOBUF a)
+{
+ size_t len;
+ int rc;
+
+ /*log_debug("iobuf-%d.%d: flush\n", a->no, a->subno );*/
+ if( a->usage == 3 )
+ log_bug("temp buffer too short\n");
+ else if( a->usage != 2 )
+ log_bug("flush on non-output iobuf\n");
+ else if( !a->filter )
+ log_bug("iobuf_flush: no filter\n");
+ len = a->d.len;
+ rc = a->filter( a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len );
+ if( !rc && len != a->d.len ) {
+ log_info("iobuf_flush did not write all!\n");
+ rc = G10ERR_WRITE_FILE;
+ }
+ a->d.len = 0;
+
+ return rc;
+}
+
+
+/****************
+ * Read a byte from the iobuf; returns -1 on EOF
+ */
+int
+iobuf_readbyte(IOBUF a)
+{
+ int c;
+
+ if( a->nlimit && a->nbytes >= a->nlimit )
+ return -1; /* forced EOF */
+
+ if( a->d.start < a->d.len ) {
+ c = a->d.buf[a->d.start++];
+ }
+ else if( (c=underflow(a)) == -1 )
+ return -1; /* EOF */
+
+ a->nbytes++;
+
+ if( a->recorder.buf ) {
+ if( a->recorder.len >= a->recorder.size ) {
+ a->recorder.size += 500;
+ a->recorder.buf = m_realloc( a->recorder.buf, a->recorder.size );
+ }
+ ((byte*)a->recorder.buf)[a->recorder.len++] = c;
+ }
+ return c;
+}
+
+
+int
+iobuf_writebyte(IOBUF a, unsigned c)
+{
+ if( a->d.len == a->d.size )
+ if( iobuf_flush(a) )
+ return -1;
+
+ assert( a->d.len < a->d.size );
+ a->d.buf[a->d.len++] = c;
+ return 0;
+}
+
+
+int
+iobuf_write(IOBUF a, byte *buf, unsigned buflen )
+{
+ for( ; buflen; buflen--, buf++ )
+ if( iobuf_writebyte(a, *buf) )
+ return -1;
+ return 0;
+}
+
+
+
+/****************
+ * copy the contents of TEMP to A.
+ */
+int
+iobuf_write_temp( IOBUF a, IOBUF temp )
+{
+ return iobuf_write(a, temp->d.buf, temp->d.len );
+}
+
+/****************
+ * copy the contents of the temp io stream to BUFFER.
+ */
+size_t
+iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen )
+{
+ size_t n = a->d.len;
+
+ if( n > buflen )
+ n = buflen;
+ memcpy( buffer, a->d.buf, n );
+ return n;
+}
+
+
+/****************
+ * Set a limit, how much bytes may be read from the input stream A.
+ * Setting the limit to 0 disables this feature.
+ */
+void
+iobuf_set_limit( IOBUF a, unsigned long nlimit )
+{
+ a->nlimit = nlimit;
+ a->nbytes = 0;
+}
+
+
+
+void
+iobuf_start_recorder( IOBUF a )
+{
+ m_free(a->recorder.buf);
+ a->recorder.size = 500;
+ a->recorder.buf = m_alloc(a->recorder.size);
+ a->recorder.len = 0;
+}
+
+void
+iobuf_push_recorder( IOBUF a, int c )
+{
+ if( a->recorder.buf ) {
+ if( a->recorder.len >= a->recorder.size ) {
+ a->recorder.size += 500;
+ a->recorder.buf = m_realloc( a->recorder.buf, a->recorder.size );
+ }
+ ((byte*)a->recorder.buf)[a->recorder.len++] = c;
+ }
+}
+
+
+char *
+iobuf_stop_recorder( IOBUF a, size_t *n )
+{
+ char *p;
+ if( !a->recorder.buf )
+ log_bug("iobuf_recorder not started\n");
+ p = a->recorder.buf;
+ if( n )
+ *n = a->recorder.len;
+ a->recorder.buf = NULL;
+ return p;
+}
+
+
+/****************
+ * Return the length of an open file
+ */
+u32
+iobuf_get_filelength( IOBUF a )
+{
+ struct stat st;
+
+ for( ; a; a = a->chain )
+ if( !a->chain && a->filter == file_filter ) {
+ file_filter_ctx_t *b = a->filter_ov;
+ FILE *fp = b->fp;
+
+ if( !fstat(fileno(fp), &st) )
+ return st.st_size;
+ log_error("fstat() failed: %s\n", strerror(errno) );
+ break;
+ }
+
+ return 0;
+}
+
+/****************
+ * Start the block write mode, see rfc1991.new for details.
+ * A value of 0 for N stops this mode (flushes and writes
+ * the end marker)
+ */
+void
+iobuf_set_block_mode( IOBUF a, size_t n )
+{
+ block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx );
+
+ assert( a->usage == 1 || a->usage == 2 );
+ ctx->usage = a->usage;
+ if( !n ) {
+ iobuf_pop_filter(a, block_filter, NULL );
+ }
+ else {
+ ctx->size = n; /* only needed for usage 2 */
+ iobuf_push_filter(a, block_filter, ctx );
+ }
+}
+
+
+/****************
+ * checks wether the stream is in block mode
+ */
+int
+iobuf_in_block_mode( IOBUF a )
+{
+ for(; a; a = a->chain )
+ if( a->filter == block_filter )
+ return 1; /* yes */
+ return 0; /* no */
+}
+
+
+
diff --git a/util/logger.c b/util/logger.c
new file mode 100644
index 000000000..803420cd8
--- /dev/null
+++ b/util/logger.c
@@ -0,0 +1,139 @@
+/* logger.c - log functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "util.h"
+
+/****************
+ * General interface for printing a line
+ * level 0 := print to /dev/null
+ * 1 := print to stdout
+ * 2 := print as info to stderr
+ * 3 := ditto but as error
+ */
+void
+printstr( int level, const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ if( !level )
+ return;
+
+ if( !fmt ) {
+ putc('\n', level? stderr: stdout);
+ return;
+ }
+
+ va_start( arg_ptr, fmt ) ;
+ if( level < 2 ) {
+ vfprintf(stdout,fmt,arg_ptr) ;
+ }
+ else {
+ fprintf(stderr, level==2? "%s: ": "%s: error: ", strusage(13) ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ }
+ va_end(arg_ptr);
+}
+
+
+void
+log_info( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "info: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+}
+
+void
+log_error( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "error: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+}
+
+void
+log_fatal( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "Fatal: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ exit(2);
+}
+
+void
+log_bug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "\nInternal Error: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ fflush(stderr);
+ abort();
+}
+
+void
+log_debug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "DBG: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+}
+
+
+
+void
+log_hexdump( const char *text, char *buf, size_t len )
+{
+ int i;
+
+ fprintf(stderr, "DBG: %s", text );
+ for(i=0; i < len; i++ )
+ fprintf(stderr, " %02X", ((byte*)buf)[i] );
+ fputc('\n', stderr);
+}
+
+
+void
+log_mpidump( const char *text, MPI a )
+{
+ fprintf(stderr, "DBG: %s", text );
+ mpi_print(stderr, a, 1 );
+ fputc('\n', stderr);
+}
+
diff --git a/util/memory.c b/util/memory.c
new file mode 100644
index 000000000..6ad57f9b0
--- /dev/null
+++ b/util/memory.c
@@ -0,0 +1,460 @@
+/* memory.c - memory allocation
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * We use our own memory allocation functions instead of plain malloc(),
+ * so that we can provide some special enhancements:
+ * a) functions to provide memory from a secure memory.
+ * Don't know how to handle it yet, but it may be possible to
+ * use memory which can't be swapped out.
+ * b) By looking at the requested allocation size we
+ * can reuse memory very quickly (e.g. MPI storage)
+ * c) A controlbyte gives us the opportunity to use only one
+ * free() function and do some overflow checking.
+ * d) memory checking and reporting if compiled with M_DEBUG
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "types.h"
+#include "memory.h"
+#include "util.h"
+
+
+#define MAGIC_NOR_BYTE 0x55
+#define MAGIC_SEC_BYTE 0xcc
+#define MAGIC_END_BYTE 0xaa
+
+const void membug( const char *fmt, ... );
+
+#ifdef M_DEBUG
+ #undef m_alloc
+ #undef m_alloc_clear
+ #undef m_alloc_secure
+ #undef m_alloc_secure_clear
+ #undef m_realloc
+ #undef m_free
+ #undef m_check
+ #define FNAME(a) m_debug_ ##a
+ #define FNAMEPRT , const char *info
+ #define FNAMEARG , info
+ #define store_len(p,n,m) do { add_entry(p,n,m, \
+ info, __FUNCTION__); } while(0)
+#else
+ #define FNAME(a) m_ ##a
+ #define FNAMEPRT
+ #define FNAMEARG
+ #define store_len(p,n,m) do { ((byte*))p[0] = n; \
+ ((byte*))p[2] = n >> 8 ; \
+ ((byte*))p[3] = n >> 16 ; \
+ ((byte*))p[4] = m? MAGIC_SEC_BYTE \
+ : MAGIC_NOR_BYTE; \
+ } while(0)
+#endif
+
+
+#ifdef M_DEBUG /* stuff used for memory debuging */
+
+struct info_entry {
+ struct info_entry *next;
+ unsigned count; /* call count */
+ const char *info; /* the reference to the info string */
+};
+
+struct memtbl_entry {
+ const void *user_p; /* for reference: the pointer given to the user */
+ size_t user_n; /* length requested by the user */
+ struct memtbl_entry *next; /* to build a list of unused entries */
+ const struct info_entry *info; /* points into the table with */
+ /* the info strings */
+ unsigned inuse:1; /* this entry is in use */
+ unsigned count:31;
+};
+
+
+#define INFO_BUCKETS 53
+#define info_hash(p) ( *(u32*)((p)) % INFO_BUCKETS )
+static struct info_entry *info_strings[INFO_BUCKETS]; /* hash table */
+
+static struct memtbl_entry *memtbl; /* the table with the memory infos */
+static unsigned memtbl_size; /* number of allocated entries */
+static unsigned memtbl_len; /* number of used entries */
+static struct memtbl_entry *memtbl_unused;/* to keep track of unused entries */
+
+static void dump_table(void);
+static void check_allmem( const char *info );
+
+/****************
+ * Put the new P into the debug table and return a pointer to the table entry.
+ * mode is true for security. BY is the name of the function which called us.
+ */
+static void
+add_entry( byte *p, unsigned n, int mode, const char *info, const char *by )
+{
+ unsigned index;
+ struct memtbl_entry *e;
+ struct info_entry *ie;
+
+ if( memtbl_len < memtbl_size )
+ index = memtbl_len++;
+ else {
+ struct memtbl_entry *e;
+ /* look for an used entry in the table. We take the first one,
+ * so that freed entries remain as long as possible in the table
+ * (free appends a new one)
+ */
+ if( (e = memtbl_unused) ) {
+ index = e - memtbl;
+ memtbl_unused = e->next;
+ e->next = NULL;
+ }
+ else { /* no free entries in the table: extend the table */
+ if( !memtbl_size ) { /* first time */
+ memtbl_size = 100;
+ if( !(memtbl = calloc( memtbl_size, sizeof *memtbl )) )
+ membug("memory debug table malloc failed\n");
+ index = 0;
+ memtbl_len = 1;
+ if( DBG_MEMSTAT )
+ atexit( dump_table );
+ }
+ else { /* realloc */
+ unsigned n = memtbl_size / 4; /* enlarge by 25% */
+ if(!(memtbl = realloc(memtbl, (memtbl_size+n)*sizeof *memtbl)))
+ membug("memory debug table realloc failed\n");
+ memset(memtbl+memtbl_size, 0, n*sizeof *memtbl );
+ memtbl_size += n;
+ index = memtbl_len++;
+ }
+ }
+ }
+ e = memtbl+index;
+ if( e->inuse )
+ membug("Ooops: entry %u is flagged as in use\n", index);
+ e->user_p = p + 4;
+ e->user_n = n;
+ e->count++;
+ if( e->next )
+ membug("Ooops: entry is in free entry list\n");
+ /* do we already have this info string */
+ for( ie = info_strings[info_hash(info)]; ie; ie = ie->next )
+ if( ie->info == info )
+ break;
+ if( !ie ) { /* no: make a new entry */
+ if( !(ie = malloc( sizeof *ie )) )
+ membug("can't allocate info entry\n");
+ ie->next = info_strings[info_hash(info)];
+ info_strings[info_hash(info)] = ie;
+ ie->info = info;
+ ie->count = 0;
+ }
+ ie->count++;
+ e->info = ie;
+ e->inuse = 1;
+
+ /* put the index at the start of the memory */
+ p[0] = index;
+ p[1] = index >> 8 ;
+ p[2] = index >> 16 ;
+ p[3] = mode? MAGIC_SEC_BYTE : MAGIC_NOR_BYTE ;
+ if( DBG_MEMORY )
+ log_debug( "%s allocates %u bytes using %s\n", info, e->user_n, by );
+}
+
+
+
+/****************
+ * Check that the memory block is correct. The magic byte has already been
+ * checked. Checks which are done here:
+ * - see wether the index points into our memory table
+ * - see wether P is the same as the one stored in the table
+ * - see wether we have already freed this block.
+ */
+struct memtbl_entry *
+check_mem( const byte *p, const char *info )
+{
+ unsigned n;
+ struct memtbl_entry *e;
+
+ n = p[0];
+ n |= p[1] << 8;
+ n |= p[2] << 16;
+
+ if( n >= memtbl_len )
+ membug("memory at %p corrupted: index=%u table_len=%u (%s)\n",
+ p+4, n, memtbl_len, info );
+ e = memtbl+n;
+
+ if( e->user_p != p+4 )
+ membug("memory at %p corrupted: reference mismatch (%s)\n", p+4, info );
+ if( !e->inuse )
+ membug("memory at %p corrupted: marked as free (%s)\n", p+4, info );
+
+ if( !(p[3] == MAGIC_NOR_BYTE || p[3] == MAGIC_SEC_BYTE) )
+ membug("memory at %p corrupted: underflow=%02x (%s)\n", p+4, p[3], info );
+ if( p[4+e->user_n] != MAGIC_END_BYTE )
+ membug("memory at %p corrupted: overflow=%02x (%s)\n", p+4, p[4+e->user_n], info );
+ if( e->info->count > 20000 )
+ membug("memory at %p corrupted: count too high (%s)\n", p+4, info );
+ return e;
+}
+
+
+/****************
+ * free the entry and the memory (replaces free)
+ */
+static void
+free_entry( byte *p, const char *info )
+{
+ struct memtbl_entry *e, *e2;
+
+ check_allmem("add_entry");
+
+ e = check_mem(p, info);
+ if( DBG_MEMORY )
+ log_debug( "%s frees %u bytes alloced by %s\n",
+ info, e->user_n, e->info->info );
+ if( !e->inuse ) {
+ if( e->user_p == p + 4 )
+ membug("freeing an already freed pointer at %p\n", p+4 );
+ else
+ membug("freeing pointer %p which is flagged as freed\n", p+4 );
+ }
+
+ e->inuse = 0;
+ e->next = NULL;
+ if( !memtbl_unused )
+ memtbl_unused = e;
+ else {
+ for(e2=memtbl_unused; e2->next; e2 = e2->next )
+ ;
+ e2->next = e;
+ }
+ memset(p,'f', e->user_n+5);
+ free(p);
+}
+
+static void
+dump_entry(struct memtbl_entry *e )
+{
+ unsigned n = e - memtbl;
+
+ fprintf(stderr, "mem %4u%c %5u %p %5u %s (%u)\n",
+ n, e->inuse?'a':'u', e->count, e->user_p, e->user_n,
+ e->info->info, e->info->count );
+
+
+}
+
+static void
+dump_table(void)
+{
+ unsigned n;
+ struct memtbl_entry *e;
+ ulong sum = 0, chunks =0;
+
+ for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) {
+ dump_entry(e);
+ if(e->inuse) {
+ sum += e->user_n;
+ chunks++;
+ }
+ }
+ fprintf(stderr, " memory used: %8lu bytes in %ld chunks\n",
+ sum, chunks );
+}
+
+static void
+check_allmem( const char *info )
+{
+ unsigned n;
+ struct memtbl_entry *e;
+
+ for( e = memtbl, n = 0; n < memtbl_len; n++, e++ )
+ if( e->inuse )
+ check_mem(e->user_p-4, info);
+}
+
+#endif /* M_DEBUG */
+
+const void
+membug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "\nMemory Error: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ fflush(stderr);
+ #ifdef M_DEBUG
+ if( DBG_MEMSTAT )
+ dump_table();
+ #endif
+ abort();
+}
+
+
+static void
+out_of_core(size_t n)
+{
+ log_fatal("out of memory while allocating %u bytes\n", (unsigned)n );
+}
+
+/****************
+ * Allocate memory of size n.
+ * This function gives up if we do not have enough memory
+ */
+void *
+FNAME(alloc)( size_t n FNAMEPRT )
+{
+ char *p;
+
+ if( !(p = malloc( n + 5 )) )
+ out_of_core(n);
+ store_len(p,n,0);
+ p[4+n] = MAGIC_END_BYTE; /* need to add the length somewhere */
+ return p+4;
+}
+
+/****************
+ * Allocate memory of size n from the secure memory pool.
+ * This function gives up if we do not have enough memory
+ */
+void *
+FNAME(alloc_secure)( size_t n FNAMEPRT )
+{
+ char *p;
+
+ if( !(p = malloc( n + 5 )) ) /* fixme: should alloc from the secure heap*/
+ out_of_core(n);
+ store_len(p,n,1);
+ p[4+n] = MAGIC_END_BYTE;
+ return p+4;
+}
+
+void *
+FNAME(alloc_clear)( size_t n FNAMEPRT )
+{
+ void *p;
+ p = FNAME(alloc)( n FNAMEARG );
+ memset(p, 0, n );
+ return p;
+}
+
+void *
+FNAME(alloc_secure_clear)( size_t n FNAMEPRT)
+{
+ void *p;
+ p = FNAME(alloc_secure)( n FNAMEARG );
+ memset(p, 0, n );
+ return p;
+}
+
+
+/****************
+ * realloc and clear the new space
+ */
+void *
+FNAME(realloc)( void *a, size_t n FNAMEPRT )
+{ /* FIXME: should be optimized :-) */
+ unsigned char *p = a;
+ void *b;
+ size_t len = m_size(a);
+
+ if( len >= n ) /* we don't shrink for now */
+ return a;
+ if( p[-1] == MAGIC_SEC_BYTE )
+ b = FNAME(alloc_secure_clear)(n FNAMEARG);
+ else
+ b = FNAME(alloc_clear)(n FNAMEARG);
+ FNAME(check)(NULL FNAMEARG);
+ memcpy(b, a, len );
+ FNAME(free)(p FNAMEARG);
+ return b;
+}
+
+
+
+/****************
+ * Free a pointer
+ */
+void
+FNAME(free)( void *a FNAMEPRT )
+{
+ byte *p = a;
+
+ if( !p )
+ return;
+ #ifdef M_DEBUG
+ free_entry(p-4, info);
+ #else
+ m_check(p);
+ free(p-4);
+ #endif
+}
+
+
+void
+FNAME(check)( const void *a FNAMEPRT )
+{
+ const byte *p = a;
+
+ #ifdef M_DEBUG
+ if( p )
+ check_mem(p-4, info);
+ else
+ check_allmem(info);
+ #else
+ if( !p )
+ return;
+ if( !(p[-1] == MAGIC_NOR_BYTE || p[-1] == MAGIC_SEC_BYTE) )
+ membug("memory at %p corrupted (underflow=%02x)\n", p, p[-1] );
+ else if( p[m_size(p)] != MAGIC_END_BYTE )
+ membug("memory at %p corrupted (overflow=%02x)\n", p, p[-1] );
+ #endif
+}
+
+
+size_t
+m_size( const void *a )
+{
+ const byte *p = a;
+ size_t n;
+
+ #ifdef M_DEBUG
+ n = check_mem(p-4, "m_size")->user_n;
+ #else
+ n = ((byte*)p[-4];
+ n |= ((byte*)p[-3] << 8;
+ n |= ((byte*)p[-2] << 16;
+ #endif
+ return n;
+}
+
+
+int
+m_is_secure( const void *p )
+{
+ return p && ((byte*)p)[-1] == MAGIC_SEC_BYTE;
+}
+
diff --git a/util/miscutil.c b/util/miscutil.c
new file mode 100644
index 000000000..9fecf4488
--- /dev/null
+++ b/util/miscutil.c
@@ -0,0 +1,33 @@
+/* miscutil.c - miscellaneous utilities
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <time.h>
+#include "types.h"
+#include "util.h"
+
+u32
+make_timestamp()
+{
+ return time(NULL);
+}
+
+
diff --git a/util/strgutil.c b/util/strgutil.c
new file mode 100644
index 000000000..b517ed5b6
--- /dev/null
+++ b/util/strgutil.c
@@ -0,0 +1,63 @@
+/* strgutil.c - miscellaneous utilities
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "types.h"
+#include "util.h"
+#include "memory.h"
+
+
+void
+free_strlist( STRLIST sl )
+{
+ STRLIST sl2;
+
+ for(; sl; sl = sl2 ) {
+ sl2 = sl->next;
+ m_free(sl);
+ }
+}
+
+/****************
+ * look for the substring SUB in buffer and return a pointer to that
+ * substring in BUF or NULL if not found.
+ * Comparison is case-in-sensitive.
+ */
+char *
+memistr( char *buf, size_t buflen, const char *sub )
+{
+ const byte *t, *s ;
+ size_t n;
+
+ for( t=buf, n=buflen, s=sub ; n ; t++, n-- )
+ if( toupper(*t) == toupper(*s) ) {
+ for( buf=(char*)t++, buflen = n--, s++;
+ n && toupper(*t) == toupper(*s); t++, s++, n-- )
+ ;
+ if( !*s )
+ return buf;
+ t = buf; n = buflen; s = sub ;
+ }
+
+ return NULL ;
+}
+
diff --git a/util/ttyio.c b/util/ttyio.c
new file mode 100644
index 000000000..39ad5a666
--- /dev/null
+++ b/util/ttyio.c
@@ -0,0 +1,114 @@
+/* ttyio.c - tty i/O functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <ctype.h>
+#include "util.h"
+#include "memory.h"
+#include "ttyio.h"
+
+static int last_prompt_len;
+
+static FILE *
+open_tty(void)
+{
+ FILE *tty = fopen("/dev/tty", "r");
+ if( !tty )
+ log_fatal("cannot open /dev/tty: %s\n", strerror(errno) );
+ return tty;
+}
+
+static void
+close_tty( FILE *tty )
+{
+ fclose(tty);
+}
+
+
+
+void
+tty_printf( const char *fmt, ... )
+{
+ va_list arg_ptr;
+
+ va_start( arg_ptr, fmt ) ;
+ last_prompt_len += vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ fflush(stderr);
+}
+
+
+char *
+tty_get( const char *prompt )
+{
+ char *buf;
+ int c, n, i;
+ FILE *fp;
+
+ last_prompt_len = 0;
+ tty_printf( prompt );
+ buf = m_alloc(n=50);
+ i = 0;
+ fp = open_tty();
+ while( (c=getc(fp)) != EOF && c != '\n' ) {
+ last_prompt_len++;
+ if( c == '\t' )
+ c = ' ';
+ else if( iscntrl(c) )
+ continue;
+ if( !(i < n-1) ) {
+ n += 50;
+ buf = m_realloc( buf, n );
+ }
+ buf[i++] = c;
+ }
+ close_tty(fp);
+ buf[i] = 0;
+ return buf;
+}
+
+char *
+tty_get_hidden( const char *prompt )
+{
+ return tty_get( prompt ); /* fixme */
+}
+
+
+void
+tty_kill_prompt()
+{
+ int i;
+#if 0
+ for(i=0; i < last_prompt_len; i ++ )
+ fputc('\b', stderr);
+ for(i=0; i < last_prompt_len; i ++ )
+ fputc(' ', stderr);
+ for(i=0; i < last_prompt_len; i ++ )
+ fputc('\b', stderr);
+#endif
+ last_prompt_len = 0;
+ fflush(stderr);
+}
+