From 5393dd53c5e06f0458949217317601b2eaed8350 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 18 Nov 1997 14:06:00 +0000 Subject: [PATCH] initially checkin --- AUTHORS | 0 COPYING | 340 ++++++++++ ChangeLog | 0 INSTALL | 0 Makefile.am | 12 + Makefile.in | 261 ++++++++ NEWS | 0 README | 0 acconfig.h | 32 + cipher/Makefile.am | 28 + cipher/Makefile.in | 264 ++++++++ cipher/blowfish.c | 522 +++++++++++++++ cipher/blowfish.h | 51 ++ cipher/elgamal.c | 61 ++ cipher/elgamal.h | 45 ++ cipher/gost.c | 309 +++++++++ cipher/gost.h | 46 ++ cipher/idea.c | 352 +++++++++++ cipher/idea.h | 51 ++ cipher/md5.c | 420 +++++++++++++ cipher/md5.h | 44 ++ cipher/primegen.c | 152 +++++ cipher/random.c | 67 ++ cipher/rmd.h | 51 ++ cipher/rmd160.c | 375 +++++++++++ cipher/rmd160test.c | 63 ++ cipher/rsa.c | 191 ++++++ cipher/rsa.h | 53 ++ cipher/smallprime.c | 114 ++++ config.h.in | 60 ++ configure.in | 54 ++ g10/Makefile.am | 33 + g10/Makefile.in | 285 +++++++++ g10/build-packet.c | 386 ++++++++++++ g10/checksig.c | 96 +++ g10/compressed.c | 114 ++++ g10/encode.c | 470 ++++++++++++++ g10/encr-data.c | 122 ++++ g10/filter.h | 35 ++ g10/free-packet.c | 198 ++++++ g10/g10.c | 219 +++++++ g10/getkey.c | 475 ++++++++++++++ g10/keydb.h | 45 ++ g10/keygen.c | 253 ++++++++ g10/main.h | 35 ++ g10/mainproc.c | 275 ++++++++ g10/mdfilter.c | 70 +++ g10/options.h | 68 ++ g10/overwrite.c | 79 +++ g10/packet.h | 214 +++++++ g10/parse-packet.c | 662 +++++++++++++++++++ g10/passphrase.c | 126 ++++ g10/plaintext.c | 114 ++++ g10/pubkey-enc.c | 130 ++++ g10/seckey-cert.c | 157 +++++ g10/seskey.c | 101 +++ g10/sig-check.c | 213 +++++++ include/cipher.h | 87 +++ include/errors.h | 52 ++ include/iobuf.h | 120 ++++ include/memory.h | 64 ++ include/mpi.h | 147 +++++ include/ttyio.h | 29 + include/types.h | 76 +++ include/util.h | 100 +++ mpi/Makefile.am | 27 + mpi/Makefile.in | 271 ++++++++ mpi/longlong.h | 1398 +++++++++++++++++++++++++++++++++++++++++ mpi/mpi-add.c | 221 +++++++ mpi/mpi-bit.c | 133 ++++ mpi/mpi-cmp.c | 72 +++ mpi/mpi-div.c | 282 +++++++++ mpi/mpi-gcd.c | 54 ++ mpi/mpi-internal.h | 198 ++++++ mpi/mpi-inv.c | 127 ++++ mpi/mpi-mul.c | 178 ++++++ mpi/mpi-pow.c | 247 ++++++++ mpi/mpi-scan.c | 88 +++ mpi/mpicoder.c | 392 ++++++++++++ mpi/mpih-add.c | 109 ++++ mpi/mpih-cmp.c | 53 ++ mpi/mpih-div.c | 528 ++++++++++++++++ mpi/mpih-mul.c | 557 ++++++++++++++++ mpi/mpih-shift.c | 94 +++ mpi/mpih-sub.c | 106 ++++ mpi/mpiutil.c | 326 ++++++++++ scripts/install-sh | 250 ++++++++ scripts/mkinstalldirs | 40 ++ stamp-h.in | 1 + tools/Makefile.am | 12 + tools/Makefile.in | 252 ++++++++ tools/bftest.c | 85 +++ tools/mpicalc.c | 341 ++++++++++ tools/primes.scm | 31 + util/Makefile.am | 13 + util/Makefile.in | 248 ++++++++ util/argparse.c | 653 +++++++++++++++++++ util/errors.c | 69 ++ util/fileutil.c | 31 + util/iobuf.c | 762 ++++++++++++++++++++++ util/logger.c | 139 ++++ util/memory.c | 460 ++++++++++++++ util/miscutil.c | 33 + util/strgutil.c | 63 ++ util/ttyio.c | 114 ++++ 105 files changed, 18726 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 NEWS create mode 100644 README create mode 100644 acconfig.h create mode 100644 cipher/Makefile.am create mode 100644 cipher/Makefile.in create mode 100644 cipher/blowfish.c create mode 100644 cipher/blowfish.h create mode 100644 cipher/elgamal.c create mode 100644 cipher/elgamal.h create mode 100644 cipher/gost.c create mode 100644 cipher/gost.h create mode 100644 cipher/idea.c create mode 100644 cipher/idea.h create mode 100644 cipher/md5.c create mode 100644 cipher/md5.h create mode 100644 cipher/primegen.c create mode 100644 cipher/random.c create mode 100644 cipher/rmd.h create mode 100644 cipher/rmd160.c create mode 100644 cipher/rmd160test.c create mode 100644 cipher/rsa.c create mode 100644 cipher/rsa.h create mode 100644 cipher/smallprime.c create mode 100644 config.h.in create mode 100644 configure.in create mode 100644 g10/Makefile.am create mode 100644 g10/Makefile.in create mode 100644 g10/build-packet.c create mode 100644 g10/checksig.c create mode 100644 g10/compressed.c create mode 100644 g10/encode.c create mode 100644 g10/encr-data.c create mode 100644 g10/filter.h create mode 100644 g10/free-packet.c create mode 100644 g10/g10.c create mode 100644 g10/getkey.c create mode 100644 g10/keydb.h create mode 100644 g10/keygen.c create mode 100644 g10/main.h create mode 100644 g10/mainproc.c create mode 100644 g10/mdfilter.c create mode 100644 g10/options.h create mode 100644 g10/overwrite.c create mode 100644 g10/packet.h create mode 100644 g10/parse-packet.c create mode 100644 g10/passphrase.c create mode 100644 g10/plaintext.c create mode 100644 g10/pubkey-enc.c create mode 100644 g10/seckey-cert.c create mode 100644 g10/seskey.c create mode 100644 g10/sig-check.c create mode 100644 include/cipher.h create mode 100644 include/errors.h create mode 100644 include/iobuf.h create mode 100644 include/memory.h create mode 100644 include/mpi.h create mode 100644 include/ttyio.h create mode 100644 include/types.h create mode 100644 include/util.h create mode 100644 mpi/Makefile.am create mode 100644 mpi/Makefile.in create mode 100644 mpi/longlong.h create mode 100644 mpi/mpi-add.c create mode 100644 mpi/mpi-bit.c create mode 100644 mpi/mpi-cmp.c create mode 100644 mpi/mpi-div.c create mode 100644 mpi/mpi-gcd.c create mode 100644 mpi/mpi-internal.h create mode 100644 mpi/mpi-inv.c create mode 100644 mpi/mpi-mul.c create mode 100644 mpi/mpi-pow.c create mode 100644 mpi/mpi-scan.c create mode 100644 mpi/mpicoder.c create mode 100644 mpi/mpih-add.c create mode 100644 mpi/mpih-cmp.c create mode 100644 mpi/mpih-div.c create mode 100644 mpi/mpih-mul.c create mode 100644 mpi/mpih-shift.c create mode 100644 mpi/mpih-sub.c create mode 100644 mpi/mpiutil.c create mode 100755 scripts/install-sh create mode 100755 scripts/mkinstalldirs create mode 100644 stamp-h.in create mode 100644 tools/Makefile.am create mode 100644 tools/Makefile.in create mode 100644 tools/bftest.c create mode 100644 tools/mpicalc.c create mode 100644 tools/primes.scm create mode 100644 util/Makefile.am create mode 100644 util/Makefile.in create mode 100644 util/argparse.c create mode 100644 util/errors.c create mode 100644 util/fileutil.c create mode 100644 util/iobuf.c create mode 100644 util/logger.c create mode 100644 util/memory.c create mode 100644 util/miscutil.c create mode 100644 util/strgutil.c create mode 100644 util/ttyio.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..e69de29bb 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. + + + Copyright (C) 19yy + + 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. + + , 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 diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..e69de29bb 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 diff --git a/README b/README new file mode 100644 index 000000000..e69de29bb 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 +#include +#include +#include +#include +#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 +#include +#include +#include +#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 +#include +#include +#include +#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 +#include +#include +#include +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#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 +#include +#include +#include +#include +#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 +#include +#include +#include + +#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 +#include +#include +#include +#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 +#include +#include +#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 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 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 +#include +#include +#include +#include + +#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 +#include +#include + +#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 +#include +#include +#include +#include +#include +/*#include */ +#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 +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include + +#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 +#include +#include + +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#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 \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 +#include +#include + +#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 +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#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 +#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 + #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 +#include +#include + +#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 +#include +#include +#include +#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<= 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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#include "mpi-internal.h" +#include "longlong.h" +#include + + +/**************** + * 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 +#include +#include +#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 +#include +#include +#include + +#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 +#include +#include + +#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 +#include +#include + +#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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#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 +#include +#include + +#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 +#include +#include +#include + +#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 +# 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 +#include +#include +#include + +#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 +#include +#include +#include + +#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 +#include +#include +#include + +#include "util.h" + +#ifdef DOCUMENTATION +@Summary arg_parse + #include + + 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 +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#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); +} +