diff options
author | Werner Koch <wk@gnupg.org> | 1997-11-18 15:06:00 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 1997-11-18 15:06:00 +0100 |
commit | 5393dd53c5e06f0458949217317601b2eaed8350 (patch) | |
tree | c4b8d021851c32a611165c5fc215ad88604b5a94 | |
parent | New repository initialized by cvs2svn. (diff) | |
download | gnupg2-5393dd53c5e06f0458949217317601b2eaed8350.tar.xz gnupg2-5393dd53c5e06f0458949217317601b2eaed8350.zip |
initially checkin
105 files changed, 18726 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/AUTHORS diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..2b7b643ff --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ChangeLog diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/INSTALL diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..cfa9abb47 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,12 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = util mpi cipher tools g10 +EXTRA_DIST = + + + +tar: clean + cd ..; tar czvf ~/bkup/g10-`date +%d%m`.tar.gz src + + + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 000000000..934efce84 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,261 @@ +# Makefile.in generated automatically by automake 1.0 from Makefile.am + +# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = . + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +SUBDIRS = util mpi cipher tools g10 +EXTRA_DIST = +ACCONFIG = acconfig.h +CONFIG_HEADER_IN = config.h.in +mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs +CONFIG_HEADER = ./config.h +DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \ +Makefile.in NEWS README acconfig.h config.h.in configure configure.in \ +stamp-h.in + + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA) +DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA) + +TAR = tar +default: all + + +$(srcdir)/Makefile.in: Makefile.am configure.in + cd $(srcdir) && automake Makefile + +# For an explanation of the following Makefile rules, see node +# `Automatic Remaking' in GNU Autoconf documentation. +Makefile: Makefile.in config.status + CONFIG_FILES=$@ CONFIG_HEADERS= ./config.status +config.status: configure + ./config.status --recheck +$(srcdir)/configure: configure.in $(ACLOCAL) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && autoconf + +$(CONFIG_HEADER): stamp-h +stamp-h: $(CONFIG_HEADER_IN) config.status + CONFIG_FILES= CONFIG_HEADERS=$(CONFIG_HEADER) ./config.status + @echo timestamp > stamp-h +$(srcdir)/$(CONFIG_HEADER_IN): stamp-h.in +$(srcdir)/stamp-h.in: configure.in $(ACLOCAL) $(ACCONFIG) $(CONFIG_TOP) $(CONFIG_BOT) + cd $(srcdir) && autoheader + echo timestamp > $(srcdir)/stamp-h.in + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + for subdir in $(SUBDIRS); do \ + target=`echo $@ | sed s/-recursive//`; \ + echo making $$target in $$subdir; \ + (cd $$subdir && $(MAKE) $$target) \ + || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" + +tags: TAGS + +tags-recursive: + list="$(SUBDIRS)"; for subdir in $$list; do \ + (cd $$subdir && $(MAKE) tags); \ + done + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(CONFIG_HEADER) \ + $(TAGS_DEPENDENCIES) + tags=; \ + here=`pwd`; \ + for subdir in $(SUBDIRS); do \ + test -f $$subdir/TAGS && { \ + tags="$$tags -i $$here/$$subdir/TAGS"; \ + }; \ + done; \ + test -z "$(ETAGS_ARGS)$(CONFIG_HEADER)$(SOURCES)$(HEADERS)$$tags" \ + || etags $(ETAGS_ARGS) $$tags $(CONFIG_HEADER) $(SOURCES) $(HEADERS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + rm -rf $(distdir) + $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; \ + cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + && $(MAKE) \ + && $(MAKE) check \ + && $(MAKE) install \ + && $(MAKE) installcheck \ + && $(MAKE) dist + rm -rf $(distdir) + @echo "========================"; \ + echo "$(distdir).tar.gz is ready for distribution"; \ + echo "========================" +dist: distdir + chmod -R a+r $(distdir) + $(TAR) chozf $(distdir).tar.gz $(distdir) + rm -rf $(distdir) +distdir: $(DEP_DISTFILES) + rm -rf $(distdir) + mkdir $(distdir) + chmod 777 $(distdir) + distdir=`cd $(distdir) && pwd` \ + && cd $(srcdir) \ + && automake --include-deps --output-dir=$$distdir --strictness=gnu + @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \ + test -f $(distdir)/$$file \ + || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $(srcdir)/$$file $(distdir)/$$file; \ + done + for subdir in $(SUBDIRS); do \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + done +info: info-recursive + +dvi: dvi-recursive + +check: check-recursive + +installcheck: installcheck-recursive + +all-recursive-hack: $(CONFIG_HEADER) + $(MAKE) all-recursive + +all-am: Makefile config.h + +install-exec: install-exec-recursive + +install-data: install-data-recursive + +install: install-recursive + @: + +uninstall: uninstall-recursive + +all: all-recursive-hack all-am + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install +installdirs: installdirs-recursive + + +mostlyclean-generic: + test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + rm -f Makefile $(DISTCLEANFILES) + rm -f config.cache config.log $(CONFIG_HEADER) stamp-h + +maintainer-clean-generic: + test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean-am: mostlyclean-tags mostlyclean-generic + +clean-am: clean-tags clean-generic mostlyclean-am + +distclean-am: distclean-tags distclean-generic clean-am + +maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ + distclean-am + +mostlyclean: mostlyclean-am mostlyclean-recursive + +clean: clean-am clean-recursive + +distclean: distclean-am distclean-recursive + rm -f config.status + +maintainer-clean: maintainer-clean-am maintainer-clean-recursive + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f config.status + +.PHONY: default install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info dvi check \ +installcheck all-recursive-hack all-am install-exec install-data \ +install uninstall all installdirs mostlyclean-generic distclean-generic \ +clean-generic maintainer-clean-generic clean mostlyclean distclean \ +maintainer-clean + + +tar: clean + cd ..; tar czvf ~/bkup/g10-`date +%d%m`.tar.gz src +.SUFFIXES: + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 000000000..01aab2a6a --- /dev/null +++ b/acconfig.h @@ -0,0 +1,32 @@ +/* acconfig.h - used by autoheader to make config.h.in + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_CONFIG_H +#define G10_CONFIG_H + + +@@TOP@@ + +#undef M_DEBUG +#undef VERSION +#undef PACKAGE + +@@BOTTOM@@ + +#endif /*G10_CONFIG_H*/ diff --git a/cipher/Makefile.am b/cipher/Makefile.am new file mode 100644 index 000000000..8a543e380 --- /dev/null +++ b/cipher/Makefile.am @@ -0,0 +1,28 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +noinst_LIBRARIES = cipher + + +cipher_SOURCES = blowfish.c \ + blowfish.h \ + elgamal.c \ + elgamal.h \ + gost.c \ + gost.h \ + idea.c \ + idea.h \ + md5.c \ + md5.h \ + primegen.c \ + random.c \ + ripemd.h \ + rmd.h \ + rmd160.c \ + rsa.c \ + rsa.h \ + smallprime.c + + + diff --git a/cipher/Makefile.in b/cipher/Makefile.in new file mode 100644 index 000000000..faee770be --- /dev/null +++ b/cipher/Makefile.in @@ -0,0 +1,264 @@ +# Makefile.in generated automatically by automake 1.0 from Makefile.am + +# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +INCLUDES = -I$(top_srcdir)/include + +noinst_LIBRARIES = cipher + +cipher_SOURCES = blowfish.c \ + blowfish.h \ + elgamal.c \ + elgamal.h \ + gost.c \ + gost.h \ + idea.c \ + idea.h \ + md5.c \ + md5.h \ + primegen.c \ + random.c \ + ripemd.h \ + rmd.h \ + rmd160.c \ + rsa.c \ + rsa.h \ + smallprime.c +mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs +CONFIG_HEADER = ../config.h +LIBRARIES = $(noinst_LIBRARIES) + +noinst_LIBFILES = libcipher.a + +CC = @CC@ +LEX = @LEX@ +YACC = @YACC@ + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(LDFLAGS) -o $@ +cipher_LIBADD = +cipher_OBJECTS = blowfish.o elgamal.o gost.o idea.o md5.o primegen.o \ +random.o rmd160.o rsa.o smallprime.o +EXTRA_cipher_SOURCES = +LIBFILES = libcipher.a +AR = ar +RANLIB = @RANLIB@ +DIST_COMMON = Makefile.am Makefile.in + + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA) +DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA) + +TAR = tar +DEP_FILES = $(srcdir)/.deps/blowfish.P $(srcdir)/.deps/elgamal.P \ +$(srcdir)/.deps/gost.P $(srcdir)/.deps/idea.P $(srcdir)/.deps/md5.P \ +$(srcdir)/.deps/primegen.P $(srcdir)/.deps/random.P \ +$(srcdir)/.deps/rmd160.P $(srcdir)/.deps/rsa.P \ +$(srcdir)/.deps/smallprime.P +SOURCES = $(cipher_SOURCES) +OBJECTS = $(cipher_OBJECTS) + +default: all + + +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in + cd $(top_srcdir) && automake $(subdir)/Makefile + +Makefile: $(top_builddir)/config.status Makefile.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + rm -f $(noinst_LIBFILES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) $< + +mostlyclean-compile: + rm -f *.o core + +clean-compile: + +distclean-compile: + rm -f *.tab.c + +maintainer-clean-compile: +$(cipher_OBJECTS): ../config.h + +libcipher.a: $(cipher_OBJECTS) $(cipher_LIBADD) + rm -f libcipher.a + $(AR) cru libcipher.a $(cipher_OBJECTS) $(cipher_LIBADD) + $(RANLIB) libcipher.a + +ID: $(HEADERS) $(SOURCES) + here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS) + +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) + here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + rm -f TAGS ID + +maintainer-clean-tags: + +subdir = cipher +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +distdir: $(DEP_DISTFILES) + @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \ + test -f $(distdir)/$$file \ + || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $(srcdir)/$$file $(distdir)/$$file; \ + done + +# This fragment is probably only useful for maintainers. It relies on +# GNU make and gcc. It is only included in the generated Makefile.in +# if `automake' is not passed the `--include-deps' flag. + +MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) + +-include $(srcdir)/.deps/.P +$(srcdir)/.deps/.P: $(BUILT_SOURCES) + cd $(srcdir) && test -d .deps || mkdir .deps + echo > $@ + +-include $(DEP_FILES) +$(DEP_FILES): $(srcdir)/.deps/.P + +$(srcdir)/.deps/%.P: $(srcdir)/%.c + @echo "mkdeps $< > $@" + @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \ + $(MKDEP) $< | sed "$$re" > $@-tmp + @if test -n "$o"; then \ + sed 's/\.o:/$$o:/' $@-tmp > $@; \ + rm $@-tmp; \ + else \ + mv $@-tmp $@; \ + fi + +# End of maintainer-only section +info: + +dvi: + +check: all + +installcheck: + +install-exec: + +install-data: + +install: install-exec install-data all + @: + +uninstall: + +all: $(LIBFILES) Makefile + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install +installdirs: + + +mostlyclean-generic: + test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + rm -f Makefile $(DISTCLEANFILES) + rm -f config.cache config.log $(CONFIG_HEADER) stamp-h + +maintainer-clean-generic: + test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean + +distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \ + distclean-generic clean + rm -f config.status + +maintainer-clean: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info dvi check installcheck \ +install-exec install-data install uninstall all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + +.SUFFIXES: +.SUFFIXES: .c .o + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/cipher/blowfish.c b/cipher/blowfish.c new file mode 100644 index 000000000..59f1afa8c --- /dev/null +++ b/cipher/blowfish.c @@ -0,0 +1,522 @@ +/* blowfish.c - Blowfish encryption + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * For a description of the algorithm, see: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. Pages 336 ff. + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "types.h" +#include "blowfish.h" + +/* precomputed S boxes */ +static const u32 ks0[256] = { + 0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96, + 0xBA7C9045,0xF12C7F99,0x24A19947,0xB3916CF7,0x0801F2E2,0x858EFC16, + 0x636920D8,0x71574E69,0xA458FEA3,0xF4933D7E,0x0D95748F,0x728EB658, + 0x718BCD58,0x82154AEE,0x7B54A41D,0xC25A59B5,0x9C30D539,0x2AF26013, + 0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E, + 0x6C9E0E8B,0xB01E8A3E,0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60, + 0xE65525F3,0xAA55AB94,0x57489862,0x63E81440,0x55CA396A,0x2AAB10B6, + 0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993,0xB3EE1411,0x636FBC2A, + 0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C, + 0x7A325381,0x28958677,0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193, + 0x61D809CC,0xFB21A991,0x487CAC60,0x5DEC8032,0xEF845D5D,0xE98575B1, + 0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5,0x0F6D6FF3,0x83F44239, + 0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A, + 0x670C9C61,0xABD388F0,0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3, + 0x6EEF0B6C,0x137A3BE4,0xBA3BF050,0x7EFB2A98,0xA1F1651D,0x39AF0176, + 0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4,0x7D84A5C3,0x3B8B5EBE, + 0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706, + 0x1BFEDF72,0x429B023D,0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B, + 0x075372C9,0x80991B7B,0x25D479D8,0xF6E8DEF7,0xE3FE501A,0xB6794C3B, + 0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4,0x5E5C9EC2,0x196A2463, + 0x68FB6FAF,0x3E6C53B5,0x1339B2EB,0x3B52EC6F,0x6DFC511F,0x9B30952C, + 0xCC814544,0xAF5EBD09,0xBEE3D004,0xDE334AFD,0x660F2807,0x192E4BB3, + 0xC0CBA857,0x45C8740F,0xD20B5F39,0xB9D3FBDB,0x5579C0BD,0x1A60320A, + 0xD6A100C6,0x402C7279,0x679F25FE,0xFB1FA3CC,0x8EA5E9F8,0xDB3222F8, + 0x3C7516DF,0xFD616B15,0x2F501EC8,0xAD0552AB,0x323DB5FA,0xFD238760, + 0x53317B48,0x3E00DF82,0x9E5C57BB,0xCA6F8CA0,0x1A87562E,0xDF1769DB, + 0xD542A8F6,0x287EFFC3,0xAC6732C6,0x8C4F5573,0x695B27B0,0xBBCA58C8, + 0xE1FFA35D,0xB8F011A0,0x10FA3D98,0xFD2183B8,0x4AFCB56C,0x2DD1D35B, + 0x9A53E479,0xB6F84565,0xD28E49BC,0x4BFB9790,0xE1DDF2DA,0xA4CB7E33, + 0x62FB1341,0xCEE4C6E8,0xEF20CADA,0x36774C01,0xD07E9EFE,0x2BF11FB4, + 0x95DBDA4D,0xAE909198,0xEAAD8E71,0x6B93D5A0,0xD08ED1D0,0xAFC725E0, + 0x8E3C5B2F,0x8E7594B7,0x8FF6E2FB,0xF2122B64,0x8888B812,0x900DF01C, + 0x4FAD5EA0,0x688FC31C,0xD1CFF191,0xB3A8C1AD,0x2F2F2218,0xBE0E1777, + 0xEA752DFE,0x8B021FA1,0xE5A0CC0F,0xB56F74E8,0x18ACF3D6,0xCE89E299, + 0xB4A84FE0,0xFD13E0B7,0x7CC43B81,0xD2ADA8D9,0x165FA266,0x80957705, + 0x93CC7314,0x211A1477,0xE6AD2065,0x77B5FA86,0xC75442F5,0xFB9D35CF, + 0xEBCDAF0C,0x7B3E89A0,0xD6411BD3,0xAE1E7E49,0x00250E2D,0x2071B35E, + 0x226800BB,0x57B8E0AF,0x2464369B,0xF009B91E,0x5563911D,0x59DFA6AA, + 0x78C14389,0xD95A537F,0x207D5BA2,0x02E5B9C5,0x83260376,0x6295CFA9, + 0x11C81968,0x4E734A41,0xB3472DCA,0x7B14A94A,0x1B510052,0x9A532915, + 0xD60F573F,0xBC9BC6E4,0x2B60A476,0x81E67400,0x08BA6FB5,0x571BE91F, + 0xF296EC6B,0x2A0DD915,0xB6636521,0xE7B9F9B6,0xFF34052E,0xC5855664, + 0x53B02D5D,0xA99F8FA1,0x08BA4799,0x6E85076A }; + +static const u32 ks1[256] = { + 0x4B7A70E9,0xB5B32944,0xDB75092E,0xC4192623,0xAD6EA6B0,0x49A7DF7D, + 0x9CEE60B8,0x8FEDB266,0xECAA8C71,0x699A17FF,0x5664526C,0xC2B19EE1, + 0x193602A5,0x75094C29,0xA0591340,0xE4183A3E,0x3F54989A,0x5B429D65, + 0x6B8FE4D6,0x99F73FD6,0xA1D29C07,0xEFE830F5,0x4D2D38E6,0xF0255DC1, + 0x4CDD2086,0x8470EB26,0x6382E9C6,0x021ECC5E,0x09686B3F,0x3EBAEFC9, + 0x3C971814,0x6B6A70A1,0x687F3584,0x52A0E286,0xB79C5305,0xAA500737, + 0x3E07841C,0x7FDEAE5C,0x8E7D44EC,0x5716F2B8,0xB03ADA37,0xF0500C0D, + 0xF01C1F04,0x0200B3FF,0xAE0CF51A,0x3CB574B2,0x25837A58,0xDC0921BD, + 0xD19113F9,0x7CA92FF6,0x94324773,0x22F54701,0x3AE5E581,0x37C2DADC, + 0xC8B57634,0x9AF3DDA7,0xA9446146,0x0FD0030E,0xECC8C73E,0xA4751E41, + 0xE238CD99,0x3BEA0E2F,0x3280BBA1,0x183EB331,0x4E548B38,0x4F6DB908, + 0x6F420D03,0xF60A04BF,0x2CB81290,0x24977C79,0x5679B072,0xBCAF89AF, + 0xDE9A771F,0xD9930810,0xB38BAE12,0xDCCF3F2E,0x5512721F,0x2E6B7124, + 0x501ADDE6,0x9F84CD87,0x7A584718,0x7408DA17,0xBC9F9ABC,0xE94B7D8C, + 0xEC7AEC3A,0xDB851DFA,0x63094366,0xC464C3D2,0xEF1C1847,0x3215D908, + 0xDD433B37,0x24C2BA16,0x12A14D43,0x2A65C451,0x50940002,0x133AE4DD, + 0x71DFF89E,0x10314E55,0x81AC77D6,0x5F11199B,0x043556F1,0xD7A3C76B, + 0x3C11183B,0x5924A509,0xF28FE6ED,0x97F1FBFA,0x9EBABF2C,0x1E153C6E, + 0x86E34570,0xEAE96FB1,0x860E5E0A,0x5A3E2AB3,0x771FE71C,0x4E3D06FA, + 0x2965DCB9,0x99E71D0F,0x803E89D6,0x5266C825,0x2E4CC978,0x9C10B36A, + 0xC6150EBA,0x94E2EA78,0xA5FC3C53,0x1E0A2DF4,0xF2F74EA7,0x361D2B3D, + 0x1939260F,0x19C27960,0x5223A708,0xF71312B6,0xEBADFE6E,0xEAC31F66, + 0xE3BC4595,0xA67BC883,0xB17F37D1,0x018CFF28,0xC332DDEF,0xBE6C5AA5, + 0x65582185,0x68AB9802,0xEECEA50F,0xDB2F953B,0x2AEF7DAD,0x5B6E2F84, + 0x1521B628,0x29076170,0xECDD4775,0x619F1510,0x13CCA830,0xEB61BD96, + 0x0334FE1E,0xAA0363CF,0xB5735C90,0x4C70A239,0xD59E9E0B,0xCBAADE14, + 0xEECC86BC,0x60622CA7,0x9CAB5CAB,0xB2F3846E,0x648B1EAF,0x19BDF0CA, + 0xA02369B9,0x655ABB50,0x40685A32,0x3C2AB4B3,0x319EE9D5,0xC021B8F7, + 0x9B540B19,0x875FA099,0x95F7997E,0x623D7DA8,0xF837889A,0x97E32D77, + 0x11ED935F,0x16681281,0x0E358829,0xC7E61FD6,0x96DEDFA1,0x7858BA99, + 0x57F584A5,0x1B227263,0x9B83C3FF,0x1AC24696,0xCDB30AEB,0x532E3054, + 0x8FD948E4,0x6DBC3128,0x58EBF2EF,0x34C6FFEA,0xFE28ED61,0xEE7C3C73, + 0x5D4A14D9,0xE864B7E3,0x42105D14,0x203E13E0,0x45EEE2B6,0xA3AAABEA, + 0xDB6C4F15,0xFACB4FD0,0xC742F442,0xEF6ABBB5,0x654F3B1D,0x41CD2105, + 0xD81E799E,0x86854DC7,0xE44B476A,0x3D816250,0xCF62A1F2,0x5B8D2646, + 0xFC8883A0,0xC1C7B6A3,0x7F1524C3,0x69CB7492,0x47848A0B,0x5692B285, + 0x095BBF00,0xAD19489D,0x1462B174,0x23820E00,0x58428D2A,0x0C55F5EA, + 0x1DADF43E,0x233F7061,0x3372F092,0x8D937E41,0xD65FECF1,0x6C223BDB, + 0x7CDE3759,0xCBEE7460,0x4085F2A7,0xCE77326E,0xA6078084,0x19F8509E, + 0xE8EFD855,0x61D99735,0xA969A7AA,0xC50C06C2,0x5A04ABFC,0x800BCADC, + 0x9E447A2E,0xC3453484,0xFDD56705,0x0E1E9EC9,0xDB73DBD3,0x105588CD, + 0x675FDA79,0xE3674340,0xC5C43465,0x713E38D8,0x3D28F89E,0xF16DFF20, + 0x153E21E7,0x8FB03D4A,0xE6E39F2B,0xDB83ADF7 }; + +static const u32 ks2[256] = { + 0xE93D5A68,0x948140F7,0xF64C261C,0x94692934,0x411520F7,0x7602D4F7, + 0xBCF46B2E,0xD4A20068,0xD4082471,0x3320F46A,0x43B7D4B7,0x500061AF, + 0x1E39F62E,0x97244546,0x14214F74,0xBF8B8840,0x4D95FC1D,0x96B591AF, + 0x70F4DDD3,0x66A02F45,0xBFBC09EC,0x03BD9785,0x7FAC6DD0,0x31CB8504, + 0x96EB27B3,0x55FD3941,0xDA2547E6,0xABCA0A9A,0x28507825,0x530429F4, + 0x0A2C86DA,0xE9B66DFB,0x68DC1462,0xD7486900,0x680EC0A4,0x27A18DEE, + 0x4F3FFEA2,0xE887AD8C,0xB58CE006,0x7AF4D6B6,0xAACE1E7C,0xD3375FEC, + 0xCE78A399,0x406B2A42,0x20FE9E35,0xD9F385B9,0xEE39D7AB,0x3B124E8B, + 0x1DC9FAF7,0x4B6D1856,0x26A36631,0xEAE397B2,0x3A6EFA74,0xDD5B4332, + 0x6841E7F7,0xCA7820FB,0xFB0AF54E,0xD8FEB397,0x454056AC,0xBA489527, + 0x55533A3A,0x20838D87,0xFE6BA9B7,0xD096954B,0x55A867BC,0xA1159A58, + 0xCCA92963,0x99E1DB33,0xA62A4A56,0x3F3125F9,0x5EF47E1C,0x9029317C, + 0xFDF8E802,0x04272F70,0x80BB155C,0x05282CE3,0x95C11548,0xE4C66D22, + 0x48C1133F,0xC70F86DC,0x07F9C9EE,0x41041F0F,0x404779A4,0x5D886E17, + 0x325F51EB,0xD59BC0D1,0xF2BCC18F,0x41113564,0x257B7834,0x602A9C60, + 0xDFF8E8A3,0x1F636C1B,0x0E12B4C2,0x02E1329E,0xAF664FD1,0xCAD18115, + 0x6B2395E0,0x333E92E1,0x3B240B62,0xEEBEB922,0x85B2A20E,0xE6BA0D99, + 0xDE720C8C,0x2DA2F728,0xD0127845,0x95B794FD,0x647D0862,0xE7CCF5F0, + 0x5449A36F,0x877D48FA,0xC39DFD27,0xF33E8D1E,0x0A476341,0x992EFF74, + 0x3A6F6EAB,0xF4F8FD37,0xA812DC60,0xA1EBDDF8,0x991BE14C,0xDB6E6B0D, + 0xC67B5510,0x6D672C37,0x2765D43B,0xDCD0E804,0xF1290DC7,0xCC00FFA3, + 0xB5390F92,0x690FED0B,0x667B9FFB,0xCEDB7D9C,0xA091CF0B,0xD9155EA3, + 0xBB132F88,0x515BAD24,0x7B9479BF,0x763BD6EB,0x37392EB3,0xCC115979, + 0x8026E297,0xF42E312D,0x6842ADA7,0xC66A2B3B,0x12754CCC,0x782EF11C, + 0x6A124237,0xB79251E7,0x06A1BBE6,0x4BFB6350,0x1A6B1018,0x11CAEDFA, + 0x3D25BDD8,0xE2E1C3C9,0x44421659,0x0A121386,0xD90CEC6E,0xD5ABEA2A, + 0x64AF674E,0xDA86A85F,0xBEBFE988,0x64E4C3FE,0x9DBC8057,0xF0F7C086, + 0x60787BF8,0x6003604D,0xD1FD8346,0xF6381FB0,0x7745AE04,0xD736FCCC, + 0x83426B33,0xF01EAB71,0xB0804187,0x3C005E5F,0x77A057BE,0xBDE8AE24, + 0x55464299,0xBF582E61,0x4E58F48F,0xF2DDFDA2,0xF474EF38,0x8789BDC2, + 0x5366F9C3,0xC8B38E74,0xB475F255,0x46FCD9B9,0x7AEB2661,0x8B1DDF84, + 0x846A0E79,0x915F95E2,0x466E598E,0x20B45770,0x8CD55591,0xC902DE4C, + 0xB90BACE1,0xBB8205D0,0x11A86248,0x7574A99E,0xB77F19B6,0xE0A9DC09, + 0x662D09A1,0xC4324633,0xE85A1F02,0x09F0BE8C,0x4A99A025,0x1D6EFE10, + 0x1AB93D1D,0x0BA5A4DF,0xA186F20F,0x2868F169,0xDCB7DA83,0x573906FE, + 0xA1E2CE9B,0x4FCD7F52,0x50115E01,0xA70683FA,0xA002B5C4,0x0DE6D027, + 0x9AF88C27,0x773F8641,0xC3604C06,0x61A806B5,0xF0177A28,0xC0F586E0, + 0x006058AA,0x30DC7D62,0x11E69ED7,0x2338EA63,0x53C2DD94,0xC2C21634, + 0xBBCBEE56,0x90BCB6DE,0xEBFC7DA1,0xCE591D76,0x6F05E409,0x4B7C0188, + 0x39720A3D,0x7C927C24,0x86E3725F,0x724D9DB9,0x1AC15BB4,0xD39EB8FC, + 0xED545578,0x08FCA5B5,0xD83D7CD3,0x4DAD0FC4,0x1E50EF5E,0xB161E6F8, + 0xA28514D9,0x6C51133C,0x6FD5C7E7,0x56E14EC4,0x362ABFCE,0xDDC6C837, + 0xD79A3234,0x92638212,0x670EFA8E,0x406000E0 }; + +static const u32 ks3[256] = { + 0x3A39CE37,0xD3FAF5CF,0xABC27737,0x5AC52D1B,0x5CB0679E,0x4FA33742, + 0xD3822740,0x99BC9BBE,0xD5118E9D,0xBF0F7315,0xD62D1C7E,0xC700C47B, + 0xB78C1B6B,0x21A19045,0xB26EB1BE,0x6A366EB4,0x5748AB2F,0xBC946E79, + 0xC6A376D2,0x6549C2C8,0x530FF8EE,0x468DDE7D,0xD5730A1D,0x4CD04DC6, + 0x2939BBDB,0xA9BA4650,0xAC9526E8,0xBE5EE304,0xA1FAD5F0,0x6A2D519A, + 0x63EF8CE2,0x9A86EE22,0xC089C2B8,0x43242EF6,0xA51E03AA,0x9CF2D0A4, + 0x83C061BA,0x9BE96A4D,0x8FE51550,0xBA645BD6,0x2826A2F9,0xA73A3AE1, + 0x4BA99586,0xEF5562E9,0xC72FEFD3,0xF752F7DA,0x3F046F69,0x77FA0A59, + 0x80E4A915,0x87B08601,0x9B09E6AD,0x3B3EE593,0xE990FD5A,0x9E34D797, + 0x2CF0B7D9,0x022B8B51,0x96D5AC3A,0x017DA67D,0xD1CF3ED6,0x7C7D2D28, + 0x1F9F25CF,0xADF2B89B,0x5AD6B472,0x5A88F54C,0xE029AC71,0xE019A5E6, + 0x47B0ACFD,0xED93FA9B,0xE8D3C48D,0x283B57CC,0xF8D56629,0x79132E28, + 0x785F0191,0xED756055,0xF7960E44,0xE3D35E8C,0x15056DD4,0x88F46DBA, + 0x03A16125,0x0564F0BD,0xC3EB9E15,0x3C9057A2,0x97271AEC,0xA93A072A, + 0x1B3F6D9B,0x1E6321F5,0xF59C66FB,0x26DCF319,0x7533D928,0xB155FDF5, + 0x03563482,0x8ABA3CBB,0x28517711,0xC20AD9F8,0xABCC5167,0xCCAD925F, + 0x4DE81751,0x3830DC8E,0x379D5862,0x9320F991,0xEA7A90C2,0xFB3E7BCE, + 0x5121CE64,0x774FBE32,0xA8B6E37E,0xC3293D46,0x48DE5369,0x6413E680, + 0xA2AE0810,0xDD6DB224,0x69852DFD,0x09072166,0xB39A460A,0x6445C0DD, + 0x586CDECF,0x1C20C8AE,0x5BBEF7DD,0x1B588D40,0xCCD2017F,0x6BB4E3BB, + 0xDDA26A7E,0x3A59FF45,0x3E350A44,0xBCB4CDD5,0x72EACEA8,0xFA6484BB, + 0x8D6612AE,0xBF3C6F47,0xD29BE463,0x542F5D9E,0xAEC2771B,0xF64E6370, + 0x740E0D8D,0xE75B1357,0xF8721671,0xAF537D5D,0x4040CB08,0x4EB4E2CC, + 0x34D2466A,0x0115AF84,0xE1B00428,0x95983A1D,0x06B89FB4,0xCE6EA048, + 0x6F3F3B82,0x3520AB82,0x011A1D4B,0x277227F8,0x611560B1,0xE7933FDC, + 0xBB3A792B,0x344525BD,0xA08839E1,0x51CE794B,0x2F32C9B7,0xA01FBAC9, + 0xE01CC87E,0xBCC7D1F6,0xCF0111C3,0xA1E8AAC7,0x1A908749,0xD44FBD9A, + 0xD0DADECB,0xD50ADA38,0x0339C32A,0xC6913667,0x8DF9317C,0xE0B12B4F, + 0xF79E59B7,0x43F5BB3A,0xF2D519FF,0x27D9459C,0xBF97222C,0x15E6FC2A, + 0x0F91FC71,0x9B941525,0xFAE59361,0xCEB69CEB,0xC2A86459,0x12BAA8D1, + 0xB6C1075E,0xE3056A0C,0x10D25065,0xCB03A442,0xE0EC6E0E,0x1698DB3B, + 0x4C98A0BE,0x3278E964,0x9F1F9532,0xE0D392DF,0xD3A0342B,0x8971F21E, + 0x1B0A7441,0x4BA3348C,0xC5BE7120,0xC37632D8,0xDF359F8D,0x9B992F2E, + 0xE60B6F47,0x0FE3F11D,0xE54CDA54,0x1EDAD891,0xCE6279CF,0xCD3E7E6F, + 0x1618B166,0xFD2C1D05,0x848FD2C5,0xF6FB2299,0xF523F357,0xA6327623, + 0x93A83531,0x56CCCD02,0xACF08162,0x5A75EBB5,0x6E163697,0x88D273CC, + 0xDE966292,0x81B949D0,0x4C50901B,0x71C65614,0xE6C6C7BD,0x327A140A, + 0x45E1D006,0xC3F27B9A,0xC9AA53FD,0x62A80F00,0xBB25BFE2,0x35BDD2F6, + 0x71126905,0xB2040222,0xB6CBCF7C,0xCD769C2B,0x53113EC0,0x1640E3D3, + 0x38ABBD60,0x2547ADF0,0xBA38209C,0xF746CE76,0x77AFA1C5,0x20756060, + 0x85CBFE4E,0x8AE88DD8,0x7AAAF9B0,0x4CF9AA7E,0x1948C25C,0x02FB8A8C, + 0x01C36AE4,0xD6EBE1F9,0x90D4F869,0xA65CDEA0,0x3F09252D,0xC208E69F, + 0xB74E6132,0xCE77E25B,0x578FDFE3,0x3AC372E6 }; + +static const u32 ps[BLOWFISH_ROUNDS+2] = { + 0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0, + 0x082EFA98,0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C, + 0xC0AC29B7,0xC97C50DD,0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B }; + + + + + +static u32 +function_F( BLOWFISH_context *bc, u32 x ) +{ + u16 a, b, c, d, y; + + d = x & 0x00ff; + x >>= 8; + c = x & 0x00ff; + x >>= 8; + b = x & 0x00ff; + x >>= 8; + a = x & 0x00ff; + y = bc->s0[a] + bc->s1[b]; + y ^= bc->s2[c]; + y += bc->s3[d]; + + return y; +} + + +static void +encipher( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr ) +{ + u32 xl, xr, temp; + int i; + + xl = *ret_xl; + xr = *ret_xr; + + for(i=0; i < BLOWFISH_ROUNDS; i++ ) { + xl ^= bc->p[i]; + xr ^= function_F(bc, xl); + temp = xl; + xl = xr; + xr = temp; + } + + temp = xl; + xl = xr; + xr = temp; + + xr ^= bc->p[BLOWFISH_ROUNDS]; + xl ^= bc->p[BLOWFISH_ROUNDS+1]; + + *ret_xl = xl; + *ret_xr = xr; +} + +static void +decipher( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr ) +{ + u32 xl, xr, temp; + int i; + + xl = *ret_xl; + xr = *ret_xr; + + for(i=BLOWFISH_ROUNDS+1; i > 1; i-- ) { + xl ^= bc->p[i]; + xr ^= function_F(bc, xl); + temp = xl; + xl = xr; + xr = temp; + } + + temp = xl; + xl = xr; + xr = temp; + + xr ^= bc->p[1]; + xl ^= bc->p[0]; + + *ret_xl = xl; + *ret_xr = xr; +} + +static void +encipher_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ) +{ + u32 d1, d2; + + d1 = ((u32*)inbuf)[0]; + d2 = ((u32*)inbuf)[1]; + encipher( bc, &d1, &d2 ); + ((u32*)outbuf)[0] = d1; + ((u32*)outbuf)[1] = d2; +} + +static void +decipher_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ) +{ + u32 d1, d2; + + d1 = ((u32*)inbuf)[0]; + d2 = ((u32*)inbuf)[1]; + decipher( bc, &d1, &d2 ); + ((u32*)outbuf)[0] = d1; + ((u32*)outbuf)[1] = d2; +} + + +void +blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen ) +{ + int i, j, k; + u32 data, datal, datar; + + for(i=0; i < BLOWFISH_ROUNDS+2; i++ ) + c->p[i] = ps[i]; + for(i=0; i < 256; i++ ) { + c->s0[i] = ks0[i]; + c->s1[i] = ks1[i]; + c->s2[i] = ks2[i]; + c->s3[i] = ks3[i]; + } + + for(i=j=0; i < BLOWFISH_ROUNDS+2; i++ ) { + data = 0; + for(k=0; k < 4; k++) { + data = (data << 8) | key[j]; + if( ++j >= keylen ) + j = 0; + } + c->p[i] ^= data; + } + + datal = datar = 0; + for(i=0; i < BLOWFISH_ROUNDS+2; i += 2 ) { + encipher( c, &datal, &datar ); + c->p[i] = datal; + c->p[i+1] = datar; + } + for(i=0; i < 256; i += 2 ) { + encipher( c, &datal, &datar ); + c->s0[i] = datal; + c->s0[i+1] = datar; + } + for(i=0; i < 256; i += 2 ) { + encipher( c, &datal, &datar ); + c->s1[i] = datal; + c->s1[i+1] = datar; + } + for(i=0; i < 256; i += 2 ) { + encipher( c, &datal, &datar ); + c->s2[i] = datal; + c->s2[i+1] = datar; + } + for(i=0; i < 256; i += 2 ) { + encipher( c, &datal, &datar ); + c->s3[i] = datal; + c->s3[i+1] = datar; + } +} + + +void +blowfish_setiv( BLOWFISH_context *c, byte *iv ) +{ + if( iv ) + memcpy( c->iv, iv, BLOWFISH_BLOCKSIZE ); + else + memset( c->iv, 0, BLOWFISH_BLOCKSIZE ); + c->count = 0; + encipher_block( c, c->eniv, c->iv ); +} + + +void +blowfish_encode( BLOWFISH_context *c, byte *outbuf, byte *inbuf, + unsigned nblocks ) +{ + unsigned n; + + for(n=0; n < nblocks; n++ ) { + encipher_block( c, outbuf, inbuf ); + inbuf += BLOWFISH_BLOCKSIZE;; + outbuf += BLOWFISH_BLOCKSIZE; + } +} + +void +blowfish_decode( BLOWFISH_context *c, byte *outbuf, byte *inbuf, + unsigned nblocks ) +{ + unsigned n; + + for(n=0; n < nblocks; n++ ) { + decipher_block( c, outbuf, inbuf ); + inbuf += BLOWFISH_BLOCKSIZE;; + outbuf += BLOWFISH_BLOCKSIZE; + } +} + + + +/**************** + * FIXME: Make use of bigger chunks + * (out may overlap with a or b) + */ +static void +xorblock( byte *out, byte *a, byte *b, unsigned count ) +{ + for( ; count ; count--, a++, b++ ) + *out++ = *a ^ *b ; +} + + + +/**************** + * Encode buffer in CFB mode. nbytes can be an arbitrary value. + */ +void +blowfish_encode_cfb( BLOWFISH_context *c, byte *outbuf, + byte *inbuf, unsigned nbytes) +{ + unsigned n; + + if( c->count ) { /* must make a full block first */ + assert( c->count < BLOWFISH_BLOCKSIZE ); + n = BLOWFISH_BLOCKSIZE - c->count; + if( n > nbytes ) + n = nbytes; + xorblock( outbuf, c->eniv+c->count, inbuf, n); + memcpy( c->iv+c->count, outbuf, n); + c->count += n; + nbytes -= n; + inbuf += n; + outbuf += n; + assert( c->count <= BLOWFISH_BLOCKSIZE); + if( c->count == BLOWFISH_BLOCKSIZE ) { + encipher_block( c, c->eniv, c->iv ); + c->count = 0; + } + else + return; + } + assert(!c->count); + while( nbytes >= BLOWFISH_BLOCKSIZE ) { + xorblock( outbuf, c->eniv, inbuf, BLOWFISH_BLOCKSIZE); + memcpy( c->iv, outbuf, BLOWFISH_BLOCKSIZE); + encipher_block( c, c->eniv, c->iv ); + nbytes -= BLOWFISH_BLOCKSIZE; + inbuf += BLOWFISH_BLOCKSIZE; + outbuf += BLOWFISH_BLOCKSIZE; + } + + if( nbytes ) { + xorblock( outbuf, c->eniv, inbuf, nbytes ); + memcpy( c->iv, outbuf, nbytes ); + c->count = nbytes; + } + +} + + +void +blowfish_decode_cfb( BLOWFISH_context *c, byte *outbuf, + byte *inbuf, unsigned nbytes) +{ + unsigned n; + + if( c->count ) { /* must make a full block first */ + assert( c->count < BLOWFISH_BLOCKSIZE ); + n = BLOWFISH_BLOCKSIZE - c->count; + if( n > nbytes ) + n = nbytes; + memcpy( c->iv+c->count, inbuf, n); + xorblock( outbuf, c->eniv+c->count, inbuf, n); + c->count += n; + nbytes -= n; + inbuf += n; + outbuf += n; + assert( c->count <= BLOWFISH_BLOCKSIZE); + if( c->count == BLOWFISH_BLOCKSIZE ) { + encipher_block( c, c->eniv, c->iv ); + c->count = 0; + } + else + return; + } + + assert(!c->count); + while( nbytes >= BLOWFISH_BLOCKSIZE ) { + memcpy( c->iv, inbuf, BLOWFISH_BLOCKSIZE); + xorblock( outbuf, c->eniv, inbuf, BLOWFISH_BLOCKSIZE); + encipher_block( c, c->eniv, c->iv ); + nbytes -= BLOWFISH_BLOCKSIZE; + inbuf += BLOWFISH_BLOCKSIZE; + outbuf += BLOWFISH_BLOCKSIZE; + } + + if( nbytes ) { + memcpy( c->iv, inbuf, nbytes ); + xorblock( outbuf, c->eniv, inbuf, nbytes ); + c->count = nbytes; + } + +} + diff --git a/cipher/blowfish.h b/cipher/blowfish.h new file mode 100644 index 000000000..3b01f5263 --- /dev/null +++ b/cipher/blowfish.h @@ -0,0 +1,51 @@ +/* blowfish.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_BLOWFISH_H +#define G10_BLOWFISH_H + +#include "types.h" + +#define BLOWFISH_BLOCKSIZE 8 +#define BLOWFISH_ROUNDS 16 + +typedef struct { + u32 s0[256]; + u32 s1[256]; + u32 s2[256]; + u32 s3[256]; + u32 p[BLOWFISH_ROUNDS+2]; + byte iv[BLOWFISH_BLOCKSIZE]; + byte eniv[BLOWFISH_BLOCKSIZE]; + int count; +} BLOWFISH_context; + +void blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen ); +void blowfish_setiv( BLOWFISH_context *c, byte *iv ); +void blowfish_encode( BLOWFISH_context *c, byte *outbuf, byte *inbuf, + unsigned nblocks ); +void blowfish_decode( BLOWFISH_context *c, byte *outbuf, byte *inbuf, + unsigned nblocks ); +void blowfish_encode_cfb( BLOWFISH_context *c, byte *outbuf, + byte *inbuf, unsigned nbytes); +void blowfish_decode_cfb( BLOWFISH_context *c, byte *outbuf, + byte *inbuf, unsigned nbytes); + + +#endif /*G10_BLOWFISH_H*/ diff --git a/cipher/elgamal.c b/cipher/elgamal.c new file mode 100644 index 000000000..305e1db92 --- /dev/null +++ b/cipher/elgamal.c @@ -0,0 +1,61 @@ +/* elgamal.c - ElGamal Public Key encryption + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * For a description of the algorithm, see: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. Pages 476 ff. + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "util.h" +#include "mpi.h" +#include "elgamal.h" + + +/**************** + * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT. + * + * + * + * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY. + */ +void +elg_public(MPI output, MPI input, ELG_public_key *pkey ) +{ + +} + +/**************** + * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT. + * + * + * + * Where m is OUTPUT, c is INPUT and d,n are elements of PKEY. + */ +void +elg_secret(MPI output, MPI input, ELG_secret_key *skey ) +{ + +} + + + diff --git a/cipher/elgamal.h b/cipher/elgamal.h new file mode 100644 index 000000000..3b6317599 --- /dev/null +++ b/cipher/elgamal.h @@ -0,0 +1,45 @@ +/* elgamal.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_ELGAMAL_H +#define G10_ELGAMAL_H + +#include "mpi.h" + +typedef struct { + MPI e; /* exponent */ + MPI n; /* modulus */ +} ELG_public_key; + + +typedef struct { + MPI e; /* public exponent */ + MPI n; /* public modulus */ + MPI p; /* prime p. */ + MPI q; /* prime q. */ + MPI d; /* exponent */ + MPI u; /* inverse of p mod q. */ +} ELG_secret_key; + + +void elg_public(MPI output, MPI input, ELG_public_key *skey ); +void elg_secret(MPI output, MPI input, ELG_secret_key *skey ); + + +#endif /*G10_ELGAMAL_H*/ diff --git a/cipher/gost.c b/cipher/gost.c new file mode 100644 index 000000000..21b63cbc9 --- /dev/null +++ b/cipher/gost.c @@ -0,0 +1,309 @@ +/* gost.c - GOST encryption + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * The description of GOST (and the used S-boxes) are taken from: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. . + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "util.h" +#include "types.h" +#include "gost.h" + + + +static u16 +mul_inv( u16 x ) +{ + u16 t0, t1; + u16 q, y; + + if( x < 2 ) + return x; + t1 = 0x10001L / x; + y = 0x10001L % x; + if( y == 1 ) + return (1-t1) & 0xffff; + + t0 = 1; + do { + q = x / y; + x = x % y; + t0 += q * t1; + if( x == 1 ) + return t0; + q = y / x; + y = y % x; + t1 += q * t0; + } while( y != 1 ); + return (1-t1) & 0xffff; +} + + + +static void +expand_key( byte *userkey, u16 *ek ) +{ + int i,j; + + for(j=0; j < 8; j++ ) { + ek[j] = (*userkey << 8) + userkey[1]; + userkey += 2; + } + for(i=0; j < GOST_KEYLEN; j++ ) { + i++; + ek[i+7] = ek[i&7] << 9 | ek[(i+1)&7] >> 7; + ek += i & 8; + i &= 7; + } +} + + +static void +invert_key( u16 *ek, u16 dk[GOST_KEYLEN] ) +{ + int i; + u16 t1, t2, t3; + u16 temp[GOST_KEYLEN]; + u16 *p = temp + GOST_KEYLEN; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t3; + *--p = t2; + *--p = t1; + + for(i=0; i < GOST_ROUNDS-1; i++ ) { + t1 = *ek++; + *--p = *ek++; + *--p = t1; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t3; + *--p = t2; + *--p = t1; + } + t1 = *ek++; + *--p = *ek++; + *--p = t1; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t3; + *--p = t2; + *--p = t1; + memcpy(dk, temp, sizeof(temp) ); + memset(temp, 0, sizeof(temp) ); /* burn temp */ +} + + +static void +cipher( byte *inbuf, byte *outbuf, u16 *key ) +{ + u16 x1, x2, x3,x4, s2, s3; + u16 *in, *out; + int r = GOST_ROUNDS; + #define MUL(x,y) \ + do {u16 _t16; u32 _t32; \ + if( (_t16 = (y)) ) { \ + if( (x = (x)&0xffff) ) { \ + _t32 = (u32)x * _t16; \ + x = _t32 & 0xffff; \ + _t16 = _t32 >> 16; \ + x = ((x)-_t16) + (x<_t16?1:0); \ + } \ + else { \ + x = 1 - _t16; \ + } \ + } \ + else { \ + x = 1 - x; \ + } \ + } while(0) + + in = (u16*)inbuf; + x1 = *in++; + x2 = *in++; + x3 = *in++; + x4 = *in; + #ifdef HAVE_LITTLE_ENDIAN + x1 = (x1>>8) | (x1<<8); + x2 = (x2>>8) | (x2<<8); + x3 = (x3>>8) | (x3<<8); + x4 = (x4>>8) | (x4<<8); + #endif + do { + MUL(x1, *key++); + x2 += *key++; + x3 += *key++; + MUL(x4, *key++ ); + + s3 = x3; + x3 ^= x1; + MUL(x3, *key++); + s2 = x2; + x2 ^=x4; + x2 += x3; + MUL(x2, *key++); + x3 += x2; + + x1 ^= x2; + x4 ^= x3; + + x2 ^= s3; + x3 ^= s2; + } while( --r ); + MUL(x1, *key++); + x3 += *key++; + x2 += *key++; + MUL(x4, *key); + + out = (u16*)outbuf; + #ifdef HAVE_LITTLE_ENDIAN + *out++ = (x1>>8) | (x1<<8); + *out++ = (x3>>8) | (x3<<8); + *out++ = (x2>>8) | (x2<<8); + *out = (x4>>8) | (x4<<8); + #else + *out++ = x1; + *out++ = x3; + *out++ = x2; + *out = x4; + #endif + #undef MUL +} + + +void +gost_setkey( GOST_context *c, byte *key ) +{ + expand_key( key, c->ek ); + invert_key( c->ek, c->dk ); +} + +void +gost_setiv( GOST_context *c, byte *iv ) +{ + memcpy( c->iv, iv, GOST_BLOCKSIZE ); +} + + +void +gost_encode( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nblocks ) +{ + unsigned n; + + for(n=0; n < nblocks; n++ ) { + cipher( inbuf, outbuf, c->ek ); + inbuf += 8; + outbuf += 8; + } +} + + +void +gost_decode( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nblocks ) +{ + unsigned n; + + for(n=0; n < nblocks; n++ ) { + cipher( inbuf, outbuf, c->dk ); + inbuf += 8; + outbuf += 8; + } +} + + +static void +cfbshift( byte *iv, byte *buf, unsigned count) +{ + unsigned n; + + if( count ) { + for( n = GOST_BLOCKSIZE - count; n; n--, iv++ ) + *iv = iv[count]; + for( ; count; count-- ) + *iv++ = *buf++; + } +} + + +/**************** + * FIXME: Make use of bigger chunks + */ +static void +xorblock( byte *out, byte *a, byte *b, unsigned count ) +{ + for( ; count ; count--, a++, b++ ) + *out++ = *a ^ *b ; +} + + +void +gost_encode_cfb( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nbytes) +{ + byte temp[GOST_BLOCKSIZE]; + + while( nbytes >= GOST_BLOCKSIZE ) { + cipher( c->iv, temp, c->ek ); + xorblock( outbuf, inbuf, temp, GOST_BLOCKSIZE); + cfbshift( c->iv, outbuf, GOST_BLOCKSIZE ); + nbytes -= GOST_BLOCKSIZE; + inbuf += GOST_BLOCKSIZE; + outbuf += GOST_BLOCKSIZE; + } + if( nbytes ) { + cipher( c->iv, temp, c->ek ); + xorblock( outbuf, inbuf, temp, nbytes ); + cfbshift( c->iv, outbuf, nbytes ); + } +} + + +void +gost_decode_cfb( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nbytes) +{ + byte temp[GOST_BLOCKSIZE]; + + while( nbytes >= GOST_BLOCKSIZE ) { + cipher( c->iv, temp, c->ek ); + cfbshift( c->iv, inbuf, GOST_BLOCKSIZE ); + xorblock( outbuf, inbuf, temp, GOST_BLOCKSIZE); + nbytes -= GOST_BLOCKSIZE; + inbuf += GOST_BLOCKSIZE; + outbuf += GOST_BLOCKSIZE; + } + if( nbytes ) { + cipher( c->iv, temp, c->ek ); + cfbshift( c->iv, inbuf, nbytes ); + xorblock( outbuf, inbuf, temp, nbytes ); + } +} + diff --git a/cipher/gost.h b/cipher/gost.h new file mode 100644 index 000000000..d0f4186e3 --- /dev/null +++ b/cipher/gost.h @@ -0,0 +1,46 @@ +/* gost.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_GOST_H +#define G10_GOST_H + +#include "types.h" + +#define GOST_KEYSIZE 16 +#define GOST_BLOCKSIZE 8 +#define GOST_ROUNDS 8 +#define GOST_KEYLEN (6*GOST_ROUNDS+4) + +typedef struct { + u16 ek[GOST_KEYLEN]; + u16 dk[GOST_KEYLEN]; + byte iv[GOST_BLOCKSIZE]; +} GOST_context; + +void gost_setkey( GOST_context *c, byte *key ); +void gost_setiv( GOST_context *c, byte *iv ); +void gost_encode( GOST_context *c, byte *out, byte *in, unsigned nblocks ); +void gost_decode( GOST_context *c, byte *out, byte *in, unsigned nblocks ); +void gost_encode_cfb( GOST_context *c, byte *outbuf, + byte *inbuf, unsigned nbytes); +void gost_decode_cfb( GOST_context *c, byte *outbuf, + byte *inbuf, unsigned nbytes); + + +#endif /*G10_GOST_H*/ diff --git a/cipher/idea.c b/cipher/idea.c new file mode 100644 index 000000000..3d1b01a98 --- /dev/null +++ b/cipher/idea.c @@ -0,0 +1,352 @@ +/* idea.c - IDEA function + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * ATTENTION: This code patented and needs a license for any commercial use. + * + * The code herin is take from: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. . + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "util.h" +#include "types.h" +#include "idea.h" + + + +static u16 +mul_inv( u16 x ) +{ + u16 t0, t1; + u16 q, y; + + if( x < 2 ) + return x; + t1 = 0x10001L / x; + y = 0x10001L % x; + if( y == 1 ) + return (1-t1) & 0xffff; + + t0 = 1; + do { + q = x / y; + x = x % y; + t0 += q * t1; + if( x == 1 ) + return t0; + q = y / x; + y = y % x; + t1 += q * t0; + } while( y != 1 ); + return (1-t1) & 0xffff; +} + + + +static void +expand_key( byte *userkey, u16 *ek ) +{ + int i,j; + + for(j=0; j < 8; j++ ) { + ek[j] = (*userkey << 8) + userkey[1]; + userkey += 2; + } + for(i=0; j < IDEA_KEYLEN; j++ ) { + i++; + ek[i+7] = ek[i&7] << 9 | ek[(i+1)&7] >> 7; + ek += i & 8; + i &= 7; + } +} + + +static void +invert_key( u16 *ek, u16 dk[IDEA_KEYLEN] ) +{ + int i; + u16 t1, t2, t3; + u16 temp[IDEA_KEYLEN]; + u16 *p = temp + IDEA_KEYLEN; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t3; + *--p = t2; + *--p = t1; + + for(i=0; i < IDEA_ROUNDS-1; i++ ) { + t1 = *ek++; + *--p = *ek++; + *--p = t1; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t3; + *--p = t2; + *--p = t1; + } + t1 = *ek++; + *--p = *ek++; + *--p = t1; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t3; + *--p = t2; + *--p = t1; + memcpy(dk, temp, sizeof(temp) ); + memset(temp, 0, sizeof(temp) ); /* burn temp */ +} + + +static void +cipher( byte *outbuf, byte *inbuf, u16 *key ) +{ + u16 x1, x2, x3,x4, s2, s3; + u16 *in, *out; + int r = IDEA_ROUNDS; + #define MUL(x,y) \ + do {u16 _t16; u32 _t32; \ + if( (_t16 = (y)) ) { \ + if( (x = (x)&0xffff) ) { \ + _t32 = (u32)x * _t16; \ + x = _t32 & 0xffff; \ + _t16 = _t32 >> 16; \ + x = ((x)-_t16) + (x<_t16?1:0); \ + } \ + else { \ + x = 1 - _t16; \ + } \ + } \ + else { \ + x = 1 - x; \ + } \ + } while(0) + + in = (u16*)inbuf; + x1 = *in++; + x2 = *in++; + x3 = *in++; + x4 = *in; + #ifdef HAVE_LITTLE_ENDIAN + x1 = (x1>>8) | (x1<<8); + x2 = (x2>>8) | (x2<<8); + x3 = (x3>>8) | (x3<<8); + x4 = (x4>>8) | (x4<<8); + #endif + do { + MUL(x1, *key++); + x2 += *key++; + x3 += *key++; + MUL(x4, *key++ ); + + s3 = x3; + x3 ^= x1; + MUL(x3, *key++); + s2 = x2; + x2 ^=x4; + x2 += x3; + MUL(x2, *key++); + x3 += x2; + + x1 ^= x2; + x4 ^= x3; + + x2 ^= s3; + x3 ^= s2; + } while( --r ); + MUL(x1, *key++); + x3 += *key++; + x2 += *key++; + MUL(x4, *key); + + out = (u16*)outbuf; + #ifdef HAVE_LITTLE_ENDIAN + *out++ = (x1>>8) | (x1<<8); + *out++ = (x3>>8) | (x3<<8); + *out++ = (x2>>8) | (x2<<8); + *out = (x4>>8) | (x4<<8); + #else + *out++ = x1; + *out++ = x3; + *out++ = x2; + *out = x4; + #endif + #undef MUL +} + + +void +idea_setkey( IDEA_context *c, byte *key ) +{ + expand_key( key, c->ek ); + invert_key( c->ek, c->dk ); +} + +void +idea_setiv( IDEA_context *c, byte *iv ) +{ + if( iv ) + memcpy( c->iv, iv, IDEA_BLOCKSIZE ); + else + memset( c->iv, 0, IDEA_BLOCKSIZE ); + c->nleft = 0; +} + + +void +idea_encode( IDEA_context *c, byte *outbuf, byte *inbuf, unsigned nblocks ) +{ + unsigned n; + + for(n=0; n < nblocks; n++ ) { + cipher( outbuf, inbuf, c->ek ); + inbuf += 8; + outbuf += 8; + } +} + + +void +idea_decode( IDEA_context *c, byte *outbuf, byte *inbuf, unsigned nblocks ) +{ + unsigned n; + + for(n=0; n < nblocks; n++ ) { + cipher( outbuf, inbuf, c->dk ); + inbuf += 8; + outbuf += 8; + } +} + + +static void +cfbshift( byte *iv, byte *buf, unsigned count) +{ + unsigned n; + + if( count ) { + for( n = IDEA_BLOCKSIZE - count; n; n-- ) + *iv++ = iv[count]; + for( ; count; count-- ) + *iv++ = *buf++; + } +} + + +/**************** + * FIXME: Make use of bigger chunks + */ +static void +xorblock( byte *out, byte *a, byte *b, unsigned count ) +{ + for( ; count ; count--, a++, b++ ) + *out++ = *a ^ *b ; +} + + +void +idea_encode_cfb( IDEA_context *c, byte *outbuf, byte *inbuf, unsigned nbytes) +{ + byte temp[IDEA_BLOCKSIZE]; + + while( nbytes >= IDEA_BLOCKSIZE ) { + cipher( temp, c->iv, c->ek ); + xorblock( outbuf, inbuf, temp, IDEA_BLOCKSIZE); + cfbshift( c->iv, outbuf, IDEA_BLOCKSIZE ); + nbytes -= IDEA_BLOCKSIZE; + inbuf += IDEA_BLOCKSIZE; + outbuf += IDEA_BLOCKSIZE; + } + if( nbytes ) { + cipher( temp, c->iv, c->ek ); + xorblock( outbuf, inbuf, temp, nbytes ); + cfbshift( c->iv, outbuf, nbytes ); + } +} + + +void +idea_decode_cfb( IDEA_context *c, byte *outbuf, byte *inbuf, unsigned nbytes) +{ + byte t, *ivptr; + + ivptr = c->iv + IDEA_BLOCKSIZE - c->nleft; + if( nbytes <= c->nleft ) { + c->nleft -= nbytes; + for( ; nbytes ; nbytes--, ivptr++, inbuf++ ) { + t = *ivptr; + *outbuf++ = t ^ (*ivptr = *inbuf) ; + } + return; + } + + nbytes -= c->nleft; + for( ; c->nleft ; c->nleft--, ivptr++, inbuf++ ) { + t = *ivptr; + *outbuf++ = t ^ (*ivptr = *inbuf) ; + } + + while( nbytes >= IDEA_BLOCKSIZE ) { + memcpy(c->lastcipher, c->iv, IDEA_BLOCKSIZE); + cipher( c->iv, c->iv, c->ek ); + c->nleft = IDEA_BLOCKSIZE; + nbytes -= IDEA_BLOCKSIZE; + ivptr = c->iv; + for( ; c->nleft; c->nleft--, ivptr++, inbuf++ ) { + t = *ivptr; + *outbuf++ = t ^ (*ivptr = *inbuf) ; + } + } + memcpy(c->lastcipher, c->iv, IDEA_BLOCKSIZE); + cipher( c->iv, c->iv, c->ek ); + c->nleft = IDEA_BLOCKSIZE - nbytes; + ivptr = c->iv; + for( ; nbytes; nbytes--, ivptr++, inbuf++ ) { + t = *ivptr; + *outbuf++ = t ^ (*ivptr = *inbuf) ; + } +} + + +/**************** + * This is used for the special way IDEA CFB is used in PGP + */ +void +idea_sync_cfb( IDEA_context *c ) +{ + if( c->nleft ) { + memmove(c->iv + c->nleft, c->iv, IDEA_BLOCKSIZE - c->nleft ); + memcpy(c->iv, c->lastcipher + IDEA_BLOCKSIZE - c->nleft, c->nleft); + c->nleft = 0; + } +} + + diff --git a/cipher/idea.h b/cipher/idea.h new file mode 100644 index 000000000..efebf5a56 --- /dev/null +++ b/cipher/idea.h @@ -0,0 +1,51 @@ +/* idea.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * ATTENTION: This code patented and needs a license for any commercial use. + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_IDEA_H +#define G10_IDEA_H + +#include "types.h" + +#define IDEA_KEYSIZE 16 +#define IDEA_BLOCKSIZE 8 +#define IDEA_ROUNDS 8 +#define IDEA_KEYLEN (6*IDEA_ROUNDS+4) + +typedef struct { + u16 ek[IDEA_KEYLEN]; + u16 dk[IDEA_KEYLEN]; + byte iv[IDEA_BLOCKSIZE]; + byte lastcipher[IDEA_BLOCKSIZE]; + int nleft; +} IDEA_context; + +void idea_setkey( IDEA_context *c, byte *key ); +void idea_setiv( IDEA_context *c, byte *iv ); +void idea_encode( IDEA_context *c, byte *out, byte *in, unsigned nblocks ); +void idea_decode( IDEA_context *c, byte *out, byte *in, unsigned nblocks ); +void idea_encode_cfb( IDEA_context *c, byte *outbuf, + byte *inbuf, unsigned nbytes); +void idea_decode_cfb( IDEA_context *c, byte *outbuf, + byte *inbuf, unsigned nbytes); +void idea_sync_cfb( IDEA_context *c ); + + +#endif /*G10_IDEA_H*/ diff --git a/cipher/md5.c b/cipher/md5.c new file mode 100644 index 000000000..98429ab77 --- /dev/null +++ b/cipher/md5.c @@ -0,0 +1,420 @@ +/* md5.c - MD5 Message-Digest Algorithm + * Copyright (c) 1994 by Werner Koch (dd9jn) + * + * This is a hacked version from WkLib + * + * This file is part of WkLib. + * + * WkLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * WkLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + * + * History: + * 16.01.95 wk now uses generic base-64 support + * 24.01.95 wk changed back to original base-64 coding, because + * the generic base-64 support was changed to go conform + * with RFC1113 ! + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "md5.h" +#include "memory.h" + + +#if __WATCOMC__ && defined(M_I86) + /* 16-Bit Compiler breaks Code in Function Transform() */ + /* (at least when compiling for windows) */ + #ifndef __SW_OD + #error must be compiled without optimizations + #endif +#endif + + +static void Init( MD5HANDLE mdContext); +static void Transform(u32 *buf,u32 *in); + +static byte PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G, H and I are basic MD5 functions */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (u32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (u32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (u32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (u32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* The routine Init initializes the message-digest context + * mdContext. All fields are set to zero. + * mode should be zero is reserved for extensions. + */ + +MD5HANDLE +md5_open(int secure) +{ + MD5HANDLE mdContext; + + mdContext = secure? m_alloc_secure( sizeof *mdContext ) + : m_alloc( sizeof *mdContext ); + Init(mdContext); + return mdContext; +} + + +MD5HANDLE +md5_copy( MD5HANDLE a ) +{ + MD5HANDLE mdContext; + + assert(a); + mdContext = m_is_secure(a)? m_alloc_secure( sizeof *mdContext ) + : m_alloc( sizeof *mdContext ); + memcpy( mdContext, a, sizeof *a ); + return mdContext; +} + +void +md5_close(MD5HANDLE hd) +{ + if( hd ) + m_free(hd); +} + + +static void +Init( MD5HANDLE mdContext) +{ + mdContext->i[0] = mdContext->i[1] = (u32)0; + /* Load magic initialization constants. + */ + mdContext->buf[0] = (u32)0x67452301L; + mdContext->buf[1] = (u32)0xefcdab89L; + mdContext->buf[2] = (u32)0x98badcfeL; + mdContext->buf[3] = (u32)0x10325476L; + mdContext->bufcount = 0; +} + +/* The routine Update updates the message-digest context to + * account for the presence of each of the characters inBuf[0..inLen-1] + * in the message whose digest is being computed. + */ +void +md5_write( MD5HANDLE mdContext, byte *inBuf, size_t inLen) +{ + register int i, ii; + int mdi; + u32 in[16]; + + if(mdContext->bufcount) { /* flush the buffer */ + i = mdContext->bufcount; + mdContext->bufcount = 0; + md5_write( mdContext, mdContext->digest, i); + } + if( !inBuf ) + return; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if((mdContext->i[0] + ((u32)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((u32)inLen << 3); + mdContext->i[1] += ((u32)inLen >> 29); + + while(inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if( mdi == 0x40 ) { + for(i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((u32)mdContext->in[ii+3]) << 24) | + (((u32)mdContext->in[ii+2]) << 16) | + (((u32)mdContext->in[ii+1]) << 8) | + ((u32)mdContext->in[ii]); + Transform(mdContext->buf, in); + mdi = 0; + } + } +} + + +/**************** + * Process a single character, this character will be buffered to + * increase performance. The digest-field is used as a buffer. + */ + +void +md5_putchar( MD5HANDLE mdContext, int c ) +{ + if(mdContext->bufcount == 16) + md5_write( mdContext, NULL, 0 ); + mdContext->digest[mdContext->bufcount++] = c & 0xff; +} + + + +/* The routine final terminates the message-digest computation and + * ends with the desired message digest in mdContext->digest[0...15]. + * The handle is prepared for a new MD5 cycle. + * Returns 16 bytes representing the digest. + */ + +void +md5_final(MD5HANDLE mdContext) +{ + u32 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + if(mdContext->bufcount) /* flush buffer */ + md5_write(mdContext, NULL, 0 ); + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + md5_write(mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for(i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((u32)mdContext->in[ii+3]) << 24) | + (((u32)mdContext->in[ii+2]) << 16) | + (((u32)mdContext->in[ii+1]) << 8) | + ((u32)mdContext->in[ii]); + Transform(mdContext->buf, in); + + /* store buffer in digest */ + for(i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (byte)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii+1] = (byte)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii+2] = (byte)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii+3] = (byte)((mdContext->buf[i] >> 24) & 0xFF); + } + Init(mdContext); +} + +/********** + * Returns 16 bytes representing the digest. + */ +byte * +md5_read(MD5HANDLE mdContext) +{ + return mdContext->digest; +} + + + +/**************** + * Converts the result form Read into a printable representation. + * This should only be used direct after a md5_read(), because it uses + * In-Place conversion. + * Returns digest. + */ + +char * +md5_tostring( byte *digest ) +{ + static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ." + "abcdefghijklmnopqrstuvwxyz_" + "0123456789"; + int i; + byte *d, *s; + + memmove(digest+8,digest, 16); /* make some room */ + d = digest; + s = digest+8; + for(i=0; i < 5; i++, s += 3 ) { + *d++ = bintoasc[(*s >> 2) & 077]; + *d++ = bintoasc[(((*s << 4) & 060) | ((s[1] >> 4) & 017)) & 077]; + *d++ = bintoasc[(((s[1] << 2) & 074) | ((s[2] >> 6) & 03)) & 077]; + *d++ = bintoasc[s[2] & 077]; + } + *d++ = bintoasc[(*s >> 2) & 077]; + *d++ = bintoasc[((*s << 4) & 060) & 077]; + *d = 0; + return (char*)digest; +} + + +/* Basic MD5 step. Transforms buf based on in. Note that if the Mysterious + * Constants are arranged backwards in little-endian order and decrypted with + * the DES they produce OCCULT MESSAGES! + */ +static void +Transform(register u32 *buf,register u32 *in) +{ + register u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF ( a, b, c, d, in[ 0], S11, 0xD76AA478L); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, 0xE8C7B756L); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, 0x242070DBL); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, 0xC1BDCEEEL); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, 0xF57C0FAFL); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, 0x4787C62AL); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, 0xA8304613L); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, 0xFD469501L); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, 0x698098D8L); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, 0x8B44F7AFL); /* 10 */ + FF ( c, d, a, b, in[10], S13, 0xFFFF5BB1L); /* 11 */ + FF ( b, c, d, a, in[11], S14, 0x895CD7BEL); /* 12 */ + FF ( a, b, c, d, in[12], S11, 0x6B901122L); /* 13 */ + FF ( d, a, b, c, in[13], S12, 0xFD987193L); /* 14 */ + FF ( c, d, a, b, in[14], S13, 0xA679438EL); /* 15 */ + FF ( b, c, d, a, in[15], S14, 0x49B40821L); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, 0xF61E2562L); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, 0xC040B340L); /* 18 */ + GG ( c, d, a, b, in[11], S23, 0x265E5A51L); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, 0xE9B6C7AAL); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, 0xD62F105DL); /* 21 */ + GG ( d, a, b, c, in[10], S22, 0x02441453L); /* 22 */ + GG ( c, d, a, b, in[15], S23, 0xD8A1E681L); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, 0xE7D3FBC8L); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, 0x21E1CDE6L); /* 25 */ + GG ( d, a, b, c, in[14], S22, 0xC33707D6L); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, 0xF4D50D87L); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, 0x455A14EDL); /* 28 */ + GG ( a, b, c, d, in[13], S21, 0xA9E3E905L); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, 0xFCEFA3F8L); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, 0x676F02D9L); /* 31 */ + GG ( b, c, d, a, in[12], S24, 0x8D2A4C8AL); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, 0xFFFA3942L); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, 0x8771F681L); /* 34 */ + HH ( c, d, a, b, in[11], S33, 0x6D9D6122L); /* 35 */ + HH ( b, c, d, a, in[14], S34, 0xFDE5380CL); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, 0xA4BEEA44L); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, 0x4BDECFA9L); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, 0xF6BB4B60L); /* 39 */ + HH ( b, c, d, a, in[10], S34, 0xBEBFBC70L); /* 40 */ + HH ( a, b, c, d, in[13], S31, 0x289B7EC6L); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, 0xEAA127FAL); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, 0xD4EF3085L); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, 0x04881D05L); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, 0xD9D4D039L); /* 45 */ + HH ( d, a, b, c, in[12], S32, 0xE6DB99E5L); /* 46 */ + HH ( c, d, a, b, in[15], S33, 0x1FA27CF8L); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, 0xC4AC5665L); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, 0xF4292244L); /* 49 */ + II ( d, a, b, c, in[ 7], S42, 0x432AFF97L); /* 50 */ + II ( c, d, a, b, in[14], S43, 0xAB9423A7L); /* 51 */ + II ( b, c, d, a, in[ 5], S44, 0xFC93A039L); /* 52 */ + II ( a, b, c, d, in[12], S41, 0x655B59C3L); /* 53 */ + II ( d, a, b, c, in[ 3], S42, 0x8F0CCC92L); /* 54 */ + II ( c, d, a, b, in[10], S43, 0xFFEFF47DL); /* 55 */ + II ( b, c, d, a, in[ 1], S44, 0x85845DD1L); /* 56 */ + II ( a, b, c, d, in[ 8], S41, 0x6FA87E4FL); /* 57 */ + II ( d, a, b, c, in[15], S42, 0xFE2CE6E0L); /* 58 */ + II ( c, d, a, b, in[ 6], S43, 0xA3014314L); /* 59 */ + II ( b, c, d, a, in[13], S44, 0x4E0811A1L); /* 60 */ + II ( a, b, c, d, in[ 4], S41, 0xF7537E82L); /* 61 */ + II ( d, a, b, c, in[11], S42, 0xBD3AF235L); /* 62 */ + II ( c, d, a, b, in[ 2], S43, 0x2AD7D2BBL); /* 63 */ + II ( b, c, d, a, in[ 9], S44, 0xEB86D391L); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + + + +/* end of file */ diff --git a/cipher/md5.h b/cipher/md5.h new file mode 100644 index 000000000..fa401a162 --- /dev/null +++ b/cipher/md5.h @@ -0,0 +1,44 @@ +/* md5.h - message digest 5 + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_MD5_H +#define G10_MD5_H + +#include "types.h" + +typedef struct { + u32 i[2]; /* number of _bits_ handled mod 2^64 */ + u32 buf[4]; /* scratch buffer */ + byte in[64]; /* input buffer */ + byte digest[16+8+1]; /* actual digest after Final call */ + byte bufcount; /* extra room for bintoascii */ +} *MD5HANDLE; + +/*-- md5.c --*/ +MD5HANDLE md5_open(int); +MD5HANDLE md5_copy(MD5HANDLE a); +void md5_write(MD5HANDLE hd, byte *inBuf, size_t inLen); +void md5_putchar(MD5HANDLE hd, int c ); +void md5_final(MD5HANDLE hd); +byte *md5_read(MD5HANDLE hd); +char *md5_tostring( byte *digest ); +void md5_close(MD5HANDLE hd); + + +#endif /*G10_MD5_H*/ diff --git a/cipher/primegen.c b/cipher/primegen.c new file mode 100644 index 000000000..07d83d831 --- /dev/null +++ b/cipher/primegen.c @@ -0,0 +1,152 @@ +/* primegen.c - prime number generator + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "mpi.h" +#include "cipher.h" + +static int no_of_small_prime_numbers; +static int rabin_miller( MPI n ); + + +/**************** + * Generate a prime number (stored in secure memory) + */ +MPI +generate_random_prime( unsigned nbits ) +{ + + unsigned nlimbs; + MPI prime, val_2, val_3, result; + int i; + unsigned x, step; + unsigned count1, count2; + int *mods; + + if( DBG_CIPHER ) + log_debug("generate a prime of %u bits ", nbits ); + + if( !no_of_small_prime_numbers ) { + for(i=0; small_prime_numbers[i]; i++ ) + no_of_small_prime_numbers++; + } + mods = m_alloc( no_of_small_prime_numbers * sizeof *mods ); + /* make nbits fit into MPI implementation */ + nlimbs = (nbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB; + assert( nlimbs ); + val_2 = mpi_alloc( nlimbs ); + mpi_set_ui(val_2, 2); + val_3 = mpi_alloc( nlimbs ); + mpi_set_ui(val_3, 3); + result = mpi_alloc( nlimbs ); + prime = mpi_alloc_secure( nlimbs ); + count1 = count2 = 0; + /* enter (endless) loop */ + for(;;) { + /* generate a random number */ + mpi_set_bytes( prime, nbits, get_random_byte, 2 ); + /* set high order bit to 1, set low order bit to 1 */ + mpi_set_bit( prime, nbits-1 ); + mpi_set_bit( prime, 0 ); + + /* calculate all remainders */ + for(i=0; (x = small_prime_numbers[i]); i++ ) + mods[i] = mpi_fdiv_r_ui(NULL, prime, x); + + for(step=0; step < 20000; step += 2 ) { + /* check against all the small primes we have in mods */ + count1++; + for(i=0; (x = small_prime_numbers[i]); i++ ) { + while( mods[i] + step >= x ) + mods[i] -= x; + if( !(mods[i] + step) ) + break; + } + if( x ) + continue; /* found a multiple of a already known prime */ + if( DBG_CIPHER ) + fputc('.', stderr); + + mpi_add_ui( prime, prime, step ); + + /* do a Fermat test */ + count2++; + mpi_powm( result, val_2, prime, prime ); + if( mpi_cmp_ui(result, 2) ) + continue; /* stepping (fermat test failed) */ + if( DBG_CIPHER ) + fputc('+', stderr); + /* and a second one */ + count2++; + mpi_powm( result, val_3, prime, prime ); + if( mpi_cmp_ui(result, 3) ) + continue; /* stepping (fermat test failed) */ + if( DBG_CIPHER ) + fputc('+', stderr); + + /* perform Rabin-Miller tests */ + for(i=5; i > 0; i-- ) { + if( DBG_CIPHER ) + fputc('+', stderr); + if( rabin_miller(prime) ) + break; + } + if( !i ) { + if( !mpi_test_bit( prime, nbits-1 ) ) { + if( DBG_CIPHER ) { + fputc('\n', stderr); + log_debug("overflow in prime generation\n"); + break; /* step loop, cont with a new prime */ + } + } + if( DBG_CIPHER ) { + fputc('\n', stderr); + log_debug("performed %u simple and %u Fermat/Rabin-Miller tests\n", + count1, count2 ); + log_mpidump("found prime: ", prime ); + } + + mpi_free(val_2); + mpi_free(val_3); + mpi_free(result); + m_free(mods); + return prime; + } + } + if( DBG_CIPHER ) + fputc(':', stderr); /* restart with a new random value */ + } +} + + +/**************** + * Return 1 if n is not a prime + */ +static int +rabin_miller( MPI n ) +{ + return 0; +} + diff --git a/cipher/random.c b/cipher/random.c new file mode 100644 index 000000000..73a9a3ebf --- /dev/null +++ b/cipher/random.c @@ -0,0 +1,67 @@ +/* random.c - random number generator + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include "util.h" +#include "cipher.h" + +static struct { + int level; + int len; + byte buffer[100]; /* fixme: should this be allocated in secure space? */ +} cache; + +/**************** + * Fill the buffer with LENGTH bytes of cryptologic strong + * random bytes. level 0 is not very strong, 1 is strong enough + * for most usage, 2 is good for key generation stuff but may be very slow. + */ +void +randomize_buffer( byte *buffer, size_t length, int level ) +{ + FILE *fp; + + if( level == 2 ) + level = 1; /* 2 is much too slow */ + fp = fopen(level < 2? "/dev/urandom":"/dev/random", "r"); + if( !fp ) + log_fatal("can't open random device: %s\n", strerror(errno) ); + for( ; length; length-- ) + *buffer++ = getc(fp); + fclose(fp); +} + + +byte +get_random_byte( int level ) +{ + if( !cache.len || cache.level < level ) { + randomize_buffer(cache.buffer, DIM(cache.buffer), level ); + cache.level = level; + cache.len = DIM(cache.buffer); + } + + return cache.buffer[--cache.len]; +} + + diff --git a/cipher/rmd.h b/cipher/rmd.h new file mode 100644 index 000000000..3d260cdca --- /dev/null +++ b/cipher/rmd.h @@ -0,0 +1,51 @@ +/* rmd.h - RIPE-MD hash functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_RMD_H +#define G10_RMD_H + +#include "types.h" + +typedef struct { + u32 h0,h1,h2,h3,h4; + u32 nblocks; + byte buffer[64]; + int bufcount; +} *RMDHANDLE; + + +/**************** + * Process a single character, this character will be buffered to + * increase performance. + */ +#define rmd160_putchar(h,c) \ + do { \ + if( (h)->bufcount == 64 ) \ + rmd160_write( (h), NULL, 0 ); \ + (h)->buffer[(h)->bufcount++] = (c) & 0xff; \ + } while(0) + +RMDHANDLE rmd160_open( int secure ); +RMDHANDLE rmd160_copy( RMDHANDLE a ); +void rmd160_close(RMDHANDLE hd); +void rmd160_write( RMDHANDLE hd, byte *inbuf, size_t inlen); +byte * rmd160_final(RMDHANDLE hd); + + +#endif /*G10_RMD_H*/ diff --git a/cipher/rmd160.c b/cipher/rmd160.c new file mode 100644 index 000000000..9a882fc5e --- /dev/null +++ b/cipher/rmd160.c @@ -0,0 +1,375 @@ +/* rmd160.c - RIPE-MD160 + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "memory.h" +#include "rmd.h" + +/********************************* + * RIPEMD-160 is not patented, see (as of 25.10.97) + * http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html + * Note that the code uses Little Endian byteorder, which is good for + * 386 etc, but we must add some conversion when used on a big endian box. + * + * + * Pseudo-code for RIPEMD-160 + * + * RIPEMD-160 is an iterative hash function that operates on 32-bit words. + * The round function takes as input a 5-word chaining variable and a 16-word + * message block and maps this to a new chaining variable. All operations are + * defined on 32-bit words. Padding is identical to that of MD4. + * + * + * RIPEMD-160: definitions + * + * + * nonlinear functions at bit level: exor, mux, -, mux, - + * + * f(j, x, y, z) = x XOR y XOR z (0 <= j <= 15) + * f(j, x, y, z) = (x AND y) OR (NOT(x) AND z) (16 <= j <= 31) + * f(j, x, y, z) = (x OR NOT(y)) XOR z (32 <= j <= 47) + * f(j, x, y, z) = (x AND z) OR (y AND NOT(z)) (48 <= j <= 63) + * f(j, x, y, z) = x XOR (y OR NOT(z)) (64 <= j <= 79) + * + * + * added constants (hexadecimal) + * + * K(j) = 0x00000000 (0 <= j <= 15) + * K(j) = 0x5A827999 (16 <= j <= 31) int(2**30 x sqrt(2)) + * K(j) = 0x6ED9EBA1 (32 <= j <= 47) int(2**30 x sqrt(3)) + * K(j) = 0x8F1BBCDC (48 <= j <= 63) int(2**30 x sqrt(5)) + * K(j) = 0xA953FD4E (64 <= j <= 79) int(2**30 x sqrt(7)) + * K'(j) = 0x50A28BE6 (0 <= j <= 15) int(2**30 x cbrt(2)) + * K'(j) = 0x5C4DD124 (16 <= j <= 31) int(2**30 x cbrt(3)) + * K'(j) = 0x6D703EF3 (32 <= j <= 47) int(2**30 x cbrt(5)) + * K'(j) = 0x7A6D76E9 (48 <= j <= 63) int(2**30 x cbrt(7)) + * K'(j) = 0x00000000 (64 <= j <= 79) + * + * + * selection of message word + * + * r(j) = j (0 <= j <= 15) + * r(16..31) = 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8 + * r(32..47) = 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12 + * r(48..63) = 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2 + * r(64..79) = 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 + * r0(0..15) = 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12 + * r0(16..31)= 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2 + * r0(32..47)= 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13 + * r0(48..63)= 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14 + * r0(64..79)= 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 + * + * + * amount for rotate left (rol) + * + * s(0..15) = 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8 + * s(16..31) = 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12 + * s(32..47) = 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5 + * s(48..63) = 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12 + * s(64..79) = 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 + * s'(0..15) = 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6 + * s'(16..31)= 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11 + * s'(32..47)= 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5 + * s'(48..63)= 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8 + * s'(64..79)= 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 + * + * + * initial value (hexadecimal) + * + * h0 = 0x67452301; h1 = 0xEFCDAB89; h2 = 0x98BADCFE; h3 = 0x10325476; + * h4 = 0xC3D2E1F0; + * + * + * RIPEMD-160: pseudo-code + * + * It is assumed that the message after padding consists of t 16-word blocks + * that will be denoted with X[i][j], with 0 <= i <= t-1 and 0 <= j <= 15. + * The symbol [+] denotes addition modulo 2**32 and rol_s denotes cyclic left + * shift (rotate) over s positions. + * + * + * for i := 0 to t-1 { + * A := h0; B := h1; C := h2; D = h3; E = h4; + * A' := h0; B' := h1; C' := h2; D' = h3; E' = h4; + * for j := 0 to 79 { + * T := rol_s(j)(A [+] f(j, B, C, D) [+] X[i][r(j)] [+] K(j)) [+] E; + * A := E; E := D; D := rol_10(C); C := B; B := T; + * T := rol_s'(j)(A' [+] f(79-j, B', C', D') [+] X[i][r'(j)] + [+] K'(j)) [+] E'; + * A' := E'; E' := D'; D' := rol_10(C'); C' := B'; B' := T; + * } + * T := h1 [+] C [+] D'; h1 := h2 [+] D [+] E'; h2 := h3 [+] E [+] A'; + * h3 := h4 [+] A [+] B'; h4 := h0 [+] B [+] C'; h0 := T; + * } + */ + +/* Some examples: + * "" 9c1185a5c5e9fc54612808977ee8f548b2258d31 + * "a" 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe + * "abc" 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc + * "message digest" 5d0689ef49d2fae572b881b123a85ffa21595f36 + * "a...z" f71c27109c692c1b56bbdceb5b9d2865b3708dbc + * "abcdbcde...nopq" 12a053384a9c0c88e405a06c27dcf49ada62eb2b + * "A...Za...z0...9" b0e20b6e3116640286ed3a87a5713079b21f5189 + * 8 times "1234567890" 9b752e45573d4b39f4dbd3323cab82bf63326bfb + * 1 million times "a" 52783243c1697bdbe16d37f97f68f08325dc1528 + */ + + +static void +initialize( RMDHANDLE hd ) +{ + hd->h0 = 0x67452301; + hd->h1 = 0xEFCDAB89; + hd->h2 = 0x98BADCFE; + hd->h3 = 0x10325476; + hd->h4 = 0xC3D2E1F0; + hd->bufcount = 0; + hd->nblocks = 0; +} + + +/**************** + * Transform the message X which consists of 16 32-bit-words + */ +static void +transform( RMDHANDLE hd, u32 *x ) +{ + static int r[80] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 }; + static int rr[80] = { + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 }; + static int s[80] = { + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 }; + static int ss[80] = { + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 }; + u32 a,b,c,d,e,aa,bb,cc,dd,ee,t; + int rbits, j; + +#define K(a) ( (a) < 16 ? 0x00000000 : \ + (a) < 32 ? 0x5A827999 : \ + (a) < 48 ? 0x6ED9EBA1 : \ + (a) < 64 ? 0x8F1BBCDC : 0xA953FD4E ) +#define KK(a) ( (a) < 16 ? 0x50A28BE6 : \ + (a) < 32 ? 0x5C4DD124 : \ + (a) < 48 ? 0x6D703EF3 : \ + (a) < 64 ? 0x7A6D76E9 : 0x00000000 ) + +#define F0(x,y,z) ( (x) ^ (y) ^ (z) ) +#define F1(x,y,z) ( ((x) & (y)) | (~(x) & (z)) ) +#define F2(x,y,z) ( ((x) | ~(y)) ^ (z) ) +#define F3(x,y,z) ( ((x) & (z)) | ((y) & ~(z)) ) +#define F4(x,y,z) ( (x) ^ ((y) | ~(z)) ) +#define F(a,x,y,z) ( (a) < 16 ? F0((x),(y),(z)) : \ + (a) < 32 ? F1((x),(y),(z)) : \ + (a) < 48 ? F2((x),(y),(z)) : \ + (a) < 64 ? F3((x),(y),(z)) : \ + F4((x),(y),(z)) ) + +#define rol(n,x) ( ((x) << (n)) | ((x) >> (32-(n))) ) + + a = aa = hd->h0; + b = bb = hd->h1; + c = cc = hd->h2; + d = dd = hd->h3; + e = ee = hd->h4; + + for(j=0; j < 80; j++ ) { + t = a + F( j, b, c, d ) + x[ r[j] ] + K(j); + rbits = s[j]; + a = rol(rbits, t) + e; + c = rol(10,c); + t = a; a = e; e = d; d = c; c = b; b = t; + + t = aa + F(79-j, bb, cc, dd ) + x[ rr[j] ] + KK(j); + rbits = ss[j]; + aa = rol(rbits, t) + ee; + cc = rol(10,cc); + t = aa; aa = ee; ee = dd; dd = cc; cc = bb; bb = t; + } + + t = hd->h1 + c + dd; + hd->h1 = hd->h2 + d + ee; + hd->h2 = hd->h3 + e + aa; + hd->h3 = hd->h4 + a + bb; + hd->h4 = hd->h0 + b + cc; + hd->h0 = t; +} + + + + +RMDHANDLE +rmd160_open( int secure ) +{ + RMDHANDLE hd; + + hd = secure? m_alloc_secure( sizeof *hd ) + : m_alloc( sizeof *hd ); + initialize(hd); + return hd; +} + + +RMDHANDLE +rmd160_copy( RMDHANDLE a ) +{ + RMDHANDLE b; + + assert(a); + b = m_is_secure(a)? m_alloc_secure( sizeof *b ) + : m_alloc( sizeof *b ); + memcpy( b, a, sizeof *a ); + return b; +} + +void +rmd160_close(RMDHANDLE hd) +{ + if( hd ) + m_free(hd); +} + + + +/* Update the message digest with the contents + * of INBUF with length INLEN. + */ +void +rmd160_write( RMDHANDLE hd, byte *inbuf, size_t inlen) +{ + if( hd->bufcount == 64 ) { /* flush the buffer */ + transform( hd, (u32*)hd->buffer ); + hd->bufcount = 0; + hd->nblocks++; + } + if( !inbuf ) + return; + if( hd->bufcount ) { + for( ; inlen && hd->bufcount < 64; inlen-- ) + hd->buffer[hd->bufcount++] = *inbuf++; + rmd160_write( hd, NULL, 0 ); + if( !inlen ) + return; + } + + while( inlen >= 64 ) { + transform( hd, (u32*)inbuf ); + hd->bufcount = 0; + hd->nblocks++; + inlen -= 64; + inbuf += 64; + } + for( ; inlen && hd->bufcount < 64; inlen-- ) + hd->buffer[hd->bufcount++] = *inbuf++; +} + + +/* The routine final terminates the computation and + * returns the digest. + * The handle is prepared for a new cycle, but adding bytes to the + * handle will the destroy the returned buffer. + * Returns: 20 bytes representing the digest. + */ + +byte * +rmd160_final(RMDHANDLE hd) +{ + u32 t, msb, lsb; + byte *p; + + rmd160_write(hd, NULL, 0); /* flush */; + + msb = 0; + t = hd->nblocks; + if( (lsb = t << 6) < t ) /* multiply by 64 to make a byte count */ + msb++; + msb += t >> 26; + t = lsb; + if( (lsb = t + hd->bufcount) < t ) /* add the bufcount */ + msb++; + t = lsb; + if( (lsb = t << 3) < t ) /* multiply by 8 to make a bit count */ + msb++; + msb += t >> 29; + + if( hd->bufcount < 56 ) { /* enough room */ + hd->buffer[hd->bufcount++] = 0x80; /* pad */ + while( hd->bufcount < 56 ) + hd->buffer[hd->bufcount++] = 0; /* pad */ + } + else { /* need one extra block */ + hd->buffer[hd->bufcount++] = 0x80; /* pad character */ + while( hd->bufcount < 64 ) + hd->buffer[hd->bufcount++] = 0; + rmd160_write(hd, NULL, 0); /* flush */; + memset(hd->buffer, 0, 56 ); /* fill next block with zeroes */ + } + /* append the 64 bit count */ + hd->buffer[56] = lsb ; + hd->buffer[57] = lsb >> 8; + hd->buffer[58] = lsb >> 16; + hd->buffer[59] = lsb >> 24; + hd->buffer[60] = msb ; + hd->buffer[61] = msb >> 8; + hd->buffer[62] = msb >> 16; + hd->buffer[63] = msb >> 24; + transform( hd, (u32*)hd->buffer ); + + p = hd->buffer; + #ifdef HAVE_BIG_ENDIAN + #define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ + *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0) + #else /* little endian */ + #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0) + #endif + X(0); + X(1); + X(2); + X(3); + X(4); + #undef X + + initialize( hd ); /* prepare for next cycle */ + return hd->buffer; /* now contains the digest */ +} + + diff --git a/cipher/rmd160test.c b/cipher/rmd160test.c new file mode 100644 index 000000000..365fde02c --- /dev/null +++ b/cipher/rmd160test.c @@ -0,0 +1,63 @@ +/* rmd160test.c - ripe md 160 test program + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "util.h" +#include "rmd.h" + +static void +usage(void) +{ + fprintf(stderr, "usage: rmd160test\n"); + exit(1); +} + + +int +main(int argc, char **argv) +{ + RMDHANDLE rmdhd; + int i, n; + byte buf[100], *p; + + if( argc > 1 ) + usage(); + + rmdhd = rmd160_open(0); + #if 1 + while( (n = fread( buf, 1, 100, stdin )) > 0 ) + rmd160_write(rmdhd, buf, n); + #else + for(i=0; i < 1000000; i++ ) + rmd160_putchar(rmdhd, 'a'); + #endif + p = rmd160_final(rmdhd); + for(i=0; i < 20; i++, p++ ) + printf("%02x", *p ); + putchar('\n'); + + rmd160_close(rmdhd); + return 0; +} + diff --git a/cipher/rsa.c b/cipher/rsa.c new file mode 100644 index 000000000..ec761a953 --- /dev/null +++ b/cipher/rsa.c @@ -0,0 +1,191 @@ +/* rsa.c - RSA function + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * ATTENTION: This code should not be exported from the United States + * nor should it be used their without a license agreement with PKP. + * The RSA alorithm is protected by U.S. Patent #4,405,829 which + * expires on September 20, 2000! + * + * For a description of the algorithm, see: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. Pages 466 ff. + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "util.h" +#include "mpi.h" +#include "cipher.h" + + +void +rsa_free_public_key( RSA_public_key *pk ) +{ + mpi_free( pk->n ); pk->n = NULL; + mpi_free( pk->e ); pk->e = NULL; +} + +void +rsa_free_secret_key( RSA_secret_key *sk ) +{ + mpi_free( sk->e ); sk->e = NULL; + mpi_free( sk->n ); sk->n = NULL; + mpi_free( sk->p ); sk->p = NULL; + mpi_free( sk->q ); sk->q = NULL; + mpi_free( sk->d ); sk->d = NULL; + mpi_free( sk->u ); sk->u = NULL; +} + + +static void +test_keys( RSA_public_key *pk, RSA_secret_key *sk, unsigned nbits ) +{ + MPI test = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + MPI out1 = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + MPI out2 = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + + mpi_set_bytes( test, nbits, get_random_byte, 0 ); + + rsa_public( out1, test, pk ); + rsa_secret( out2, out1, sk ); + if( mpi_cmp( test, out2 ) ) + log_fatal("RSA operation: public, secret failed\n"); + rsa_secret( out1, test, sk ); + rsa_public( out2, out1, pk ); + if( mpi_cmp( test, out2 ) ) + log_fatal("RSA operation: secret, public failed\n"); + mpi_free( test ); + mpi_free( out1 ); + mpi_free( out2 ); +} + +/**************** + * Generate a key pair with a key of size NBITS + * Returns: 2 structures filles with all needed values + */ +void +rsa_generate( RSA_public_key *pk, RSA_secret_key *sk, unsigned nbits ) +{ + MPI p, q; /* the two primes */ + MPI d; /* the private key */ + MPI u; + MPI t1, t2; + MPI n; /* the public key */ + MPI e; /* the exponent */ + MPI phi; /* helper: (p-a)(q-1) */ + + /* select two (very secret) primes */ + p = generate_random_prime( nbits / 2 ); + q = generate_random_prime( nbits / 2 ); + if( mpi_cmp( p, q ) > 0 ) /* p shall be smaller than q */ + mpi_swap(p,q); + /* calculate phi = (p-1)(q-1) */ + t1 = mpi_alloc_secure( mpi_get_nlimbs(p) ); + t2 = mpi_alloc_secure( mpi_get_nlimbs(p) ); + phi = mpi_alloc_secure( nbits / BITS_PER_MPI_LIMB ); + mpi_sub_ui( t1, p, 1 ); + mpi_sub_ui( t2, q, 1 ); + mpi_mul( phi, t1, t2 ); + /* multiply them to make the private key */ + n = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + mpi_mul( n, p, q ); + /* find a public exponent */ + e = mpi_alloc(1); + mpi_set_ui( e, 17); /* start with 17 */ + while( !mpi_gcd(t1, e, phi) ) { /* (while gcd is not 1) */ + if( DBG_CIPHER ) + log_mpidump("trying e=", e); + mpi_add_ui( e, e, 2); + } + /* calculate the secret key d = e^1 mod phi */ + d = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + mpi_inv_mod(d, e, phi ); + /* calculate the inverse of p and q (used for chinese remainder theorem)*/ + u = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + mpi_inv_mod(u, p, q ); + + if( DBG_CIPHER ) { + log_mpidump("p=", p ); + log_mpidump("q=", q ); + log_mpidump("phi=", phi ); + log_mpidump("n=", n ); + log_mpidump("e=", e ); + log_mpidump("d=", d ); + log_mpidump("u=", u ); + } + + mpi_free(t1); + mpi_free(t2); + mpi_free(phi); + + pk->n = mpi_copy(n); + pk->e = mpi_copy(e); + sk->n = n; + sk->e = e; + sk->p = p; + sk->q = q; + sk->d = d; + sk->u = u; + + /* now we can test our keys (this should never fail!) */ + test_keys( pk, sk, nbits - 16 ); +} + + + + +/**************** + * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT. + * + * c = m^e mod n + * + * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY. + */ +void +rsa_public(MPI output, MPI input, RSA_public_key *pkey ) +{ + if( output == input ) { /* powm doesn't like output and input the same */ + MPI x = mpi_alloc( mpi_get_nlimbs(input)*2 ); + mpi_powm( x, input, pkey->e, pkey->n ); + mpi_set(output, x); + mpi_free(x); + } + else + mpi_powm( output, input, pkey->e, pkey->n ); +} + +/**************** + * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT. + * + * m = c^d mod n + * + * Where m is OUTPUT, c is INPUT and d,n are elements of PKEY. + * + * FIXME: We should better use the Chinese Remainder Theorem + */ +void +rsa_secret(MPI output, MPI input, RSA_secret_key *skey ) +{ + mpi_powm( output, input, skey->d, skey->n ); +} + + + diff --git a/cipher/rsa.h b/cipher/rsa.h new file mode 100644 index 000000000..a9980d0bc --- /dev/null +++ b/cipher/rsa.h @@ -0,0 +1,53 @@ +/* rsa.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * ATTENTION: This code should not be exported from the United States + * nor should it be used their without a license agreement with PKP. + * The RSA alorithm is protected by U.S. Patent #4,405,829 which + * expires on September 20, 2000! + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_RSA_H +#define G10_RSA_H + +#include "mpi.h" + +typedef struct { + MPI e; /* exponent */ + MPI n; /* modulus */ +} RSA_public_key; + + +typedef struct { + MPI e; /* public exponent */ + MPI n; /* public modulus */ + MPI p; /* prime p. */ + MPI q; /* prime q. */ + MPI d; /* exponent */ + MPI u; /* inverse of p mod q. */ +} RSA_secret_key; + + +void rsa_free_public_key( RSA_public_key *pk ); +void rsa_free_secret_key( RSA_secret_key *sk ); +void rsa_generate( RSA_public_key *pk, RSA_secret_key *sk, unsigned nbits ); +void rsa_public(MPI output, MPI input, RSA_public_key *skey ); +void rsa_secret(MPI output, MPI input, RSA_secret_key *skey ); + + +#endif /*G10_RSA_H*/ diff --git a/cipher/smallprime.c b/cipher/smallprime.c new file mode 100644 index 000000000..74a1304a4 --- /dev/null +++ b/cipher/smallprime.c @@ -0,0 +1,114 @@ +/* smallprime.c - List of small primes + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "util.h" +#include "types.h" + +/* Note: 2 is not included because it can be testest more easily + * by looking at bit 0. The last entry in this list is marked by a zero + */ +ushort +small_prime_numbers[] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, + 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, + 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, + 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, + 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, + 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, + 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, + 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, + 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, + 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, + 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, + 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, + 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, + 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, + 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, + 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, + 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, + 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, + 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, + 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, + 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, + 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, + 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, + 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, + 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, + 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, + 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, + 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, + 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, + 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, + 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, + 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, + 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, + 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, + 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, + 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, + 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, + 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, + 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, + 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, + 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, + 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, + 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, + 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, + 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, + 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, + 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, + 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, + 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, + 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, + 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, + 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, + 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, + 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, + 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, + 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, + 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, + 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, + 4957, 4967, 4969, 4973, 4987, 4993, 4999, + 0 +}; + + diff --git a/config.h.in b/config.h.in new file mode 100644 index 000000000..1a4d6ef7e --- /dev/null +++ b/config.h.in @@ -0,0 +1,60 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ +/* acconfig.h - used by autoheader to make config.h.in + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_CONFIG_H +#define G10_CONFIG_H + + + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define as __inline if that's what the C compiler calls it. */ +#undef inline + +/* Define to `unsigned' if <sys/types.h> doesn't define. */ +#undef size_t + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +#undef M_DEBUG +#undef VERSION +#undef PACKAGE + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strtol function. */ +#undef HAVE_STRTOL + +/* Define if you have the strtoul function. */ +#undef HAVE_STRTOUL + +/* Define if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +#endif /*G10_CONFIG_H*/ diff --git a/configure.in b/configure.in new file mode 100644 index 000000000..d6eeab10b --- /dev/null +++ b/configure.in @@ -0,0 +1,54 @@ +dnl +dnl Configure template for G10 +dnl +dnl (Process this file with autoconf to produce a configure script.) + +AC_INIT(g10/g10.c) +AC_CONFIG_AUX_DIR(scripts) +AC_CONFIG_HEADER(config.h) + +VERSION=0.0.0 +PACKAGE=g10 +AC_SUBST(VERSION) +AC_SUBST(PACKAGE) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION") +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") + +AC_ARG_ENABLE(m-debug, +[ --enable-m-debug Enable debugging of memory allocation]) +if test "$enableval" = y || test "$enableval" = yes; then + AC_DEFINE(M_DEBUG) + CFLAGS="-g" +fi + +dnl Checks for programs. + +AC_PROG_MAKE_SET +AC_PROG_RANLIB +AC_PROG_INSTALL +AC_PROG_CC +AC_PROG_CPP + +AC_ARG_PROGRAM + + +dnl Checks for libraries. + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(unistd.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_TYPE_SIZE_T + +dnl Checks for library functions. +AC_FUNC_VPRINTF +AC_CHECK_FUNCS(strerror strtol strtoul) + +AC_OUTPUT([ Makefile util/Makefile mpi/Makefile cipher/Makefile \ + g10/Makefile tools/Makefile ], + [echo timestamp > stamp-h ]) + + diff --git a/g10/Makefile.am b/g10/Makefile.am new file mode 100644 index 000000000..e01940b99 --- /dev/null +++ b/g10/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +bin_PROGRAMS = g10 + +g10_SOURCES = g10.c \ + build-packet.c \ + compressed.c \ + encode.c \ + encr-data.c \ + filter.h \ + free-packet.c \ + getkey.c \ + keydb.h \ + keygen.c \ + main.h \ + mainproc.c \ + mdfilter.c \ + options.h \ + overwrite.c \ + packet.h \ + parse-packet.c \ + passphrase.c \ + plaintext.c \ + pubkey-enc.c \ + seckey-cert.c \ + seskey.c \ + sig-check.c + + +LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil + diff --git a/g10/Makefile.in b/g10/Makefile.in new file mode 100644 index 000000000..d7f9ae267 --- /dev/null +++ b/g10/Makefile.in @@ -0,0 +1,285 @@ +# Makefile.in generated automatically by automake 1.0 from Makefile.am + +# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +INCLUDES = -I$(top_srcdir)/include + +bin_PROGRAMS = g10 + +g10_SOURCES = g10.c \ + build-packet.c \ + compressed.c \ + encode.c \ + encr-data.c \ + filter.h \ + free-packet.c \ + getkey.c \ + keydb.h \ + keygen.c \ + main.h \ + mainproc.c \ + mdfilter.c \ + options.h \ + overwrite.c \ + packet.h \ + parse-packet.c \ + passphrase.c \ + plaintext.c \ + pubkey-enc.c \ + seckey-cert.c \ + seskey.c \ + sig-check.c + +LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil +mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs +CONFIG_HEADER = ../config.h +PROGRAMS = $(bin_PROGRAMS) + + +CC = @CC@ +LEX = @LEX@ +YACC = @YACC@ + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(LDFLAGS) -o $@ +g10_OBJECTS = g10.o build-packet.o compressed.o encode.o encr-data.o \ +free-packet.o getkey.o keygen.o mainproc.o mdfilter.o overwrite.o \ +parse-packet.o passphrase.o plaintext.o pubkey-enc.o seckey-cert.o \ +seskey.o sig-check.o +EXTRA_g10_SOURCES = +g10_LDADD = $(LDADD) +DIST_COMMON = Makefile.am Makefile.in + + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA) +DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA) + +TAR = tar +DEP_FILES = $(srcdir)/.deps/build-packet.P $(srcdir)/.deps/compressed.P \ +$(srcdir)/.deps/encode.P $(srcdir)/.deps/encr-data.P \ +$(srcdir)/.deps/free-packet.P $(srcdir)/.deps/g10.P \ +$(srcdir)/.deps/getkey.P $(srcdir)/.deps/keygen.P \ +$(srcdir)/.deps/mainproc.P $(srcdir)/.deps/mdfilter.P \ +$(srcdir)/.deps/overwrite.P $(srcdir)/.deps/parse-packet.P \ +$(srcdir)/.deps/passphrase.P $(srcdir)/.deps/plaintext.P \ +$(srcdir)/.deps/pubkey-enc.P $(srcdir)/.deps/seckey-cert.P \ +$(srcdir)/.deps/seskey.P $(srcdir)/.deps/sig-check.P +SOURCES = $(g10_SOURCES) +OBJECTS = $(g10_OBJECTS) + +default: all + + +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in + cd $(top_srcdir) && automake $(subdir)/Makefile + +Makefile: $(top_builddir)/config.status Makefile.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + $(mkinstalldirs) $(bindir) + list="$(bin_PROGRAMS)"; for p in $$list; do \ + if test -f $$p; then \ + $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + list="$(bin_PROGRAMS)"; for p in $$list; do \ + rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \ + done + +.c.o: + $(COMPILE) $< + +mostlyclean-compile: + rm -f *.o core + +clean-compile: + +distclean-compile: + rm -f *.tab.c + +maintainer-clean-compile: +$(g10_OBJECTS): ../config.h + +g10: $(g10_OBJECTS) $(g10_DEPENDENCIES) + $(LINK) $(g10_OBJECTS) $(g10_LDADD) $(LIBS) + +ID: $(HEADERS) $(SOURCES) + here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS) + +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) + here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + rm -f TAGS ID + +maintainer-clean-tags: + +subdir = g10 +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +distdir: $(DEP_DISTFILES) + @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \ + test -f $(distdir)/$$file \ + || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $(srcdir)/$$file $(distdir)/$$file; \ + done + +# This fragment is probably only useful for maintainers. It relies on +# GNU make and gcc. It is only included in the generated Makefile.in +# if `automake' is not passed the `--include-deps' flag. + +MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) + +-include $(srcdir)/.deps/.P +$(srcdir)/.deps/.P: $(BUILT_SOURCES) + cd $(srcdir) && test -d .deps || mkdir .deps + echo > $@ + +-include $(DEP_FILES) +$(DEP_FILES): $(srcdir)/.deps/.P + +$(srcdir)/.deps/%.P: $(srcdir)/%.c + @echo "mkdeps $< > $@" + @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \ + $(MKDEP) $< | sed "$$re" > $@-tmp + @if test -n "$o"; then \ + sed 's/\.o:/$$o:/' $@-tmp > $@; \ + rm $@-tmp; \ + else \ + mv $@-tmp $@; \ + fi + +# End of maintainer-only section +info: + +dvi: + +check: all + +installcheck: + +install-exec: install-binPROGRAMS + +install-data: + +install: install-exec install-data all + @: + +uninstall: uninstall-binPROGRAMS + +all: $(PROGRAMS) Makefile + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install +installdirs: + $(mkinstalldirs) $(bindir) + + +mostlyclean-generic: + test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + rm -f Makefile $(DISTCLEANFILES) + rm -f config.cache config.log $(CONFIG_HEADER) stamp-h + +maintainer-clean-generic: + test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +clean: clean-binPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean + +distclean: distclean-binPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean + rm -f config.status + +maintainer-clean: maintainer-clean-binPROGRAMS maintainer-clean-compile \ + maintainer-clean-tags maintainer-clean-generic \ + distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: default mostlyclean-binPROGRAMS distclean-binPROGRAMS \ +clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \ +install-binPROGRAMS mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info dvi check installcheck \ +install-exec install-data install uninstall all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + +.SUFFIXES: +.SUFFIXES: .c .o + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/g10/build-packet.c b/g10/build-packet.c new file mode 100644 index 000000000..b6e1b6fd4 --- /dev/null +++ b/g10/build-packet.c @@ -0,0 +1,386 @@ +/* build-packet.c - assemble packets and write them + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "packet.h" +#include "errors.h" +#include "iobuf.h" +#include "mpi.h" +#include "util.h" +#include "cipher.h" +#include "memory.h" +#include "options.h" + + +static int do_comment( IOBUF out, int ctb, PKT_comment *rem ); +static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid ); +static int do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pk ); +static int do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *pk ); +static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ); +static u32 calc_plaintext( PKT_plaintext *pt ); +static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt ); +static int do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed ); + +static int calc_header_length( u32 len ); +static int write_16(IOBUF inp, u16 a); +static int write_32(IOBUF inp, u32 a); +static int write_header( IOBUF out, int ctb, u32 len ); +static int write_version( IOBUF out, int ctb ); + +/**************** + * Build a packet and write it to INP + * Returns: 0 := okay + * >0 := error + * Note: Caller must free the packet + */ +int +build_packet( IOBUF out, PACKET *pkt ) +{ + int rc=0, ctb; + + if( DBG_PACKET ) + log_debug("build_packet() type=%d\n", pkt->pkttype ); + assert( pkt->pkt.generic ); + ctb = 0x80 | ((pkt->pkttype & 15)<<2); + switch( pkt->pkttype ) { + case PKT_USER_ID: + rc = do_user_id( out, ctb, pkt->pkt.user_id ); + break; + case PKT_COMMENT: + rc = do_comment( out, ctb, pkt->pkt.comment ); + break; + case PKT_PUBKEY_CERT: + rc = do_pubkey_cert( out, ctb, pkt->pkt.pubkey_cert ); + break; + case PKT_SECKEY_CERT: + rc = do_seckey_cert( out, ctb, pkt->pkt.seckey_cert ); + break; + case PKT_PUBKEY_ENC: + rc = do_pubkey_enc( out, ctb, pkt->pkt.pubkey_enc ); + break; + case PKT_PLAINTEXT: + rc = do_plaintext( out, ctb, pkt->pkt.plaintext ); + break; + case PKT_ENCR_DATA: + rc = do_encr_data( out, ctb, pkt->pkt.encr_data ); + break; + case PKT_SIGNATURE: + case PKT_RING_TRUST: + case PKT_COMPR_DATA: + default: + log_bug("invalid packet type in build_packet()"); + break; + } + + return rc; +} + +/**************** + * calculate the length of a packet described by PKT + */ +u32 +calc_packet_length( PACKET *pkt ) +{ + u32 n=0; + + assert( pkt->pkt.generic ); + switch( pkt->pkttype ) { + case PKT_PLAINTEXT: + n = calc_plaintext( pkt->pkt.plaintext ); + break; + case PKT_USER_ID: + case PKT_COMMENT: + case PKT_PUBKEY_CERT: + case PKT_SECKEY_CERT: + case PKT_PUBKEY_ENC: + case PKT_ENCR_DATA: + case PKT_SIGNATURE: + case PKT_RING_TRUST: + case PKT_COMPR_DATA: + default: + log_bug("invalid packet type in calc_packet_length()"); + break; + } + n += calc_header_length(n); + return n; +} + + +static int +do_comment( IOBUF out, int ctb, PKT_comment *rem ) +{ + write_header(out, ctb, rem->len); + if( iobuf_write( out, rem->data, rem->len ) ) + return G10ERR_WRITE_FILE; + return 0; +} + +static int +do_user_id( IOBUF out, int ctb, PKT_user_id *uid ) +{ + write_header(out, ctb, uid->len); + if( iobuf_write( out, uid->name, uid->len ) ) + return G10ERR_WRITE_FILE; + return 0; +} + +static int +do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pkc ) +{ + int rc = 0; + IOBUF a = iobuf_temp(); + + write_version( a, ctb ); + write_32(a, pkc->timestamp ); + write_16(a, pkc->valid_days ); + iobuf_put(a, pkc->pubkey_algo ); + if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { + mpi_encode(a, pkc->d.rsa.rsa_n ); + mpi_encode(a, pkc->d.rsa.rsa_e ); + } + else { + rc = G10ERR_PUBKEY_ALGO; + goto leave; + } + + write_header(out, ctb, iobuf_get_temp_length(a) ); + if( iobuf_write_temp( out, a ) ) + rc = G10ERR_WRITE_FILE; + + leave: + iobuf_close(a); + return rc; +} + +static int +do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *skc ) +{ + int rc = 0; + IOBUF a = iobuf_temp(); + + write_version( a, ctb ); + write_32(a, skc->timestamp ); + write_16(a, skc->valid_days ); + iobuf_put(a, skc->pubkey_algo ); + if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) { + mpi_encode(a, skc->d.rsa.rsa_n ); + mpi_encode(a, skc->d.rsa.rsa_e ); + iobuf_put(a, skc->d.rsa.protect_algo ); + skc->d.rsa.calc_csum = 0; + if( skc->d.rsa.protect_algo ) { + assert( skc->d.rsa.is_protected == 1 ); + assert( skc->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH ); + iobuf_write(a, skc->d.rsa.protect.blowfish.iv, 8 ); + + mpi_write_csum(a, (byte*)skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum ); + mpi_write_csum(a, (byte*)skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum ); + mpi_write_csum(a, (byte*)skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum ); + mpi_write_csum(a, (byte*)skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum ); + } + else { /* Not protected: You fool you! */ + assert( !skc->d.rsa.is_protected ); + mpi_encode_csum(a, skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum ); + mpi_encode_csum(a, skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum ); + mpi_encode_csum(a, skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum ); + mpi_encode_csum(a, skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum ); + } + + write_16(a, skc->d.rsa.calc_csum ); + } + else { + rc = G10ERR_PUBKEY_ALGO; + goto leave; + } + + write_header(out, ctb, iobuf_get_temp_length(a) ); + if( iobuf_write_temp( out, a ) ) + rc = G10ERR_WRITE_FILE; + + leave: + iobuf_close(a); + return rc; +} + +static int +do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) +{ + int rc = 0; + IOBUF a = iobuf_temp(); + + write_version( a, ctb ); + write_32(a, enc->keyid[0] ); + write_32(a, enc->keyid[1] ); + iobuf_put(a,enc->pubkey_algo ); + if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) { + mpi_encode(a, enc->d.rsa.rsa_integer ); + } + else { + rc = G10ERR_PUBKEY_ALGO; + goto leave; + } + + write_header(out, ctb, iobuf_get_temp_length(a) ); + if( iobuf_write_temp( out, a ) ) + rc = G10ERR_WRITE_FILE; + + leave: + iobuf_close(a); + return rc; +} + + +static u32 +calc_plaintext( PKT_plaintext *pt ) +{ + return pt->len? (1 + 1 + pt->namelen + 4 + pt->len) : 0; +} + +static int +do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt ) +{ + int c, i, rc = 0; + u32 n; + + write_header(out, ctb, calc_plaintext( pt ) ); + iobuf_put(out, pt->mode ); + iobuf_put(out, pt->namelen ); + for(i=0; i < pt->namelen; i++ ) + iobuf_put(out, pt->name[i] ); + if( write_32(out, pt->timestamp ) ) + rc = G10ERR_WRITE_FILE; + + n = 0; + while( (c=iobuf_get(pt->buf)) != -1 ) { + if( iobuf_put(out, c) ) { + rc = G10ERR_WRITE_FILE; + break; + } + n++; + } + if( !pt->len ) + iobuf_set_block_mode(out, 0 ); /* write end marker */ + else if( n != pt->len ) + log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n", + (ulong)n, (ulong)pt->len ); + + return rc; +} + + + +static int +do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed ) +{ + int rc = 0; + u32 n; + + n = ed->len ? (ed->len + 10) : 0; + write_header(out, ctb, n ); + + /* This is all. The caller has to write the real data */ + + return rc; +} + + + + +static int +write_16(IOBUF out, u16 a) +{ + iobuf_put(out, a>>8); + if( iobuf_put(out,a) ) + return -1; + return 0; +} + +static int +write_32(IOBUF out, u32 a) +{ + iobuf_put(out, a>> 24); + iobuf_put(out, a>> 16); + iobuf_put(out, a>> 8); + if( iobuf_put(out, a) ) + return -1; + return 0; +} + + +/**************** + * calculate the length of a header + */ +static int +calc_header_length( u32 len ) +{ + if( !len ) + return 1; /* only the ctb */ + else if( len < 256 ) + return 2; + else if( len < 65536 ) + return 3; + else + return 5; +} + +/**************** + * Write the CTB and the packet length + */ +static int +write_header( IOBUF out, int ctb, u32 len ) +{ + if( !len ) + ctb |= 3; + else if( len < 256 ) + ; + else if( len < 65536 ) + ctb |= 1; + else + ctb |= 2; + if( iobuf_put(out, ctb ) ) + return -1; + if( !len ) { + iobuf_set_block_mode(out, 5 /*8196*/ ); + } + else { + if( ctb & 2 ) { + iobuf_put(out, len >> 24 ); + iobuf_put(out, len >> 16 ); + } + if( ctb & 3 ) + iobuf_put(out, len >> 8 ); + if( iobuf_put(out, len ) ) + return -1; + } + return 0; +} + +static int +write_version( IOBUF out, int ctb ) +{ + if( iobuf_put( out, 3 ) ) + return -1; + return 0; +} + diff --git a/g10/checksig.c b/g10/checksig.c new file mode 100644 index 000000000..7f00d5801 --- /dev/null +++ b/g10/checksig.c @@ -0,0 +1,96 @@ +/* checksig.c - check a signature + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> + +#include "packet.h" +#include "iobuf.h" +#include "memory.h" +#include "util.h" +#include "cipher.h" + +static void +usage(void) +{ + fprintf(stderr, "usage: checksig textfile sigfile\n"); + exit(1); +} + + +int +main(int argc, char **argv) +{ + IOBUF a; + PACKET pkt; + PKT_signature *sig; + int rc, result, c; + FILE *fp; + MD5HANDLE md5; + + if( argc != 3 ) + usage(); + argc--; argv++; + + + if( !(a = iobuf_open(argv[1])) ) + log_fatal("can't open '%s'\n", argv[1]); + + init_packet(&pkt); + while( (rc=parse_packet(a, &pkt)) != -1 ) { + if( !rc && pkt.pkttype == PKT_SECKEY_ENC ) { + sig = pkt.pkt.signature; + printf("sig: keyid=%08lX%08lX: ", sig->keyid[0], sig->keyid[1] ); + if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) { + if( !(fp = fopen(*argv, "rb")) ) + log_fatal("can't open '%s'\n", *argv); + md5 = md5_open(0); + while( (c=getc(fp)) != EOF ) + md5_putchar(md5, c ); + fclose(fp); + result = md5_signature_check( sig, md5 ); + md5_close(md5); + } + else + result = G10ERR_DIGEST_ALGO; + } + else + result = G10ERR_PUBKEY_ALGO; + + if( !result ) + fputs( "signature is good", stdout ); + else if( result == G10ERR_DIGEST_ALGO ) + printf( "Unknown digest algorithm %d", sig->d.rsa.digest_algo); + else if( result == G10ERR_PUBKEY_ALGO ) + printf( "Unknown pubkey algorithm %d", sig->pubkey_algo); + else + fputs( g10_errstr(result), stdout); + putchar('\n'); + } + free_packet(&pkt); + } + + iobuf_close(a); + return 0; +} + + diff --git a/g10/compressed.c b/g10/compressed.c new file mode 100644 index 000000000..cc0eafcfa --- /dev/null +++ b/g10/compressed.c @@ -0,0 +1,114 @@ +/* compressed.c - process an compressed packet + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +/*#include <zlib.h>*/ +#include "util.h" +#include "memory.h" +#include "packet.h" + + +/**************** + * Handle a compressed packet + */ +int +handle_compressed( PKT_compressed *zd ) +{ + return -1; + #if 0 + int c, zrc, rc = 0; + z_stream *zs = NULL; + unsigned inbufsize = 4096; + unsigned outbufsize = 16384; + unsigned n; + byte *inbuf = NULL; + byte *outbuf = NULL; + + if( zd->algorithm != 1 ) { + rc =G10ERR_COMPR_ALGO; + goto leave; + } + + zs = m_alloc_clear( sizeof *zs ); + if( (zrc = inflateInit( zs )) != Z_OK ) { + log_fatal("zlib problem: %s\n", zs->msg? zs->msg : + zrc == Z_MEM_ERROR ? "out of core" : + zrc == Z_VERSION_ERROR ? "invalid lib version" : + "unknown error" ); + } + + inbuf = m_alloc( inbufsize ); + outbuf = m_alloc( outbufsize ); /* Fixme: put it in secure space? */ + + zs->next_in = inbuf; + zs->avail_in = inbufsize; + zs->next_out = outbuf; + zs->avail_out = outbufsize; + + n = 0; + inbuf[n++] = 0x58; + inbuf[n++] = 0x09; + for(; n < inbufsize && (c=iobuf_get(zd->buf)) != -1 ; n++ ) + inbuf[n] = c; + if( n ) { + { int i; + printf("start of compressed packet (n=%u):\n", n); + for(i=0; i < 32 && i < n; i++ ) + printf(" %02x", inbuf[i] ); + putchar('\n'); + } + zrc = inflate( zs, Z_PARTIAL_FLUSH ); + switch( zrc ) { + case Z_OK: + log_info("inflate returned okay\n"); + break; + case Z_STREAM_END: + log_info("inflate returned stream-end\n"); + break; + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_STREAM_ERROR: + case Z_MEM_ERROR: + case Z_BUF_ERROR: + default: + if( zs->msg ) + log_error("zlib inflate problem: %s\n", zs->msg ); + else + log_error("zlib inflate problem: rc=%d\n", zrc ); + break; + } + } + + leave: + if( zs ) { + inflateEnd(zs); + m_free(zs); + } + m_free(inbuf); + m_free(outbuf); + return rc; + #endif +} + diff --git a/g10/encode.c b/g10/encode.c new file mode 100644 index 000000000..5b599ef00 --- /dev/null +++ b/g10/encode.c @@ -0,0 +1,470 @@ +/* encode.c - encode/sign data + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "options.h" +#include "packet.h" +#include "errors.h" +#include "iobuf.h" +#include "keydb.h" +#include "memory.h" +#include "util.h" +#include "main.h" + + + + +static int encode_simple( const char *filename, int mode ); +static IOBUF open_outfile( const char *iname ); +static int armor_filter( void *opaque, int control, + IOBUF chain, byte *buf, size_t *ret_len); +static int compress_filter( void *opaque, int control, + IOBUF chain, byte *buf, size_t *ret_len); +static int cipher_filter( void *opaque, int control, + IOBUF chain, byte *buf, size_t *ret_len); + + + +typedef struct { + DEK *dek; + PKT_encr_data ed; + BLOWFISH_context *bf_ctx; + int header; +} cipher_filter_context_t; + + + + + + +/**************** + * Encode FILENAME only with the symmetric cipher. Take input from + * stdin if FILENAME is NULL. + */ +int +encode_symmetric( const char *filename ) +{ + return encode_simple( filename, 1 ); +} + +/**************** + * Encode FILENAME as literal data packet only. Take input from + * stdin if FILENAME is NULL. + */ +int +encode_store( const char *filename ) +{ + return encode_simple( filename, 0 ); +} + +static void +write_comment( IOBUF out, const char *s ) +{ + PACKET pkt; + size_t n = strlen(s); + int rc; + + pkt.pkttype = PKT_COMMENT; + pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n - 1 ); + pkt.pkt.comment->len = n; + strcpy(pkt.pkt.comment->data, s); + if( (rc = build_packet( out, &pkt )) ) + log_error("build_packet(comment) failed: %s\n", g10_errstr(rc) ); + free_packet( &pkt ); +} + + +static int +encode_simple( const char *filename, int mode ) +{ + IOBUF inp, out; + PACKET pkt; + PKT_plaintext *pt; + int rc = 0; + u32 filesize; + cipher_filter_context_t cfx; + + memset( &cfx, 0, sizeof cfx); + + /* prepare iobufs */ + if( !(inp = iobuf_open(filename)) ) { + log_error("can't open %s: %s\n", filename? filename: "[stdin]", + strerror(errno) ); + return G10ERR_OPEN_FILE; + } + + cfx.dek = NULL; + if( mode ) { + cfx.dek = m_alloc_secure( sizeof *cfx.dek ); + cfx.dek->algo = DEFAULT_CIPHER_ALGO; + if( (rc = make_dek_from_passphrase( cfx.dek , 2 )) ) { + m_free(cfx.dek); + iobuf_close(inp); + log_error("error creating passphrase: %s\n", g10_errstr(rc) ); + return rc; + } + } + + if( !(out = open_outfile( filename )) ) { + iobuf_close(inp); + m_free(cfx.dek); + return G10ERR_CREATE_FILE; /* or user said: do not overwrite */ + } + + if( opt.armor ) + iobuf_push_filter( out, armor_filter, NULL ); + + write_comment( out, "#Created by G10 pre-release " VERSION ); + + if( opt.compress ) + iobuf_push_filter( out, compress_filter, NULL ); + + + /* setup the inner packet */ + if( filename ) { + pt = m_alloc( sizeof *pt + strlen(filename) - 1 ); + pt->namelen = strlen(filename); + memcpy(pt->name, filename, pt->namelen ); + if( !(filesize = iobuf_get_filelength(inp)) ) + log_info("warning: '%s' is an empty file\n", filename ); + } + else { /* no filename */ + pt = m_alloc( sizeof *pt - 1 ); + pt->namelen = 0; + filesize = 0; /* stdin */ + } + pt->timestamp = make_timestamp(); + pt->mode = 'b'; + pt->len = filesize; + pt->buf = inp; + pkt.pkttype = PKT_PLAINTEXT; + pkt.pkt.plaintext = pt; + cfx.ed.len = filesize? calc_packet_length( &pkt ) : 0; + cfx.ed.buf = NULL; /* not used! */ + + /* register the cipher filter */ + if( mode ) + iobuf_push_filter( out, cipher_filter, &cfx ); + + /* do the work */ + if( (rc = build_packet( out, &pkt )) ) + log_error("build_packet failed: %s\n", g10_errstr(rc) ); + + /* finish the stuff */ + iobuf_close(inp); + iobuf_close(out); /* fixme: check returncode */ + pt->buf = NULL; + free_packet(&pkt); + m_free(cfx.dek); + return rc; +} + +/**************** + * Encrypt the file with the given userids (or ask if none + * is supplied). + */ +int +encode_crypt( const char *filename, STRLIST remusr ) +{ + IOBUF inp, out; + PACKET pkt; + PKT_plaintext *pt; + PKT_pubkey_cert *pkc = NULL; + PKT_pubkey_enc *enc = NULL; + int last_rc, rc = 0; + u32 filesize; + cipher_filter_context_t cfx; + int any_names = 0; + STRLIST local_remusr = NULL; + char *ustr; + + memset( &cfx, 0, sizeof cfx); + + if( !remusr ) { + remusr = NULL; /* fixme: ask */ + local_remusr = remusr; + } + + /* prepare iobufs */ + if( !(inp = iobuf_open(filename)) ) { + log_error("can't open %s: %s\n", filename? filename: "[stdin]", + strerror(errno) ); + free_strlist(local_remusr); + return G10ERR_OPEN_FILE; + } + else if( opt.verbose ) + log_error("reding from '%s'\n", filename? filename: "[stdin]"); + + if( !(out = open_outfile( filename )) ) { + iobuf_close(inp); + free_strlist(local_remusr); + return G10ERR_CREATE_FILE; /* or user said: do not overwrite */ + } + + if( opt.armor ) + iobuf_push_filter( out, armor_filter, NULL ); + + write_comment( out, "#Created by G10 pre-release " VERSION ); + + if( opt.compress ) + iobuf_push_filter( out, compress_filter, NULL ); + + /* create a session key */ + cfx.dek = m_alloc_secure( sizeof *cfx.dek ); + cfx.dek->algo = DEFAULT_CIPHER_ALGO; + make_session_key( cfx.dek ); + if( DBG_CIPHER ) + log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen ); + + /* loop over all user ids and build public key packets for each */ + for(last_rc=0 ; remusr; remusr = remusr->next ) { + if( pkc ) + free_pubkey_cert( pkc ); + pkc = m_alloc_clear( sizeof *pkc ); + pkc->pubkey_algo = DEFAULT_PUBKEY_ALGO; + + if( (rc = get_pubkey_by_name( pkc, remusr->d )) ) { + last_rc = rc; + log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) ); + continue; + } + /* build the pubkey packet */ + enc = m_alloc_clear( sizeof *enc ); + enc->pubkey_algo = pkc->pubkey_algo; + if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) { + RSA_public_key pkey; + + mpi_get_keyid( pkc->d.rsa.rsa_n, enc->keyid ); + enc->d.rsa.rsa_integer = encode_session_key( cfx.dek, + mpi_get_nbits(pkc->d.rsa.rsa_n) ); + pkey.n = pkc->d.rsa.rsa_n; + pkey.e = pkc->d.rsa.rsa_e; + if( DBG_CIPHER ) + log_mpidump("Plain DEK frame: ", enc->d.rsa.rsa_integer); + rsa_public( enc->d.rsa.rsa_integer, enc->d.rsa.rsa_integer, &pkey); + if( DBG_CIPHER ) + log_mpidump("Encry DEK frame: ", enc->d.rsa.rsa_integer); + if( opt.verbose ) { + ustr = get_user_id_string( enc->keyid ); + log_info("RSA enciphered for: %s\n", ustr ); + m_free(ustr); + } + } + else { + last_rc = rc = G10ERR_PUBKEY_ALGO; + log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) ); + free_pubkey_enc(enc); + continue; + } + /* and write it */ + init_packet(&pkt); + pkt.pkttype = PKT_PUBKEY_ENC; + pkt.pkt.pubkey_enc = enc; + if( (rc = build_packet( out, &pkt )) ) { + last_rc = rc; + log_error("build pubkey_enc packet failed: %s\n", g10_errstr(rc) ); + free_pubkey_enc(enc); + continue; + } + /* okay: a pubkey packet has been written */ + free_pubkey_enc(enc); + any_names = 1; + } + if( pkc ) { + free_pubkey_cert( pkc ); + pkc = NULL; + } + if( !any_names ) { + log_error("no valid keys - aborting further processing\n"); + iobuf_close(inp); + iobuf_cancel(out); + m_free(cfx.dek); /* free and burn the session key */ + free_strlist(local_remusr); + return last_rc; + } + + /* setup the inner packet */ + if( filename ) { + pt = m_alloc( sizeof *pt + strlen(filename) - 1 ); + pt->namelen = strlen(filename); + memcpy(pt->name, filename, pt->namelen ); + if( !(filesize = iobuf_get_filelength(inp)) ) + log_info("warning: '%s' is an empty file\n", filename ); + } + else { /* no filename */ + pt = m_alloc( sizeof *pt - 1 ); + pt->namelen = 0; + filesize = 0; /* stdin */ + } + pt->timestamp = make_timestamp(); + pt->mode = 'b'; + pt->len = filesize; + pt->buf = inp; + init_packet(&pkt); + pkt.pkttype = PKT_PLAINTEXT; + pkt.pkt.plaintext = pt; + cfx.ed.len = filesize? calc_packet_length( &pkt ) : 0; + cfx.ed.buf = NULL; /* not used! */ + + /* register the cipher filter */ + iobuf_push_filter( out, cipher_filter, &cfx ); + + /* do the work */ + if( (rc = build_packet( out, &pkt )) ) + log_error("build_packet failed: %s\n", g10_errstr(rc) ); + + /* finish the stuff */ + iobuf_close(inp); + iobuf_close(out); /* fixme: check returncode */ + pt->buf = NULL; + free_packet(&pkt); + m_free(cfx.dek); + free_strlist(local_remusr); + return rc; +} + + +/**************** + * Make an output filename for the inputfile INAME. + * Returns an + */ +static IOBUF +open_outfile( const char *iname ) +{ + IOBUF a = NULL; + int rc; + + if( (!iname && !opt.outfile) || opt.outfile_is_stdout ) { + if( !(a = iobuf_create(NULL)) ) + log_error("can't open [stdout]: %s\n", strerror(errno) ); + else if( opt.verbose ) + log_info("writing to stdout\n"); + } + else { + char *buf=NULL; + const char *name; + + if( opt.outfile ) + name = opt.outfile; + else { + buf = m_alloc(strlen(iname)+4+1); + strcpy(stpcpy(buf,iname), ".g10"); + name = buf; + } + if( !(rc=overwrite_filep( name )) ) { + if( !(a = iobuf_create( name )) ) + log_error("can't create %s: %s\n", name, strerror(errno) ); + else if( opt.verbose ) + log_info("writing to '%s'\n", name ); + } + else if( rc != -1 ) + log_error("oops: overwrite_filep(%s): %s\n", name, g10_errstr(rc) ); + m_free(buf); + } + return a; +} + +static int +armor_filter( void *opaque, int control, + IOBUF chain, byte *buf, size_t *ret_len) +{ + if( control == IOBUFCTRL_DESC ) { + *(char**)buf = "armor_filter"; + } + return 0; +} + +static int +compress_filter( void *opaque, int control, + IOBUF a, byte *buf, size_t *ret_len) +{ + size_t size = *ret_len; + int rc=0; + + if( control == IOBUFCTRL_FLUSH ) { + assert(a); + if( iobuf_write( a, buf, size ) ) + rc = G10ERR_WRITE_FILE; + } + else if( control == IOBUFCTRL_DESC ) { + *(char**)buf = "compress_filter"; + } + return rc; +} + + +/**************** + * The filter is used to encipher data. + */ +static int +cipher_filter( void *opaque, int control, + IOBUF a, byte *buf, size_t *ret_len) +{ + size_t size = *ret_len; + cipher_filter_context_t *cfx = opaque; + int rc=0; + + if( control == IOBUFCTRL_FLUSH ) { + assert(a); + if( !cfx->header ) { + PACKET pkt; + byte temp[10]; + + pkt.pkttype = PKT_ENCR_DATA; + pkt.pkt.encr_data = &cfx->ed; + if( build_packet( a, &pkt )) + log_bug("build_packet(ENCR_DATA) failed\n"); + randomize_buffer( temp, 8, 1 ); + temp[8] = temp[6]; + temp[9] = temp[7]; + if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH ) { + cfx->bf_ctx = m_alloc_secure( sizeof *cfx->bf_ctx ); + blowfish_setkey( cfx->bf_ctx, cfx->dek->key, cfx->dek->keylen ); + blowfish_setiv( cfx->bf_ctx, NULL ); + blowfish_encode_cfb( cfx->bf_ctx, temp, temp, 10); + } + else + log_bug("no cipher algo %d\n", cfx->dek->algo); + + iobuf_write(a, temp, 10); + cfx->header=1; + } + + if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH ) + blowfish_encode_cfb( cfx->bf_ctx, buf, buf, size); + if( iobuf_write( a, buf, size ) ) + rc = G10ERR_WRITE_FILE; + } + else if( control == IOBUFCTRL_FREE ) { + if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH ) + m_free(cfx->bf_ctx); + } + else if( control == IOBUFCTRL_DESC ) { + *(char**)buf = "cipher_filter"; + } + return rc; +} + diff --git a/g10/encr-data.c b/g10/encr-data.c new file mode 100644 index 000000000..5c047e90d --- /dev/null +++ b/g10/encr-data.c @@ -0,0 +1,122 @@ +/* encr-data.c - process an encrypted data packet + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "memory.h" +#include "packet.h" +#include "mpi.h" +#include "cipher.h" + + +static int decode_filter( void *opaque, int control, IOBUF a, + byte *buf, size_t *ret_len); + +typedef struct { + BLOWFISH_context *bf_ctx; +} decode_filter_ctx_t; + + + +/**************** + * Decrypt the data, specified by ED with the key DEK. + */ +int +decrypt_data( PKT_encr_data *ed, DEK *dek ) +{ + decode_filter_ctx_t dfx; + byte *p; + int c, i; + byte temp[16]; + + + if( dek->algo != CIPHER_ALGO_BLOWFISH ) + return G10ERR_CIPHER_ALGO; + if( ed->len && ed->len < 10 ) + log_bug("Nanu\n"); /* oops: found a bug */ + + dfx.bf_ctx = m_alloc_secure( sizeof *dfx.bf_ctx ); + blowfish_setkey( dfx.bf_ctx, dek->key, dek->keylen ); + blowfish_setiv( dfx.bf_ctx, NULL ); + + if( ed->len ) { + iobuf_set_limit( ed->buf, ed->len ); + + for(i=0; i < 10 && ed->len; i++, ed->len-- ) + temp[i] = iobuf_get(ed->buf); + } + else { + for(i=0; i < 10; i++ ) + if( (c=iobuf_get(ed->buf)) == -1 ) + break; + else + temp[i] = c; + } + blowfish_decode_cfb( dfx.bf_ctx, temp, temp, 10); + p = temp; + if( p[6] != p[8] || p[7] != p[9] ) { + m_free(dfx.bf_ctx); + return G10ERR_BAD_KEY; + } + iobuf_push_filter( ed->buf, decode_filter, &dfx ); + proc_packets(ed->buf); + iobuf_pop_filter( ed->buf, decode_filter, &dfx ); + if( ed->len ) + iobuf_set_limit( ed->buf, 0 ); /* disable the readlimit */ + else + iobuf_clear_eof( ed->buf ); + ed->buf = NULL; + m_free(dfx.bf_ctx); + return 0; +} + +static int +decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) +{ + decode_filter_ctx_t *fc = opaque; + size_t n, size = *ret_len; + int rc = 0; + int c; + + if( control == IOBUFCTRL_UNDERFLOW ) { + assert(a); + for(n=0; n < size; n++ ) { + if( (c = iobuf_get(a)) == -1 ) + break; + buf[n] = c; + } + + if( n ) + blowfish_decode_cfb( fc->bf_ctx, buf, buf, n); + else + rc = -1; /* eof */ + *ret_len = n; + } + else if( control == IOBUFCTRL_DESC ) { + *(char**)buf = "decode_filter"; + } + return rc; +} + + diff --git a/g10/filter.h b/g10/filter.h new file mode 100644 index 000000000..8cbb26af7 --- /dev/null +++ b/g10/filter.h @@ -0,0 +1,35 @@ +/* filter.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_FILTER_H +#define G10_FILTER_H + +#include "cipher.h" + +typedef struct { + MD5HANDLE md5; /* if !NULL create md5 */ + RMDHANDLE rmd160; /* if !NULL create rmd160 */ + size_t maxbuf_size; +} md_filter_context_t; + + +/*-- mdfilter.c --*/ +int md_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); + +#endif /*G10_FILTER_H*/ diff --git a/g10/free-packet.c b/g10/free-packet.c new file mode 100644 index 000000000..f4f38baa4 --- /dev/null +++ b/g10/free-packet.c @@ -0,0 +1,198 @@ +/* free-packet.c - cleanup stuff for packets + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "packet.h" +#include "iobuf.h" +#include "mpi.h" +#include "util.h" +#include "cipher.h" +#include "memory.h" + + +void +free_pubkey_enc( PKT_pubkey_enc *enc ) +{ + mpi_free( enc->d.rsa.rsa_integer ); + m_free(enc); +} + +void +free_seckey_enc( PKT_signature *enc ) +{ + mpi_free( enc->d.rsa.rsa_integer ); + m_free(enc); +} + +void +free_pubkey_cert( PKT_pubkey_cert *cert ) +{ + mpi_free( cert->d.rsa.rsa_n ); + mpi_free( cert->d.rsa.rsa_e ); + md5_close( cert->mfx.md5 ); + rmd160_close( cert->mfx.rmd160 ); + m_free(cert); +} + +PKT_pubkey_cert * +copy_pubkey_cert( PKT_pubkey_cert *d, PKT_pubkey_cert *s ) +{ + if( !d ) + d = m_alloc(sizeof *d); + memcpy( d, s, sizeof *d ); + d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n ); + d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e ); + d->mfx.md5 = NULL; + d->mfx.rmd160 =NULL; + return d; +} + +void +free_seckey_cert( PKT_seckey_cert *cert ) +{ + mpi_free( cert->d.rsa.rsa_n ); + mpi_free( cert->d.rsa.rsa_e ); + if( cert->d.rsa.is_protected ) { + m_free( cert->d.rsa.rsa_d ); + m_free( cert->d.rsa.rsa_p ); + m_free( cert->d.rsa.rsa_q ); + m_free( cert->d.rsa.rsa_u ); + } + else { + mpi_free( cert->d.rsa.rsa_d ); + mpi_free( cert->d.rsa.rsa_p ); + mpi_free( cert->d.rsa.rsa_q ); + mpi_free( cert->d.rsa.rsa_u ); + } + m_free(cert); +} + +void +free_comment( PKT_comment *rem ) +{ + m_free(rem); +} + +void +free_user_id( PKT_user_id *uid ) +{ + m_free(uid); +} + +void +free_compressed( PKT_compressed *zd ) +{ + if( zd->buf ) { /* have to skip some bytes */ + /* don't have any informations about the length, so + * we assume this is the last packet */ + while( iobuf_get(zd->buf) != -1 ) + ; + } + m_free(zd); +} + +void +free_encr_data( PKT_encr_data *ed ) +{ + if( ed->buf ) { /* have to skip some bytes */ + if( iobuf_in_block_mode(ed->buf) ) { + while( iobuf_get(ed->buf) != -1 ) + ; + iobuf_set_block_mode(ed->buf, 0); + } + else { + for( ; ed->len; ed->len-- ) /* skip the packet */ + iobuf_get(ed->buf); + } + } + m_free(ed); +} + + +void +free_plaintext( PKT_plaintext *pt ) +{ + if( pt->buf ) { /* have to skip some bytes */ + if( iobuf_in_block_mode(pt->buf) ) { + while( iobuf_get(pt->buf) != -1 ) + ; + iobuf_set_block_mode(pt->buf, 0); + } + else { + for( ; pt->len; pt->len-- ) /* skip the packet */ + iobuf_get(pt->buf); + } + } + m_free(pt); +} + +/**************** + * Free the packet in pkt. + */ +void +free_packet( PACKET *pkt ) +{ + if( !pkt || !pkt->pkt.generic ) + return; + + if( DBG_MEMORY ) + log_debug("free_packet() type=%d\n", pkt->pkttype ); + + switch( pkt->pkttype ) { + case PKT_SIGNATURE: + free_seckey_enc( pkt->pkt.signature ); + break; + case PKT_PUBKEY_ENC: + free_pubkey_enc( pkt->pkt.pubkey_enc ); + break; + case PKT_PUBKEY_CERT: + free_pubkey_cert( pkt->pkt.pubkey_cert ); + break; + case PKT_SECKEY_CERT: + free_seckey_cert( pkt->pkt.seckey_cert ); + break; + case PKT_COMMENT: + free_comment( pkt->pkt.comment ); + break; + case PKT_USER_ID: + free_user_id( pkt->pkt.user_id ); + break; + case PKT_COMPR_DATA: + free_compressed( pkt->pkt.compressed); + break; + case PKT_ENCR_DATA: + free_encr_data( pkt->pkt.encr_data ); + break; + case PKT_PLAINTEXT: + free_plaintext( pkt->pkt.plaintext ); + break; + default: + m_free( pkt->pkt.generic ); + break; + } + pkt->pkt.generic = NULL; +} + + diff --git a/g10/g10.c b/g10/g10.c new file mode 100644 index 000000000..1cf1d769a --- /dev/null +++ b/g10/g10.c @@ -0,0 +1,219 @@ +/* g10.c - The G10 re-install utility + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> + +#include "packet.h" +#include "iobuf.h" +#include "memory.h" +#include "util.h" +#include "main.h" +#include "options.h" +#include "keydb.h" +#include "mpi.h" +#include "cipher.h" + + +const char * +strusage( int level ) +{ + const char *p; + switch( level ) { + case 10: + case 0: p = "g10 - v" VERSION "; " + "Copyright 1997 Werner Koch (dd9jn)" ; break; + case 13: p = "g10"; break; + case 14: p = VERSION; break; + case 1: + case 11: p = "Usage: g10 [options] [files] (-h for help)"; + break; + case 2: + case 12: p = + "\nSyntax: g10 [options] [files]\n" + "sign, check, encrypt or decrypt\n" + "default operation depends on the input data\n"; + break; + default: p = default_strusage(level); + } + return p; +} + +static void +set_debug(void) +{ + if( opt.debug & DBG_MEMORY_VALUE ) + memory_debug_mode = 1; + if( opt.debug & DBG_MEMSTAT_VALUE ) + memory_stat_debug_mode = 1; + if( opt.debug & DBG_MPI_VALUE ) + mpi_debug_mode = 1; + if( opt.debug & DBG_CIPHER_VALUE ) + cipher_debug_mode = 1; +} + + +int +main( int argc, char **argv ) +{ + static ARGPARSE_OPTS opts[] = { + { 'a', "armor", 0, "create ascii armored output"}, + { 'v', "verbose", 0, "verbose" }, + { 'z', NULL, 1, "set compress level (0 disables)" }, + { 'b', "batch", 0, "batch mode: never ask" }, + { 'n', "dry-run", 0, "don't make any changes" }, + { 'c', "symmetric", 0, "do only a symmetric encryption" }, + { 'o', "output", 2, "use as output file" }, + { 501, "yes", 0, "assume yes on most questions"}, + { 502, "no", 0, "assume no on most questions"}, + { 503, "make-key", 0, "generate a new key pair" }, + { 504, "add-key", 0, "add key to the public keyring" }, + { 505, "delete-key",0, "remove key from public keyring" }, + { 506, "sign-key" ,0, "make a signature on a key in the keyring" }, + { 507, "store", 0, "store only" }, + { 508, "check-key" ,0, "check signatures on a key in the keyring" }, + { 509, "keyring" ,2, "add this keyring to the list of keyrings" }, + { 's', "sign", 0, "make a signature"}, + { 'e', "encrypt", 0, "encrypt data" }, + { 'd', "decrypt", 0, "decrypt data (default)" }, + { 'c', "check", 0, "check a signature (default)" }, + { 'l', "local-user",2, "use this user-id to sign or decrypt" }, + { 'r', "remote-user", 2, "use this user-id for encryption" }, + { 510, "debug" ,4|16, "set debugging flags" }, + { 511, "debug-all" ,0, "enable full debugging"}, + { 512, "cache-all" ,0, "hold everything in memory"}, + { 513, "gen-prime" , 1, "generate a prime of length n" }, + { 514, "gen-key" , 0, "generate a key pair" }, + {0} }; + ARGPARSE_ARGS pargs = { &argc, &argv, 0 }; + IOBUF a; + int rc; + enum { aNull, aSym, aStore, aEncr, aPrimegen, aKeygen, + } action = aNull; + const char *fname, *fname_print; + STRLIST sl, remusr= NULL; + int nrings=0; + + opt.compress = -1; /* defaults to default compression level */ + while( arg_parse( &pargs, opts) ) { + switch( pargs.r_opt ) { + case 'v': opt.verbose++; break; + case 'z': + opt.compress = pargs.r.ret_int; + break; + case 'a': opt.armor = 1; break; + case 'c': action = aSym; break; + case 'e': action = aEncr; break; + case 'o': opt.outfile = pargs.r.ret_str; + if( opt.outfile[0] == '-' && !opt.outfile[1] ) + opt.outfile_is_stdout = 1; + break; + case 'b': opt.batch = 1; break; + case 501: opt.answer_yes = 1; break; + case 502: opt.answer_no = 1; break; + case 507: action = aStore; break; + case 508: opt.check_sigs = 1; break; + case 509: add_keyring(pargs.r.ret_str); nrings++; break; + case 510: opt.debug |= pargs.r.ret_ulong; break; + case 511: opt.debug = ~0; break; + case 512: opt.cache_all = 1; break; + case 'r': /* store the remote users */ + sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str)); + strcpy(sl->d, pargs.r.ret_str); + sl->next = remusr; + remusr = sl; + break; + case 513: action = aPrimegen; break; + case 514: action = aKeygen; break; + default : pargs.err = 2; break; + } + } + set_debug(); + if( opt.verbose > 1 ) + set_packet_list_mode(1); + + if( !nrings ) { /* add default rings */ + add_keyring("../keys/ring.pgp"); + add_keyring("../keys/pubring.g10"); + } + + if( argc ) { + fname_print = fname = *argv; + } + else { + fname_print = "[stdin]"; + fname = NULL; + } + + switch( action ) { + case aStore: /* only store the file */ + if( argc > 1 ) + usage(1); + if( (rc = encode_store(fname)) ) + log_error("encode_store('%s'): %s\n", + fname_print, g10_errstr(rc) ); + break; + + case aSym: /* encrypt the given file only with the symmetric cipher */ + if( argc > 1 ) + usage(1); + if( (rc = encode_symmetric(fname)) ) + log_error("encode_symmetric('%s'): %s\n", + fname_print, g10_errstr(rc) ); + break; + + case aEncr: /* encrypt the given file */ + if( argc > 1 ) + usage(1); + if( (rc = encode_crypt(fname,remusr)) ) + log_error("encode_crypt('%s'): %s\n", + fname_print, g10_errstr(rc) ); + break; + + case aPrimegen: + if( argc ) + usage(1); + mpi_print( stdout, generate_random_prime( pargs.r.ret_int ), 1); + putchar('\n'); + break; + + case aKeygen: /* generate a key (interactive) */ + if( argc ) + usage(1); + generate_keypair(); + break; + + default: + if( argc > 1 ) + usage(1); + if( !(a = iobuf_open(fname)) ) + log_fatal("can't open '%s'\n", fname_print); + proc_packets( a ); + iobuf_close(a); + break; + } + + /* cleanup */ + FREE_STRLIST(remusr); + return 0; +} + + diff --git a/g10/getkey.c b/g10/getkey.c new file mode 100644 index 000000000..0bd14063b --- /dev/null +++ b/g10/getkey.c @@ -0,0 +1,475 @@ +/* getkey.c - Get a key from the database + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "packet.h" +#include "memory.h" +#include "iobuf.h" +#include "keydb.h" +#include "options.h" + +#define MAX_PKC_CACHE_ENTRIES 500 + + +typedef struct keyid_list { + struct keyid_list *next; + u32 keyid[2]; +} *keyid_list_t; + +typedef struct user_id_db { + struct user_id_db *next; + u32 keyid[2]; + int len; + char name[1]; +} *user_id_db_t; + +typedef struct pkc_cache_entry { + struct pkc_cache_entry *next; + u32 keyid[2]; + PKT_pubkey_cert *pkc; +} *pkc_cache_entry_t; + +static STRLIST keyrings; + +static keyid_list_t unknown_keyids; +static user_id_db_t user_id_db; +static pkc_cache_entry_t pkc_cache; +static int pkc_cache_entries; /* number of entries in pkc cache */ + + +static int scan_keyring( PKT_pubkey_cert *pkc, u32 *keyid, + const char *name, const char *filename ); +static int scan_secret_keyring( PACKET *pkt, u32 *keyid, const char *filename); + + +void +add_keyring( const char *name ) +{ + STRLIST sl; + + /* FIXME: check wether this one is available etc */ + /* my be we should do this later */ + sl = m_alloc( sizeof *sl + strlen(name) ); + strcpy(sl->d, name ); + sl->next = keyrings; + keyrings = sl; +} + + +void +cache_pubkey_cert( PKT_pubkey_cert *pkc ) +{ + pkc_cache_entry_t ce; + u32 keyid[2]; + + if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { + mpi_get_keyid( pkc->d.rsa.rsa_n, keyid ); + } + else + return; /* don't know how to get the keyid */ + + for( ce = pkc_cache; ce; ce = ce->next ) + if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) { + if( DBG_CACHE ) + log_debug("cache_pubkey_cert: already in cache\n"); + return; + } + + if( pkc_cache_entries > MAX_PKC_CACHE_ENTRIES ) { + /* FIMXE: use another algorithm to free some cache slots */ + if( pkc_cache_entries == MAX_PKC_CACHE_ENTRIES ) { + pkc_cache_entries++; + log_info("too many entries in pkc cache - disabled\n"); + } + ce = pkc_cache; + free_pubkey_cert( ce->pkc ); + } + else { + pkc_cache_entries++; + ce = m_alloc( sizeof *ce ); + ce->next = pkc_cache; + pkc_cache = ce; + } + ce->pkc = copy_pubkey_cert( NULL, pkc ); + ce->keyid[0] = keyid[0]; + ce->keyid[1] = keyid[1]; +} + + +/**************** + * Store the association of keyid and userid + */ +void +cache_user_id( PKT_user_id *uid, u32 *keyid ) +{ + user_id_db_t r; + + for(r=user_id_db; r; r = r->next ) + if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) { + if( DBG_CACHE ) + log_debug("cache_user_id: already in cache\n"); + return; + } + + r = m_alloc( sizeof *r + uid->len-1 ); + r->keyid[0] = keyid[0]; + r->keyid[1] = keyid[1]; + r->len = uid->len; + memcpy(r->name, uid->name, r->len); + r->next = user_id_db; + user_id_db = r; +} + + + +/**************** + * Get a public key and store it into the allocated pkc + * can be called with PKC set to NULL to just read it into some + * internal structures. + */ +int +get_pubkey( PKT_pubkey_cert *pkc, u32 *keyid ) +{ + keyid_list_t kl; + int internal = 0; + int rc = 0; + pkc_cache_entry_t ce; + STRLIST sl; + + + if( opt.cache_all && !pkc_cache ) { + log_info("reading all entries ...\n"); + for(sl = keyrings; sl; sl = sl->next ) + if( !scan_keyring( NULL, NULL, NULL, sl->d ) ) + goto leave; + log_info("cached %d entries\n", pkc_cache_entries); + } + + + /* lets see wether we checked the keyid already */ + for( kl = unknown_keyids; kl; kl = kl->next ) + if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] ) + return G10ERR_NO_PUBKEY; /* already checked and not found */ + + /* 1. Try to get it from our cache */ + for( ce = pkc_cache; ce; ce = ce->next ) + if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) { + if( pkc ) + copy_pubkey_cert( pkc, ce->pkc ); + return 0; + } + + /* more init stuff */ + if( !pkc ) { + pkc = m_alloc_clear( sizeof *pkc ); + internal++; + } + + + /* 2. Try to get it from the keyrings */ + for(sl = keyrings; sl; sl = sl->next ) + if( !scan_keyring( pkc, keyid, NULL, sl->d ) ) + goto leave; + + /* 3. Try to get it from a key server */ + + /* 4. not found: store it for future reference */ + kl = m_alloc( sizeof *kl ); + kl->keyid[0] = keyid[0]; + kl->keyid[1] = keyid[1]; + kl->next = unknown_keyids; + unknown_keyids = kl; + rc = G10ERR_NO_PUBKEY; + + leave: + if( !rc ) + cache_pubkey_cert( pkc ); + if( internal ) + m_free(pkc); + return rc; +} + + +/**************** + * Try to get the pubkey by the userid. This functions looks for the + * first pubkey certificate which has the given name in a user_id. + * if pkc has the pubkey algo set, the function will only return + * a pubkey with that algo. + */ +int +get_pubkey_by_name( PKT_pubkey_cert *pkc, const char *name ) +{ + int internal = 0; + int rc = 0; + STRLIST sl; + + if( !pkc ) { + pkc = m_alloc_clear( sizeof *pkc ); + internal++; + } + + /* 2. Try to get it from the keyrings */ + for(sl = keyrings; sl; sl = sl->next ) + if( !scan_keyring( pkc, NULL, name, sl->d ) ) + goto leave; + + /* 3. Try to get it from a key server */ + + /* 4. not found: store it for future reference */ + rc = G10ERR_NO_PUBKEY; + + leave: + if( internal ) + m_free(pkc); + return rc; +} + + +/**************** + * Get a secret key and store it into skey + */ +int +get_seckey( RSA_secret_key *skey, u32 *keyid ) +{ + int rc=0; + PACKET pkt; + + init_packet( &pkt ); + if( !(rc=scan_secret_keyring( &pkt, keyid, "../keys/secring.g10" ) ) ) + goto found; + /* fixme: look at other places */ + goto leave; + + found: + /* get the secret key (this may prompt for a passprase to + * unlock the secret key + */ + if( (rc = check_secret_key( pkt.pkt.seckey_cert )) ) + goto leave; + if( pkt.pkt.seckey_cert->pubkey_algo != PUBKEY_ALGO_RSA ) { + rc = G10ERR_PUBKEY_ALGO; /* unsupport algorithm */ + goto leave; + } + /* copy the stuff to SKEY. skey is then the owner */ + skey->e = pkt.pkt.seckey_cert->d.rsa.rsa_e; + skey->n = pkt.pkt.seckey_cert->d.rsa.rsa_n; + skey->p = pkt.pkt.seckey_cert->d.rsa.rsa_p; + skey->q = pkt.pkt.seckey_cert->d.rsa.rsa_q; + skey->d = pkt.pkt.seckey_cert->d.rsa.rsa_d; + skey->u = pkt.pkt.seckey_cert->d.rsa.rsa_u; + /* set all these to NULL, so that free_packet will not destroy + * these integers. */ + pkt.pkt.seckey_cert->d.rsa.rsa_e = NULL; + pkt.pkt.seckey_cert->d.rsa.rsa_n = NULL; + pkt.pkt.seckey_cert->d.rsa.rsa_p = NULL; + pkt.pkt.seckey_cert->d.rsa.rsa_q = NULL; + pkt.pkt.seckey_cert->d.rsa.rsa_d = NULL; + pkt.pkt.seckey_cert->d.rsa.rsa_u = NULL; + + leave: + free_packet(&pkt); + return rc; +} + + +/**************** + * scan the keyring and look for either the keyid or the name. + */ +static int +scan_keyring( PKT_pubkey_cert *pkc, u32 *keyid, + const char *name, const char *filename ) +{ + int rc=0; + int found = 0; + IOBUF a; + PACKET pkt; + int save_mode; + u32 akeyid[2]; + PKT_pubkey_cert *last_pk = NULL; + + assert( !keyid || !name ); + + if( opt.cache_all && (name || keyid) ) + return G10ERR_NO_PUBKEY; + + if( !(a = iobuf_open( filename ) ) ) { + log_debug("scan_keyring: can't open '%s'\n", filename ); + return G10ERR_KEYRING_OPEN; + } + + if( name ) + log_debug("scan_keyring %s for '%s'\n", filename, name ); + else if( keyid ) + log_debug("scan_keyring %s for %08lx %08lx\n", filename, + keyid[0], keyid[1] ); + else + log_debug("scan_keyring %s (all)\n", filename ); + + save_mode = set_packet_list_mode(0); + init_packet(&pkt); + while( (rc=parse_packet(a, &pkt)) != -1 ) { + if( rc ) + ; /* e.g. unknown packet */ + else if( keyid && found && pkt.pkttype == PKT_PUBKEY_CERT ) { + log_error("Hmmm, pubkey without an user id in '%s'\n", filename); + goto leave; + } + else if( keyid && pkt.pkttype == PKT_PUBKEY_CERT ) { + switch( pkt.pkt.pubkey_cert->pubkey_algo ) { + case PUBKEY_ALGO_RSA: + mpi_get_keyid( pkt.pkt.pubkey_cert->d.rsa.rsa_n , akeyid ); + if( akeyid[0] == keyid[0] && akeyid[1] == keyid[1] ) { + copy_pubkey_cert( pkc, pkt.pkt.pubkey_cert ); + found++; + } + break; + default: + log_error("cannot handle pubkey algo %d\n", + pkt.pkt.pubkey_cert->pubkey_algo); + } + } + else if( keyid && found && pkt.pkttype == PKT_USER_ID ) { + cache_user_id( pkt.pkt.user_id, keyid ); + goto leave; + } + else if( name && pkt.pkttype == PKT_PUBKEY_CERT ) { + if( last_pk ) + free_pubkey_cert(last_pk); + last_pk = pkt.pkt.pubkey_cert; + pkt.pkt.pubkey_cert = NULL; + } + else if( name && pkt.pkttype == PKT_USER_ID ) { + if( memistr( pkt.pkt.user_id->name, pkt.pkt.user_id->len, name )) { + if( !last_pk ) + log_error("Ooops: no pubkey for userid '%.*s'\n", + pkt.pkt.user_id->len, pkt.pkt.user_id->name); + else if( pkc->pubkey_algo && + pkc->pubkey_algo != last_pk->pubkey_algo ) + log_info("skipping id '%.*s': want algo %d, found %d\n", + pkt.pkt.user_id->len, pkt.pkt.user_id->name, + pkc->pubkey_algo, last_pk->pubkey_algo ); + else { + copy_pubkey_cert( pkc, last_pk ); + goto leave; + } + } + } + else if( !keyid && !name && pkt.pkttype == PKT_PUBKEY_CERT ) { + if( last_pk ) + free_pubkey_cert(last_pk); + last_pk = pkt.pkt.pubkey_cert; + pkt.pkt.pubkey_cert = NULL; + } + else if( !keyid && !name && pkt.pkttype == PKT_USER_ID ) { + if( !last_pk ) + log_error("Ooops: no pubkey for userid '%.*s'\n", + pkt.pkt.user_id->len, pkt.pkt.user_id->name); + else { + if( last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) { + mpi_get_keyid( last_pk->d.rsa.rsa_n , akeyid ); + cache_user_id( pkt.pkt.user_id, akeyid ); + } + cache_pubkey_cert( last_pk ); + } + } + free_packet(&pkt); + } + rc = G10ERR_NO_PUBKEY; + + leave: + if( last_pk ) + free_pubkey_cert(last_pk); + free_packet(&pkt); + iobuf_close(a); + set_packet_list_mode(save_mode); + return rc; +} + + +/**************** + * This is the function to get a secret key. We use an extra function, + * so that we can easily add special handling for secret keyrings + * PKT returns the secret key certificate. + */ +static int +scan_secret_keyring( PACKET *pkt, u32 *keyid, const char *filename ) +{ + IOBUF a; + int save_mode, rc; + u32 akeyid[2]; + + if( !(a = iobuf_open( filename ) ) ) { + log_debug("scan_secret_keyring: can't open '%s'\n", filename ); + return G10ERR_KEYRING_OPEN; + } + + save_mode = set_packet_list_mode(0); + init_packet(pkt); + while( (rc=parse_packet(a, pkt)) != -1 ) { + if( rc ) + ; + else if( pkt->pkttype == PKT_SECKEY_CERT ) { + mpi_get_keyid( pkt->pkt.seckey_cert->d.rsa.rsa_n , akeyid ); + if( akeyid[0] == keyid[0] && akeyid[1] == keyid[1] ) { + iobuf_close(a); + set_packet_list_mode(save_mode); + return 0; /* got it */ + } + } + free_packet(pkt); + } + + iobuf_close(a); + set_packet_list_mode(save_mode); + return G10ERR_NO_SECKEY; +} + + + +/**************** + * Return a string with a printable representation of the user_id. + * this string must be freed by m_free. + */ +char* +get_user_id_string( u32 *keyid ) +{ + user_id_db_t r; + char *p; + int pass=0; + /* try it two times; second pass reads from keyrings */ + do { + for(r=user_id_db; r; r = r->next ) + if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) { + p = m_alloc( r->len + 10 ); + sprintf(p, "%08lX %.*s", keyid[1], r->len, r->name ); + return p; + } + } while( ++pass < 2 && !get_pubkey( NULL, keyid ) ); + p = m_alloc( 15 ); + sprintf(p, "%08lX [?]", keyid[1] ); + return p; +} + + diff --git a/g10/keydb.h b/g10/keydb.h new file mode 100644 index 000000000..641cd4cbc --- /dev/null +++ b/g10/keydb.h @@ -0,0 +1,45 @@ +/* keydb.h - Key database + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef G10_KEYDB_H +#define G10_KEYDB_H + +#include "types.h" +#include "cipher.h" + + +/*-- passphrase.h --*/ +DEK *get_passphrase_hash( u32 *keyid, char *text ); +int make_dek_from_passphrase( DEK *dek, int mode ); + +/*-- getkey.c --*/ +void add_keyring( const char *name ); +void cache_pubkey_cert( PKT_pubkey_cert *pkc ); +void cache_user_id( PKT_user_id *uid, u32 *keyid ); +int get_pubkey( PKT_pubkey_cert *pkc, u32 *keyid ); +int get_pubkey_by_name( PKT_pubkey_cert *pkc, const char *name ); +int get_seckey( RSA_secret_key *skey, u32 *keyid ); +char*get_user_id_string( u32 *keyid ); + + + + + +#endif /*G10_KEYDB_H*/ diff --git a/g10/keygen.c b/g10/keygen.c new file mode 100644 index 000000000..0d5db8d85 --- /dev/null +++ b/g10/keygen.c @@ -0,0 +1,253 @@ +/* keygen.c - generate a key pair + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include "util.h" +#include "main.h" +#include "packet.h" +#include "cipher.h" +#include "ttyio.h" +#include "options.h" + +static int +answer_is_yes( const char *s ) +{ + if( !stricmp(s, "yes") ) + return 1; + if( *s == 'y' && !s[1] ) + return 1; + if( *s == 'Y' && !s[1] ) + return 1; + return 0; +} + + +static void +write_comment( IOBUF out, const char *s ) +{ + PACKET pkt; + size_t n = strlen(s); + int rc; + + pkt.pkttype = PKT_COMMENT; + pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n - 1 ); + pkt.pkt.comment->len = n; + strcpy(pkt.pkt.comment->data, s); + if( (rc = build_packet( out, &pkt )) ) + log_error("build_packet(comment) failed: %s\n", g10_errstr(rc) ); + free_packet( &pkt ); +} + +static void +write_uid( IOBUF out, const char *s ) +{ + PACKET pkt; + size_t n = strlen(s); + int rc; + + pkt.pkttype = PKT_USER_ID; + pkt.pkt.user_id = m_alloc( sizeof *pkt.pkt.user_id + n - 1 ); + pkt.pkt.user_id->len = n; + strcpy(pkt.pkt.user_id->name, s); + if( (rc = build_packet( out, &pkt )) ) + log_error("build_packet(user_id) failed: %s\n", g10_errstr(rc) ); + free_packet( &pkt ); +} + + +static int +gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io) +{ + int rc; + PACKET pkt1, pkt2; + PKT_seckey_cert *skc; + PKT_pubkey_cert *pkc; + RSA_public_key pk; + RSA_secret_key sk; + + rsa_generate( &pk, &sk, nbits ); + + skc = m_alloc( sizeof *skc ); + pkc = m_alloc( sizeof *pkc ); + skc->timestamp = pkc->timestamp = make_timestamp(); + skc->valid_days = pkc->valid_days = 0; /* fixme: make it configurable*/ + skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_RSA; + memset(&pkc->mfx, 0, sizeof pkc->mfx); + pkc->d.rsa.rsa_n = pk.n; + pkc->d.rsa.rsa_e = pk.e; + skc->d.rsa.rsa_n = sk.n; + skc->d.rsa.rsa_e = sk.e; + skc->d.rsa.rsa_d = sk.d; + skc->d.rsa.rsa_p = sk.p; + skc->d.rsa.rsa_q = sk.q; + skc->d.rsa.rsa_u = sk.u; + skc->d.rsa.calc_csum = 0; + skc->d.rsa.is_protected = 0; /* FIXME!!! */ + skc->d.rsa.protect_algo = 0; /* should be blowfish */ + /*memcpy(skc->d.rsa.protect.blowfish.iv,"12345678", 8);*/ + + init_packet(&pkt1); + pkt1.pkttype = PKT_PUBKEY_CERT; + pkt1.pkt.pubkey_cert = pkc; + init_packet(&pkt2); + pkt2.pkttype = PKT_SECKEY_CERT; + pkt2.pkt.seckey_cert = skc; + + if( (rc = build_packet( pub_io, &pkt1 )) ) { + log_error("build pubkey_cert packet failed: %s\n", g10_errstr(rc) ); + goto leave; + } + if( (rc = build_packet( sec_io, &pkt2 )) ) { + log_error("build seckey_cert packet failed: %s\n", g10_errstr(rc) ); + goto leave; + } + + leave: + free_packet(&pkt1); + free_packet(&pkt2); + return rc; +} + + +/**************** + * Generate a keypair + */ +void +generate_keypair() +{ + char *answer; + unsigned nbits; + char *pub_fname = "./pubring.g10"; + char *sec_fname = "./secring.g10"; + char *uid = NULL; + IOBUF pub_io = NULL; + IOBUF sec_io = NULL; + int rc; + + if( opt.batch || opt.answer_yes || opt.answer_no ) + log_fatal("Key generation can only be used in interactive mode\n"); + + tty_printf("About to generate a new keypair:\n" + " minimum keysize is 768 bits\n" + " default keysize is 1024 bits\n" + " highest suggested keysize is 2048 bits\n" ); + for(;;) { + answer = tty_get("What keysize do you want? (256) "); + tty_kill_prompt(); + nbits = *answer? atoi(answer): 256; + m_free(answer); + if( nbits < 128 ) /* FIXME: change this to 768 */ + tty_printf("keysize too small; please select a larger one\n"); + else if( nbits > 2048 ) { + tty_printf("Keysizes larger than 2048 are not suggested, because " + "computations take REALLY long!\n"); + answer = tty_get("Are you sure, that you want this keysize? "); + tty_kill_prompt(); + if( answer_is_yes(answer) ) { + m_free(answer); + tty_printf("Okay, but keep in mind that your monitor " + "and keyboard radiation is also very vulnerable " + "to attacks!\n"); + break; + } + m_free(answer); + } + else + break; + } + tty_printf("Requested keysize is %u bits\n", nbits ); + if( (nbits % 32) ) { + nbits = ((nbits + 31) / 32) * 32; + tty_printf("rounded up to %u bits\n", nbits ); + } + tty_printf( "\nYou need a User-ID to identify your key; please use your name and your\n" + "email address in this suggested format:\n" + " \"Heinrich Heine <heinrichh@uni-duesseldorf.de>\n" ); + uid = NULL; + for(;;) { + m_free(uid); + tty_printf("\n"); + uid = tty_get("Your User-ID: "); + tty_kill_prompt(); + if( strlen(uid) < 5 ) + tty_printf("Please enter a string of at least 5 characters\n"); + else { + tty_printf("You selected this USER-ID:\n \"%s\"\n\n", uid); + answer = tty_get("Is this correct? "); + tty_kill_prompt(); + if( answer_is_yes(answer) ) { + m_free(answer); + break; + } + m_free(answer); + } + } + + /* now check wether we a are allowed to write the keyrings */ + if( !(rc=overwrite_filep( pub_fname )) ) { + if( !(pub_io = iobuf_create( pub_fname )) ) + log_error("can't create %s: %s\n", pub_fname, strerror(errno) ); + else if( opt.verbose ) + log_info("writing to '%s'\n", pub_fname ); + } + else if( rc != -1 ) { + log_error("Oops: overwrite_filep(%s): %s\n", pub_fname, g10_errstr(rc) ); + m_free(uid); + return; + } + else { + m_free(uid); + return; + } + if( !(rc=overwrite_filep( sec_fname )) ) { + if( !(sec_io = iobuf_create( sec_fname )) ) + log_error("can't create %s: %s\n", sec_fname, strerror(errno) ); + else if( opt.verbose ) + log_info("writing to '%s'\n", sec_fname ); + } + else if( rc != -1 ) { + log_error("Oops: overwrite_filep(%s): %s\n", sec_fname, g10_errstr(rc) ); + m_free(uid); + return; + } + else { + iobuf_cancel(pub_io); + m_free(uid); + return; + } + + + write_comment( pub_io, "#public key created by G10 pre-release " VERSION ); + write_comment( sec_io, "#secret key created by G10 pre-release " VERSION ); + + gen_rsa(nbits, pub_io, sec_io); + write_uid(pub_io, uid ); + write_uid(sec_io, uid ); + m_free(uid); + + iobuf_close(pub_io); + iobuf_close(sec_io); +} + diff --git a/g10/main.h b/g10/main.h new file mode 100644 index 000000000..398dc40f1 --- /dev/null +++ b/g10/main.h @@ -0,0 +1,35 @@ +/* main.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_MAIN_H +#define G10_MAIN_H +#include "types.h" + +/*-- encode.c --*/ +int encode_symmetric( const char *filename ); +int encode_store( const char *filename ); +int encode_crypt( const char *filename, STRLIST remusr ); + +/*-- keygen.c --*/ +void generate_keypair(void); + +/*-- overwrite.c --*/ +int overwrite_filep( const char *fname ); + +#endif /*G10_MAIN_H*/ diff --git a/g10/mainproc.c b/g10/mainproc.c new file mode 100644 index 000000000..0055200b4 --- /dev/null +++ b/g10/mainproc.c @@ -0,0 +1,275 @@ +/* mainproc.c - handle packets + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> + +#include "packet.h" +#include "iobuf.h" +#include "memory.h" +#include "options.h" +#include "util.h" +#include "cipher.h" +#include "keydb.h" + + +static int opt_list=1; /* and list the data packets to stdout */ + +int +proc_packets( IOBUF a ) +{ + PACKET *pkt; + PKT_pubkey_cert *last_pubkey = NULL; + PKT_seckey_cert *last_seckey = NULL; + PKT_user_id *last_user_id = NULL; + DEK *dek = NULL; + PKT_signature *sig; /* CHECK: "might be used uninitialied" */ + int rc, result; + MD_HANDLE md_handle; /* union to pass handles */ + char *ustr; + int lvl0, lvl1; + int last_was_pubkey_enc = 0; + u32 keyid[2]; + + lvl0 = opt.check_sigs? 1:0; /* stdout or /dev/null */ + lvl1 = opt.check_sigs? 1:3; /* stdout or error */ + pkt = m_alloc( sizeof *pkt ); + init_packet(pkt); + while( (rc=parse_packet(a, pkt)) != -1 ) { + if( dek && pkt->pkttype != PKT_ENCR_DATA ) { + log_error("oops: valid pubkey enc packet not followed by data\n"); + m_free(dek); dek = NULL; /* burn it */ + } + + if( rc ) + free_packet(pkt); + else if( pkt->pkttype == PKT_PUBKEY_CERT ) { + if( last_user_id ) { + free_user_id( last_user_id ); + last_user_id = NULL; + } + if( last_pubkey ) { + free_pubkey_cert( last_pubkey ); + last_pubkey = NULL; + } + if( opt.check_sigs ) { + ustr = get_user_id_string(sig->keyid); + printstr(lvl0, "pub: %s\n", ustr ); + m_free(ustr); + } + else + fputs( "pub: [Public Key Cerificate]\n", stdout ); + last_pubkey = pkt->pkt.pubkey_cert; + pkt->pkt.pubkey_cert = NULL; + free_packet(pkt); + pkt->pkc_parent = last_pubkey; /* set this as parent */ + } + else if( pkt->pkttype == PKT_SECKEY_CERT ) { + if( last_user_id ) { + free_user_id( last_user_id ); + last_user_id = NULL; + } + if( last_seckey ) { + free_seckey_cert( last_seckey ); + last_seckey = NULL; + } + if( opt_list ) + fputs( "sec: (secret key certificate)\n", stdout ); + rc = check_secret_key( pkt->pkt.seckey_cert ); + if( opt_list ) { + if( !rc ) + fputs( " Secret key is good", stdout ); + else + fputs( g10_errstr(rc), stdout); + putchar('\n'); + } + else if( rc ) + log_error("secret key certificate error: %s\n", g10_errstr(rc)); + last_seckey = pkt->pkt.seckey_cert; + pkt->pkt.seckey_cert = NULL; + free_packet(pkt); + pkt->skc_parent = last_seckey; /* set this as parent */ + } + else if( pkt->pkttype == PKT_USER_ID ) { + if( last_user_id ) { + free_user_id( last_user_id ); + last_user_id = NULL; + } + if( opt_list ) { + printf("uid: '%.*s'\n", pkt->pkt.user_id->len, + pkt->pkt.user_id->name ); + if( !pkt->pkc_parent && !pkt->skc_parent ) + puts(" (orphaned)"); + } + if( pkt->pkc_parent ) { + if( pkt->pkc_parent->pubkey_algo == PUBKEY_ALGO_RSA ) { + mpi_get_keyid( pkt->pkc_parent->d.rsa.rsa_n, keyid ); + cache_user_id( pkt->pkt.user_id, keyid ); + } + } + + last_user_id = pkt->pkt.user_id; /* save */ + pkt->pkt.user_id = NULL; + free_packet(pkt); /* fixme: free_packet is not a good name */ + pkt->user_parent = last_user_id; /* and set this as user */ + } + else if( pkt->pkttype == PKT_SIGNATURE ) { + sig = pkt->pkt.signature; + ustr = get_user_id_string(sig->keyid); + result = -1; + if( sig->sig_class != 0x10 ) + printstr(lvl1,"sig?: %s: unknown signature class %02x\n", + ustr, sig->sig_class); + else if( !pkt->pkc_parent || !pkt->user_parent ) + printstr(lvl1,"sig?: %s: orphaned encoded packet\n", ustr); + else + result = 0; + + if( result ) + ; + else if( !opt.check_sigs ) { + result = -1; + printstr(lvl0, "sig: from %s\n", ustr ); + } + else if(sig->pubkey_algo == PUBKEY_ALGO_RSA ) { + md_handle.algo = sig->d.rsa.digest_algo; + if( sig->d.rsa.digest_algo == DIGEST_ALGO_RMD160 ) { + md_handle.u.rmd = rmd160_copy(pkt->pkc_parent->mfx.rmd160); + rmd160_write(md_handle.u.rmd, pkt->user_parent->name, + pkt->user_parent->len); + result = signature_check( sig, md_handle ); + rmd160_close(md_handle.u.rmd); + } + else if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) { + md_handle.u.md5 = md5_copy(pkt->pkc_parent->mfx.md5); + md5_write(md_handle.u.md5, pkt->user_parent->name, + pkt->user_parent->len); + result = signature_check( sig, md_handle ); + md5_close(md_handle.u.md5); + } + else + result = G10ERR_DIGEST_ALGO; + } + else + result = G10ERR_PUBKEY_ALGO; + + if( result == -1 ) + ; + else if( !result ) + printstr(lvl0, "sig: good signature from %s\n", ustr ); + else + printstr(lvl1, "sig? %s: %s\n", ustr, g10_errstr(result)); + free_packet(pkt); + m_free(ustr); + } + else if( pkt->pkttype == PKT_PUBKEY_ENC ) { + PKT_pubkey_enc *enc; + + last_was_pubkey_enc = 1; + result = 0; + enc = pkt->pkt.pubkey_enc; + printf("enc: encrypted by a pubkey with keyid %08lX\n", + enc->keyid[1] ); + if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) { + m_free(dek ); /* paranoid: delete a pending DEK */ + dek = m_alloc_secure( sizeof *dek ); + if( (result = get_session_key( enc, dek )) ) { + /* error: delete the DEK */ + m_free(dek); dek = NULL; + } + } + else + result = G10ERR_PUBKEY_ALGO; + + if( result == -1 ) + ; + else if( !result ) + fputs( " DEK is good", stdout ); + else + printf( " %s", g10_errstr(result)); + putchar('\n'); + free_packet(pkt); + } + else if( pkt->pkttype == PKT_ENCR_DATA ) { + result = 0; + printf("dat: %sencrypted data\n", dek?"":"conventional "); + if( !dek && !last_was_pubkey_enc ) { + /* assume this is conventional encrypted data */ + dek = m_alloc_secure( sizeof *dek ); + dek->algo = DEFAULT_CIPHER_ALGO; + result = make_dek_from_passphrase( dek, 0 ); + } + else if( !dek ) + result = G10ERR_NO_SECKEY; + if( !result ) + result = decrypt_data( pkt->pkt.encr_data, dek ); + m_free(dek); dek = NULL; + if( result == -1 ) + ; + else if( !result ) + fputs( " encryption okay",stdout); + else + printf( " %s", g10_errstr(result)); + putchar('\n'); + free_packet(pkt); + last_was_pubkey_enc = 0; + } + else if( pkt->pkttype == PKT_PLAINTEXT ) { + PKT_plaintext *pt = pkt->pkt.plaintext; + printf("txt: plain text data name='%.*s'\n", pt->namelen, pt->name); + result = handle_plaintext( pt ); + if( !result ) + fputs( " okay",stdout); + else + printf( " %s", g10_errstr(result)); + putchar('\n'); + free_packet(pkt); + last_was_pubkey_enc = 0; + } + else if( pkt->pkttype == PKT_COMPR_DATA ) { + PKT_compressed *zd = pkt->pkt.compressed; + printf("zip: compressed data packet\n"); + result = handle_compressed( zd ); + if( !result ) + fputs( " okay",stdout); + else + printf( " %s", g10_errstr(result)); + putchar('\n'); + free_packet(pkt); + last_was_pubkey_enc = 0; + } + else + free_packet(pkt); + } + + if( last_user_id ) + free_user_id( last_user_id ); + if( last_seckey ) + free_seckey_cert( last_seckey ); + if( last_pubkey ) + free_pubkey_cert( last_pubkey ); + m_free(dek); + free_packet( pkt ); + m_free( pkt ); + return 0; +} + + diff --git a/g10/mdfilter.c b/g10/mdfilter.c new file mode 100644 index 000000000..b6cd86110 --- /dev/null +++ b/g10/mdfilter.c @@ -0,0 +1,70 @@ +/* mdfilter.c - filter data and calculate a message digest + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "errors.h" +#include "iobuf.h" +#include "memory.h" +#include "util.h" +#include "filter.h" + + + +/**************** + * The filter is used to collect a message digest + */ +int +md_filter( void *opaque, int control, + IOBUF a, byte *buf, size_t *ret_len) +{ + size_t size = *ret_len; + md_filter_context_t *mfx = opaque; + int i, c, rc=0; + + if( control == IOBUFCTRL_UNDERFLOW ) { + if( size > mfx->maxbuf_size ) + size = mfx->maxbuf_size; + for(i=0; i < size; i++ ) { + if( (c = iobuf_get(a)) == -1 ) + break; + buf[i] = c; + } + + if( i ) { + if( mfx->md5 ) + md5_write(mfx->md5, buf, i ); + if( mfx->rmd160 ) + rmd160_write(mfx->rmd160, buf, i ); + } + else + rc = -1; /* eof */ + *ret_len = i; + } + else if( control == IOBUFCTRL_DESC ) + *(char**)buf = "md_filter"; + return rc; +} + diff --git a/g10/options.h b/g10/options.h new file mode 100644 index 000000000..f2a17de85 --- /dev/null +++ b/g10/options.h @@ -0,0 +1,68 @@ +/* options.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_OPTIONS_H +#define G10_OPTIONS_H + +struct { + int verbose; + unsigned debug; + int armor; + int compress; + char *outfile; + int outfile_is_stdout; + int batch; /* run in batch mode */ + int answer_yes; /* answer yes on most questions */ + int answer_no; /* answer no on most questions */ + int check_sigs; /* check key signatures */ + int cache_all; + int reserved2; + int reserved3; + int reserved4; + int reserved5; + int reserved6; + int reserved7; + int reserved8; + int reserved9; + int reserved10; + int reserved11; + int reserved12; + int reserved13; + int reserved14; + int reserved15; +} opt; + + +#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */ +#define DBG_MPI_VALUE 2 /* debug mpi details */ +#define DBG_CIPHER_VALUE 4 /* debug cipher handling */ + /* (may reveal sensitive data) */ +#define DBG_FILTER_VALUE 8 /* debug internal filter handling */ +#define DBG_IOBUF_VALUE 16 /* debug iobuf stuff */ +#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */ +#define DBG_CACHE_VALUE 64 /* debug the cacheing */ +#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */ + + +#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE) +#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE) +#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE) + + +#endif /*G10_OPTIONS_H*/ diff --git a/g10/overwrite.c b/g10/overwrite.c new file mode 100644 index 000000000..a98dd3be7 --- /dev/null +++ b/g10/overwrite.c @@ -0,0 +1,79 @@ +/* overwrite.c + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include "util.h" +#include "memory.h" +#include "ttyio.h" +#include "options.h" +#include "main.h" + + +/**************** + * Check wether FNAME exists and ask if it's okay to overwrite an + * existing one. + * Returns: -1 : Do not overwrite + * 0 : it's okay to overwrite or the file does not exist + * >0 : other error + */ +int +overwrite_filep( const char *fname ) +{ + if( !access( fname, F_OK ) ) { + char *p; + int okay; + int first = 1; + + if( opt.answer_yes ) + okay = 1; + else if( opt.answer_no || opt.batch ) + okay = 2; + else + okay = 0; + + while( !okay ) { + if( !okay ) + if( first ) { + tty_printf("File '%s' exists. ", fname); + first = 0; + } + p = tty_get("Overwrite (y/N)? "); + tty_kill_prompt(); + if( (*p == 'y' || *p == 'Y') && !p[1] ) + okay = 1; + else if( !*p || ((*p == 'n' || *p == 'N') && !p[1]) ) + okay = 2; + else + okay = 0; + m_free(p); + } + if( okay == 2 ) + return -1; + /* fixme: add some backup stuff */ + } + return 0; +} + + diff --git a/g10/packet.h b/g10/packet.h new file mode 100644 index 000000000..6ac57cab0 --- /dev/null +++ b/g10/packet.h @@ -0,0 +1,214 @@ +/* packet.h - packet read/write stuff + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef G10_PACKET_H +#define G10_PACKET_H + +#include "types.h" +#include "iobuf.h" +#include "mpi.h" +#include "cipher.h" +#include "filter.h" + + +#define PKT_PUBKEY_ENC 1 /* public key encrypted packet */ +#define PKT_SIGNATURE 2 /* secret key encrypted packet */ +#define PKT_SECKEY_CERT 5 /* secret key certificate */ +#define PKT_PUBKEY_CERT 6 /* public key certificate */ +#define PKT_COMPR_DATA 8 /* compressed data packet */ +#define PKT_ENCR_DATA 9 /* conventional encrypted data */ +#define PKT_PLAINTEXT 11 /* plaintext data with filename and mode */ +#define PKT_RING_TRUST 12 /* keyring trust packet */ +#define PKT_USER_ID 13 /* user id packet */ +#define PKT_COMMENT 14 /* comment packet */ + +typedef struct packet_struct PACKET; + +typedef struct { + u32 keyid[2]; /* 64 bit keyid */ + byte pubkey_algo; /* algorithm used for public key scheme */ + union { + struct { + MPI rsa_integer; /* integer containing the DEK */ + } rsa; + } d; +} PKT_pubkey_enc; + + +typedef struct { + u32 keyid[2]; /* 64 bit keyid */ + u32 timestamp; /* signature made */ + byte sig_class; /* sig classification, append for MD calculation*/ + byte pubkey_algo; /* algorithm used for public key scheme */ + /* (PUBKEY_ALGO_xxx) */ + union { + struct { + byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */ + byte digest_start[2]; /* first 2 byte of the digest */ + MPI rsa_integer; /* the encrypted digest */ + } rsa; + } d; +} PKT_signature; + + +typedef struct { + u32 timestamp; /* certificate made */ + u16 valid_days; /* valid for this number of days */ + byte pubkey_algo; /* algorithm used for public key scheme */ + md_filter_context_t mfx; + union { + struct { + MPI rsa_n; /* public modulus */ + MPI rsa_e; /* public exponent */ + } rsa; + } d; +} PKT_pubkey_cert; + +typedef struct { + u32 timestamp; /* certificate made */ + u16 valid_days; /* valid for this number of days */ + byte pubkey_algo; /* algorithm used for public key scheme */ + union { + struct { + MPI rsa_n; /* public modulus */ + MPI rsa_e; /* public exponent */ + MPI rsa_d; /* secret descryption exponent */ + MPI rsa_p; /* secret first prime number */ + MPI rsa_q; /* secret second prime number */ + MPI rsa_u; /* secret multiplicative inverse */ + u16 csum; /* checksum */ + u16 calc_csum; /* and a place to store the calculated csum */ + byte is_protected; /* The above infos are protected and must */ + /* be deciphered before use */ + byte protect_algo; /* cipher used to protect the secret informations*/ + union { /* information for the protection */ + struct { + byte iv[8]; /* initialization vector for CFB mode */ + /* when protected, the MPIs above are pointers + * to plain storage */ + } idea; + struct { + byte iv[8]; + } blowfish; + } protect; + } rsa; + } d; +} PKT_seckey_cert; + + +typedef struct { + int len; /* length of data */ + char data[1]; +} PKT_comment; + +typedef struct { + int len; /* length of the name */ + char name[1]; +} PKT_user_id; + +typedef struct { + u32 len; /* reserved */ + byte algorithm; + IOBUF buf; /* IOBUF reference */ +} PKT_compressed; + +typedef struct { + u32 len; /* length of encrypted data */ + IOBUF buf; /* IOBUF reference */ +} PKT_encr_data; + +typedef struct { + u32 len; /* length of encrypted data */ + IOBUF buf; /* IOBUF reference */ + int mode; + u32 timestamp; + int namelen; + char name[1]; +} PKT_plaintext; + +/* combine all packets into a union */ +struct packet_struct { + int pkttype; + PKT_pubkey_cert *pkc_parent; /* the pubkey to which it belongs */ + PKT_seckey_cert *skc_parent; /* the seckey to which it belongs */ + PKT_user_id *user_parent; /* the user_id to which it belongs */ + union { + void *generic; + PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */ + PKT_signature *signature; /* PKT_SIGNATURE */ + PKT_pubkey_cert *pubkey_cert; /* PKT_PUBKEY_CERT */ + PKT_seckey_cert *seckey_cert; /* PKT_SECKEY_CERT */ + PKT_comment *comment; /* PKT_COMMENT */ + PKT_user_id *user_id; /* PKT_USER_ID */ + PKT_compressed *compressed; /* PKT_COMPRESSED */ + PKT_encr_data *encr_data; /* PKT_ENCR_DATA */ + PKT_plaintext *plaintext; /* PKT_PLAINTEXT */ + } pkt; +}; + +#define init_packet(a) do { (a)->pkttype = 0; \ + (a)->pkc_parent = NULL; \ + (a)->skc_parent = NULL; \ + (a)->user_parent = NULL; \ + (a)->pkt.generic = NULL; \ + } while(0) + +/*-- mainproc.c --*/ +int proc_packets( IOBUF a ); + +/*-- parse-packet.c --*/ +int set_packet_list_mode( int mode ); +int parse_packet( IOBUF inp, PACKET *ret_pkt); + +/*-- build-packet.c --*/ +int build_packet( IOBUF inp, PACKET *pkt ); +u32 calc_packet_length( PACKET *pkt ); + +/*-- free-packet.c --*/ +void free_pubkey_enc( PKT_pubkey_enc *enc ); +void free_seckey_enc( PKT_signature *enc ); +void free_pubkey_cert( PKT_pubkey_cert *cert ); +void free_seckey_cert( PKT_seckey_cert *cert ); +void free_user_id( PKT_user_id *uid ); +void free_comment( PKT_comment *rem ); +void free_packet( PACKET *pkt ); +PKT_pubkey_cert *copy_pubkey_cert( PKT_pubkey_cert *d, PKT_pubkey_cert *s ); + + +/*-- sig-check.c --*/ +int signature_check( PKT_signature *sig, MD_HANDLE digest ); + +/*-- seckey-cert.c --*/ +int check_secret_key( PKT_seckey_cert *cert ); + +/*-- pubkey-enc.c --*/ +int get_session_key( PKT_pubkey_enc *k, DEK *dek ); + +/*-- compressed.c --*/ +int handle_compressed( PKT_compressed *zd ); + +/*-- encr-data.c --*/ +int decrypt_data( PKT_encr_data *ed, DEK *dek ); +int encrypt_data( PKT_encr_data *ed, DEK *dek ); + +/*-- plaintext.c --*/ +int handle_plaintext( PKT_plaintext *pt ); + +#endif /*G10_PACKET_H*/ diff --git a/g10/parse-packet.c b/g10/parse-packet.c new file mode 100644 index 000000000..7c6b85782 --- /dev/null +++ b/g10/parse-packet.c @@ -0,0 +1,662 @@ +/* parse-packet.c - read packets + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "packet.h" +#include "iobuf.h" +#include "mpi.h" +#include "util.h" +#include "cipher.h" +#include "memory.h" +#include "filter.h" +#include "options.h" + +static mpi_print_mode = 0; +static list_mode = 0; + +static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen ); +static void skip_rest( IOBUF inp, unsigned long pktlen ); +static int parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, + PACKET *packet ); +static int parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, + PKT_signature *sig ); +static int parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, + byte *hdr, int hdrlen, PACKET *packet ); +static int parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, + PACKET *packet ); +static void parse_comment( IOBUF inp, int pkttype, unsigned long pktlen ); +static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen ); +static int parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, + PACKET *pkt ); +static int parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, + PACKET *packet ); +static int parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, + PACKET *packet ); + +static u16 +checksum( byte *p ) +{ + u16 n, a; + + n = *p++ << 8; + n |= *p++; + for(a=0; n; n-- ) + a += *p++; + return a; +} + +static unsigned short +read_16(IOBUF inp) +{ + unsigned short a; + a = iobuf_get_noeof(inp) << 8; + a |= iobuf_get_noeof(inp); + return a; +} + +static unsigned long +read_32(IOBUF inp) +{ + unsigned long a; + a = iobuf_get_noeof(inp) << 24; + a |= iobuf_get_noeof(inp) << 16; + a |= iobuf_get_noeof(inp) << 8; + a |= iobuf_get_noeof(inp); + return a; +} + +int +set_packet_list_mode( int mode ) +{ + int old = list_mode; + list_mode = mode; + mpi_print_mode = DBG_MPI; + return old; +} + +/**************** + * Parse a Packet and return it in packet + * Returns: 0 := valid packet in pkt + * -1 := no more packets + * >0 := error + * Note: The function may return an error and a partly valid packet; + * caller must free this packet. + */ +int +parse_packet( IOBUF inp, PACKET *pkt ) +{ + int rc, ctb, pkttype, lenbytes; + unsigned long pktlen; + byte hdr[5]; + int hdrlen; + + assert( !pkt->pkt.generic ); + if( (ctb = iobuf_get(inp)) == -1 ) + return -1; + hdrlen=0; + hdr[hdrlen++] = ctb; + if( !(ctb & 0x80) ) { + log_error("invalid packet at '%s'\n", iobuf_where(inp) ); + return G10ERR_INVALID_PACKET; + } + /* we handle the pgp 3 extensions here, so that we can skip such packets*/ + pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf); + lenbytes = (ctb & 0x40) || ((ctb&3)==3)? 0 : (1<<(ctb & 3)); + pktlen = 0; + if( !lenbytes ) { + pktlen = 0; /* don't know the value */ + iobuf_set_block_mode(inp, 1); + } + else { + for( ; lenbytes; lenbytes-- ) { + pktlen <<= 8; + pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp); + } + } + + if( DBG_PACKET ) + log_debug("parse_packet(iob=%d): type=%d length=%lu\n", + iobuf_id(inp), pkttype, pktlen ); + pkt->pkttype = pkttype; + rc = G10ERR_UNKNOWN_PACKET; /* default to no error */ + switch( pkttype ) { + case PKT_PUBKEY_CERT: + pkt->pkt.pubkey_cert = m_alloc_clear(sizeof *pkt->pkt.pubkey_cert ); + rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt ); + break; + case PKT_SECKEY_CERT: + pkt->pkt.seckey_cert = m_alloc_clear(sizeof *pkt->pkt.seckey_cert ); + rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt ); + break; + case PKT_PUBKEY_ENC: + rc = parse_publickey(inp, pkttype, pktlen, pkt ); + break; + case PKT_SIGNATURE: + pkt->pkt.signature = m_alloc_clear(sizeof *pkt->pkt.signature ); + rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature ); + m_check(pkt->pkt.signature); + break; + case PKT_USER_ID: + rc = parse_user_id(inp, pkttype, pktlen, pkt ); + break; + case PKT_COMMENT: + parse_comment(inp, pkttype, pktlen); + break; + case PKT_RING_TRUST: + parse_trust(inp, pkttype, pktlen); + break; + case PKT_PLAINTEXT: + rc = parse_plaintext(inp, pkttype, pktlen, pkt ); + break; + case PKT_COMPR_DATA: + rc = parse_compressed(inp, pkttype, pktlen, pkt ); + break; + case PKT_ENCR_DATA: + rc = parse_encrypted(inp, pkttype, pktlen, pkt ); + break; + default: + skip_packet(inp, pkttype, pktlen); + break; + } + + return rc; +} + + +static void +skip_packet( IOBUF inp, int pkttype, unsigned long pktlen ) +{ + if( list_mode ) + printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen ); + skip_rest(inp,pktlen); +} + +static void +skip_rest( IOBUF inp, unsigned long pktlen ) +{ + if( iobuf_in_block_mode(inp) ) { + while( iobuf_get(inp) != -1 ) + ; + } + else { + for( ; pktlen; pktlen-- ) + iobuf_get(inp); + } +} + + +static int +parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) +{ + int version; + unsigned n; + PKT_pubkey_enc *k; + + k = packet->pkt.pubkey_enc = m_alloc(sizeof *packet->pkt.pubkey_enc ); + if( pktlen < 12 ) { + log_error("packet(%d) too short\n", pkttype); + goto leave; + } + version = iobuf_get_noeof(inp); pktlen--; + if( version != 2 && version != 3 ) { + log_error("packet(%d) with unknown version %d\n", pkttype, version); + goto leave; + } + k->keyid[0] = read_32(inp); pktlen -= 4; + k->keyid[1] = read_32(inp); pktlen -= 4; + k->pubkey_algo = iobuf_get_noeof(inp); pktlen--; + if( list_mode ) + printf(":public key packet: keyid %08lX%08lX\n", + k->keyid[0], k->keyid[1]); + if( k->pubkey_algo == PUBKEY_ALGO_RSA ) { + n = pktlen; + k->d.rsa.rsa_integer = mpi_decode(inp, &n ); pktlen -=n; + if( list_mode ) { + printf("\trsa integer: "); + mpi_print(stdout, k->d.rsa.rsa_integer, mpi_print_mode ); + putchar('\n'); + } + } + else if( list_mode ) + printf("\tunknown algorithm %d\n", k->pubkey_algo ); + + + leave: + skip_rest(inp, pktlen); + return 0; +} + + +static int +parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, + PKT_signature *sig ) +{ + int version, md5_len; + unsigned n; + + if( pktlen < 16 ) { + log_error("packet(%d) too short\n", pkttype); + goto leave; + } + version = iobuf_get_noeof(inp); pktlen--; + if( version != 2 && version != 3 ) { + log_error("packet(%d) with unknown version %d\n", pkttype, version); + goto leave; + } + m_check(sig); + md5_len = iobuf_get_noeof(inp); pktlen--; + sig->sig_class = iobuf_get_noeof(inp); pktlen--; + sig->timestamp = read_32(inp); pktlen -= 4; + sig->keyid[0] = read_32(inp); pktlen -= 4; + sig->keyid[1] = read_32(inp); pktlen -= 4; + sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--; + m_check(sig); + if( list_mode ) + printf(":signature packet: keyid %08lX%08lX\n" + "\tversion %d, created %lu, md5len %d, sigclass %02x\n", + sig->keyid[0], sig->keyid[1], + version, sig->timestamp, md5_len, sig->sig_class ); + if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) { + if( pktlen < 5 ) { + log_error("packet(%d) too short\n", pkttype); + goto leave; + } + m_check(sig); + sig->d.rsa.digest_algo = iobuf_get_noeof(inp); pktlen--; + sig->d.rsa.digest_start[0] = iobuf_get_noeof(inp); pktlen--; + sig->d.rsa.digest_start[1] = iobuf_get_noeof(inp); pktlen--; + m_check(sig); + n = pktlen; + sig->d.rsa.rsa_integer = mpi_decode(inp, &n ); pktlen -=n; + if( list_mode ) { + printf("\tdigest algo %d, begin of digest %02x %02x\n", + sig->d.rsa.digest_algo, + sig->d.rsa.digest_start[0], sig->d.rsa.digest_start[1] ); + printf("\trsa integer: "); + mpi_print(stdout, sig->d.rsa.rsa_integer, mpi_print_mode ); + putchar('\n'); + } + } + else if( list_mode ) + printf("\tunknown algorithm %d\n", sig->pubkey_algo ); + m_check(sig); + + + leave: + skip_rest(inp, pktlen); + return 0; +} + + + + +static int +parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, + byte *hdr, int hdrlen, PACKET *pkt ) +{ + int i, version, algorithm; + unsigned n; + unsigned long timestamp; + unsigned short valid_period; + MPI rsa_pub_mod, rsa_pub_exp; + + if( pkttype == PKT_PUBKEY_CERT ) { + pkt->pkt.pubkey_cert->mfx.md5 = md5_open(0); + pkt->pkt.pubkey_cert->mfx.rmd160 = rmd160_open(0); + pkt->pkt.pubkey_cert->mfx.maxbuf_size = 1; + md5_write(pkt->pkt.pubkey_cert->mfx.md5, hdr, hdrlen); + rmd160_write(pkt->pkt.pubkey_cert->mfx.rmd160, hdr, hdrlen); + iobuf_push_filter( inp, md_filter, &pkt->pkt.pubkey_cert->mfx ); + } + + if( pktlen < 12 ) { + log_error("packet(%d) too short\n", pkttype); + goto leave; + } + version = iobuf_get_noeof(inp); pktlen--; + if( version != 2 && version != 3 ) { + log_error("packet(%d) with unknown version %d\n", pkttype, version); + goto leave; + } + + timestamp = read_32(inp); pktlen -= 4; + valid_period = read_16(inp); pktlen -= 2; + algorithm = iobuf_get_noeof(inp); pktlen--; + if( list_mode ) + printf(":%s key certification packet:\n" + "\tversion %d, created %lu, valid for %hu days\n", + pkttype == PKT_PUBKEY_CERT? "public": "secret", + version, timestamp, valid_period ); + if( pkttype == PKT_SECKEY_CERT ) { + pkt->pkt.seckey_cert->timestamp = timestamp; + pkt->pkt.seckey_cert->valid_days = valid_period; + pkt->pkt.seckey_cert->pubkey_algo = algorithm; + } + else { + pkt->pkt.pubkey_cert->timestamp = timestamp; + pkt->pkt.pubkey_cert->valid_days = valid_period; + pkt->pkt.pubkey_cert->pubkey_algo = algorithm; + } + + if( algorithm == PUBKEY_ALGO_RSA ) { + n = pktlen; rsa_pub_mod = mpi_decode(inp, &n ); pktlen -=n; + n = pktlen; rsa_pub_exp = mpi_decode(inp, &n ); pktlen -=n; + if( list_mode ) { + printf( "\tpublic modulus n: "); + mpi_print(stdout, rsa_pub_mod, mpi_print_mode ); + printf("\n\tpublic exponent e: "); + mpi_print(stdout, rsa_pub_exp, mpi_print_mode ); + putchar('\n'); + } + if( pkttype == PKT_PUBKEY_CERT ) { + pkt->pkt.pubkey_cert->d.rsa.rsa_n = rsa_pub_mod; + pkt->pkt.pubkey_cert->d.rsa.rsa_e = rsa_pub_exp; + } + else { + PKT_seckey_cert *cert = pkt->pkt.seckey_cert; + byte temp[8]; + byte *mpibuf; + + pkt->pkt.seckey_cert->d.rsa.rsa_n = rsa_pub_mod; + pkt->pkt.seckey_cert->d.rsa.rsa_e = rsa_pub_exp; + cert->d.rsa.protect_algo = iobuf_get_noeof(inp); pktlen--; + if( list_mode ) + printf( "\tprotect algo: %d\n", cert->d.rsa.protect_algo); + if( cert->d.rsa.protect_algo ) { + cert->d.rsa.is_protected = 1; + for(i=0; i < 8 && pktlen; i++, pktlen-- ) + temp[i] = iobuf_get_noeof(inp); + if( list_mode ) { + printf( "\tprotect IV: "); + for(i=0; i < 8; i++ ) + printf(" %02x", temp[i] ); + putchar('\n'); + } + if( cert->d.rsa.protect_algo == CIPHER_ALGO_IDEA ) + memcpy(cert->d.rsa.protect.idea.iv, temp, 8 ); + else if( cert->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH ) + memcpy(cert->d.rsa.protect.blowfish.iv, temp, 8 ); + } + else + cert->d.rsa.is_protected = 0; + + n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2); + cert->d.rsa.rsa_d = (MPI)mpibuf; + + n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2); + cert->d.rsa.rsa_p = (MPI)mpibuf; + + n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2); + cert->d.rsa.rsa_q = (MPI)mpibuf; + + n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2); + cert->d.rsa.rsa_u = (MPI)mpibuf; + + cert->d.rsa.csum = read_16(inp); pktlen -= 2; + cert->d.rsa.calc_csum = 0; + if( list_mode ) { + printf("\t[secret values d,p,q,u are not shown]\n" + "\tchecksum: %04hx\n", cert->d.rsa.csum); + } + if( !cert->d.rsa.is_protected ) { /* convert buffer to MPIs */ + #define X(a) do { \ + mpibuf = (byte*)cert->d.rsa.rsa_##a; \ + cert->d.rsa.calc_csum += checksum( mpibuf ); \ + cert->d.rsa.rsa_##a = mpi_decode_buffer( mpibuf ); \ + m_free( mpibuf ); \ + } while(0) + X(d); + X(p); + X(q); + X(u); + #undef X + log_mpidump("rsa n=", cert->d.rsa.rsa_n ); + log_mpidump("rsa e=", cert->d.rsa.rsa_e ); + log_mpidump("rsa d=", cert->d.rsa.rsa_d ); + log_mpidump("rsa p=", cert->d.rsa.rsa_p ); + log_mpidump("rsa q=", cert->d.rsa.rsa_q ); + log_mpidump("rsa u=", cert->d.rsa.rsa_u ); + } + } + } + else if( list_mode ) + printf("\tunknown algorithm %d\n", algorithm ); + + + leave: + if( pkttype == PKT_PUBKEY_CERT ) + iobuf_pop_filter( inp, md_filter, &pkt->pkt.pubkey_cert->mfx ); + skip_rest(inp, pktlen); + return 0; +} + + +static int +parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) +{ + byte *p; + + packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + pktlen - 1); + packet->pkt.user_id->len = pktlen; + p = packet->pkt.user_id->name; + for( ; pktlen; pktlen--, p++ ) + *p = iobuf_get_noeof(inp); + + if( list_mode ) { + int n = packet->pkt.user_id->len; + printf(":user id packet: \""); + for(p=packet->pkt.user_id->name; n; p++, n-- ) { + if( *p >= ' ' && *p <= 'z' ) + putchar(*p); + else + printf("\\x%02x", *p ); + } + printf("\"\n"); + } + return 0; +} + +static void +parse_comment( IOBUF inp, int pkttype, unsigned long pktlen ) +{ + if( list_mode ) { + printf(":comment packet: \"" ); + for( ; pktlen; pktlen-- ) { + int c; + c = iobuf_get_noeof(inp); + if( c >= ' ' && c <= 'z' ) + putchar(c); + else + printf("\\x%02x", c ); + } + printf("\"\n"); + } + skip_rest(inp, pktlen); +} + + +static void +parse_trust( IOBUF inp, int pkttype, unsigned long pktlen ) +{ + int c; + + c = iobuf_get_noeof(inp); + if( list_mode ) + printf(":trust packet: flag=%02x\n", c ); + #if 0 /* fixme: depending on the context we have different interpretations*/ + if( prev_packet_is_a_key_packet ) { + int ot = c & 7; /* ownertrust bits (for the key owner) */ + + !ot ? "undefined" : + ot == 1 ? "unknown" : /* we don't know the owner of this key */ + ot == 2 ? "no" : /* usually we do not trust this key owner */ + /* to sign other keys */ + ot == 5 ? "usually" : /* usually we trust this key owner to sign */ + ot == 6 ? "always" : /* always trust this key owner to sign */ + ot == 7 ? "ultimate" : /* also present in the secret keyring */ + "" /* reserved value */ + if( c & (1<<5) ) + "key is disabled" + if( c & (1<<7) ) + "buckstop" + else if( prev_packet_is_user_is_packet ) { + int kl = c & 3; /* keylegit bits */ + 0 = "unknown, undefined, or uninitialized trust" + 1 = "we do not trust this key's ownership" + 2 = "we have marginal confidence of this key's ownership" + 3 = "we completely trust this key's ownership." + /* This one (3) requires either: + * - 1 ultimately trusted signature (SIGTRUST=7) + * - COMPLETES_NEEDED completely trusted signatures (SIGTRUST=6) + * - MARGINALS_NEEDED marginally trusted signatures (SIGTRUST=5) + */ + if( c & 0x80 ) + "warnonly" + else if( prev_packet_is_a_signature ) { + Bits 0-2 - SIGTRUST bits - Trust bits for this signature. Value is + copied directly from OWNERTRUST bits of signer: + 000 - undefined, or uninitialized trust. + 001 - unknown + 010 - We do not trust this signature. + 011 - reserved + 100 - reserved + 101 - We reasonably trust this signature. + 110 - We completely trust this signature. + 111 - ultimately trusted signature (from the owner of the ring) + Bit 6 - CHECKED bit - This means that the key checking pass (pgp -kc, + also invoked automatically whenever keys are added to the + keyring) has tested this signature and found it good. If + this bit is not set, the maintenance pass considers this + signature untrustworthy. + Bit 7 - CONTIG bit - Means this signature leads up a contiguous trusted + certification path all the way back to the ultimately- + trusted keyring owner, where the buck stops. This bit is derived + from other trust packets. It is currently not used for anything + in PGP. + } + #endif +} + + +static int +parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) +{ + int mode, namelen; + PKT_plaintext *pt; + byte *p; + int c, i; + + if( pktlen && pktlen < 6 ) { + log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen); + goto leave; + } + mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--; + namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--; + pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1); + pt->mode = mode; + pt->namelen = namelen; + if( pktlen ) { + for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ ) + pt->name[i] = iobuf_get_noeof(inp); + } + else { + for( i=0; i < namelen; i++ ) + if( (c=iobuf_get(inp)) == -1 ) + break; + else + pt->name[i] = c; + } + pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4; + pt->len = pktlen; + pt->buf = inp; + pktlen = 0; + + if( list_mode ) { + printf(":literal data packet:\n" + "\tmode %c, created %lu, name=\"", + mode >= ' ' && mode <'z'? mode : '?', + pt->timestamp ); + for(p=pt->name,i=0; i < namelen; p++, i++ ) { + if( *p >= ' ' && *p <= 'z' ) + putchar(*p); + else + printf("\\x%02x", *p ); + } + printf("\",\n\traw data: %lu bytes\n", pt->len ); + } + + leave: + return 0; +} + + +static int +parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) +{ + PKT_compressed *zd; + int algorithm; + + /* pktlen is here 0, but data follows + * (this should be the last object in a file or + * the compress algorithm should know the length) + */ + zd = pkt->pkt.compressed = m_alloc(sizeof *pkt->pkt.compressed ); + zd->len = 0; /* not yet used */ + zd->algorithm = iobuf_get_noeof(inp); + zd->buf = inp; + algorithm = iobuf_get_noeof(inp); + if( list_mode ) + printf(":compressed packet: algo=%d\n", zd->algorithm); + return 0; +} + + +static int +parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) +{ + PKT_encr_data *ed; + + ed = pkt->pkt.encr_data = m_alloc(sizeof *pkt->pkt.encr_data ); + ed->len = pktlen; + ed->buf = NULL; + if( pktlen && pktlen < 10 ) { + log_error("packet(%d) too short\n", pkttype); + skip_rest(inp, pktlen); + goto leave; + } + if( list_mode ) + if( pktlen ) + printf(":encrypted data packet:\n\tlength: %lu\n", pktlen-10); + else + printf(":encrypted data packet:\n\tlength: unknown\n"); + + ed->buf = inp; + pktlen = 0; + + leave: + return 0; +} + + diff --git a/g10/passphrase.c b/g10/passphrase.c new file mode 100644 index 000000000..c95b27bbd --- /dev/null +++ b/g10/passphrase.c @@ -0,0 +1,126 @@ +/* passphrase.c - Get a passphrase + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "memory.h" +#include "ttyio.h" +#include "cipher.h" + + +static int hash_passphrase( DEK *dek, char *pw ); + + +/**************** + * Get a passphrase for the secret key with KEYID, display TEXT + * if the user needs to enter the passphrase. + * Returns: m_alloced md5 passphrase hash; caller must free + */ +DEK * +get_passphrase_hash( u32 *keyid, char *text ) +{ + char *p=NULL, *pw; + DEK *dek; + + if( keyid ) { + tty_printf("Need a pass phrase to unlock the secret key!\n"); + tty_printf("KeyID: %08lX\n\n", keyid[1] ); + } + if( keyid && (p=getenv("PGPPATHPHRASE")) ) { + pw = m_alloc_secure(strlen(p)+1); + strcpy(pw,p); + tty_printf("Taking it from $PGPPATHPHRASE !\n", keyid[1] ); + } + else + pw = tty_get_hidden("Enter pass phrase: " ); + dek = m_alloc_secure( sizeof *dek ); + dek->algo = CIPHER_ALGO_BLOWFISH; + if( hash_passphrase( dek, pw ) ) + log_bug("get_passphrase_hash\n"); + m_free(pw); /* is allocated in secure memory, so it will be burned */ + if( !p ) { + tty_kill_prompt(); + tty_printf("\n\n"); + } + return dek; +} + + +/**************** + * This function is used to construct a DEK from a user input. + * It uses the default CIPHER + */ +int +make_dek_from_passphrase( DEK *dek, int mode ) +{ + char *pw, *pw2; + int rc=0; + + pw = tty_get_hidden("Enter pass phrase: " ); + tty_kill_prompt(); + if( mode == 2 ) { + pw2 = tty_get_hidden("Repeat pass phrase: " ); + if( strcmp(pw, pw2) ) { + m_free(pw2); + m_free(pw); + return G10ERR_PASSPHRASE; + } + m_free(pw2); + } + rc = hash_passphrase( dek, pw ); + m_free(pw); + return rc; +} + + +static int +hash_passphrase( DEK *dek, char *pw ) +{ + int rc = 0; + + dek->keylen = 0; + if( dek->algo == CIPHER_ALGO_IDEA ) { + MD5HANDLE md5; + + md5 = md5_open(1); + md5_write( md5, pw, strlen(pw) ); + md5_final( md5 ); + dek->keylen = 16; + memcpy( dek->key, md5_read(md5), dek->keylen ); + md5_close(md5); + } + else if( dek->algo == CIPHER_ALGO_BLOWFISH ) { + RMDHANDLE rmd; + + rmd = rmd160_open(1); + rmd160_write( rmd, pw, strlen(pw) ); + dek->keylen = 20; + memcpy( dek->key, rmd160_final(rmd), dek->keylen ); + rmd160_close(rmd); + } + else + rc = G10ERR_UNSUPPORTED; + return rc; +} + diff --git a/g10/plaintext.c b/g10/plaintext.c new file mode 100644 index 000000000..be8047bd0 --- /dev/null +++ b/g10/plaintext.c @@ -0,0 +1,114 @@ +/* plaintext.c - process an plaintext packet + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include "util.h" +#include "memory.h" +#include "options.h" +#include "packet.h" +#include "ttyio.h" + + +/**************** + * Handle a plaintext packet + */ +int +handle_plaintext( PKT_plaintext *pt ) +{ + char *fname; + FILE *fp = NULL; + int rc = 0; + int c; + + /* create the filename as C string */ + if( opt.outfile ) { + fname = m_alloc( strlen( opt.outfile ) + 1); + strcpy(fname, opt.outfile ); + } + else { + fname = m_alloc( pt->namelen +1 ); + memcpy( fname, pt->name, pt->namelen ); + fname[pt->namelen] = 0; + } + + if( !*fname ) { /* no filename given */ + if( opt.outfile_is_stdout ) + fp = stdout; + else { + log_error("no outputfile given\n"); + goto leave; + } + } + else if( overwrite_filep( fname ) ) + goto leave; + + if( fp ) + ; + else if( !(fp = fopen(fname,"wb")) ) { + log_error("Error creating '%s': %s\n", fname, strerror(errno) ); + rc = G10ERR_WRITE_FILE; + goto leave; + } + + if( pt->len ) { + for( ; pt->len; pt->len-- ) { + if( (c = iobuf_get(pt->buf)) == -1 ) { + log_error("Problem reading source\n"); + rc = G10ERR_READ_FILE; + goto leave; + } + if( putc( c, fp ) == EOF ) { + log_error("Error writing to '%s': %s\n", fname, strerror(errno) ); + rc = G10ERR_WRITE_FILE; + goto leave; + } + } + } + else { + while( (c = iobuf_get(pt->buf)) != -1 ) { + if( putc( c, fp ) == EOF ) { + log_error("Error writing to '%s': %s\n", + fname, strerror(errno) ); + rc = G10ERR_WRITE_FILE; + goto leave; + } + } + iobuf_clear_eof(pt->buf); + } + + if( fp && fp != stdout && fclose(fp) ) { + log_error("Error closing '%s': %s\n", fname, strerror(errno) ); + fp = NULL; + rc = G10ERR_WRITE_FILE; + goto leave; + } + fp = NULL; + + leave: + if( fp && fp != stdout ) + fclose(fp); + m_free(fname); + return rc; +} + diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c new file mode 100644 index 000000000..18c737c2d --- /dev/null +++ b/g10/pubkey-enc.c @@ -0,0 +1,130 @@ +/* pubkey-enc.c - public key encoded packet handling + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "memory.h" +#include "packet.h" +#include "mpi.h" +#include "keydb.h" +#include "cipher.h" + + +/**************** + * Get the session key from a pubkey enc paket and return + * it in DEK, which should have been allocated in secure memory. + */ +int +get_session_key( PKT_pubkey_enc *k, DEK *dek ) +{ + int i, j, c, rc = 0; + RSA_secret_key *skey = m_alloc_secure( sizeof *skey ); + MPI dek_frame = mpi_alloc_secure(40); + u16 csum, csum2; + + if( k->pubkey_algo != PUBKEY_ALGO_RSA ) { + rc = G10ERR_PUBKEY_ALGO; /* unsupported algorithm */ + goto leave; + } + + /* get the secret key for the given public key + * and decode the rsa_integer + */ + if( (rc = get_seckey( skey, k->keyid )) ) + goto leave; + + if( DBG_CIPHER ) + log_mpidump("Encr DEK frame:", k->d.rsa.rsa_integer ); + rsa_secret( dek_frame, k->d.rsa.rsa_integer, skey ); + /* Now get the DEK (data encryption key) from the dek_frame + * + * Old versions encode the DEK in in this format (msb is left): + * + * 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2 + * + * Later versions encode the DEK like this: + * + * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) + * + * RND are non-zero randow bytes. + * A is the cipher algorithm ( 1 for IDEA, 42 for blowfish ) + * DEK is the encryption key (session key) with length k + * (16 for idea, 42 for blowfish) + * CSUM + */ + if( DBG_CIPHER ) + log_mpidump("DEK frame:", dek_frame ); + for(i=0; mpi_getbyte(dek_frame, i) != -1; i++ ) + ; + for(i--; i >= 0 && !(c=mpi_getbyte(dek_frame, i)); i--) + ; /* Skip leading zeroes */ + if( i < 16 ) + { rc = G10ERR_WRONG_SECKEY; goto leave; } + if( c == 1 && mpi_getbyte(dek_frame,0) == 2 ) { + log_error("old encoding of DEK is not supported\n"); + rc = G10ERR_CIPHER_ALGO; + goto leave; + } + if( c != 2 ) /* somethink is wrong */ + { rc = G10ERR_WRONG_SECKEY; goto leave; } + /* look for the zeor byte */ + for(i--; i > 4 ; i-- ) + if( !mpi_getbyte(dek_frame,i) ) + break; + if( i <= 4 ) /* zero byte not found */ + { rc = G10ERR_WRONG_SECKEY; goto leave; } + /* next byte indicates the used cipher */ + switch( mpi_getbyte(dek_frame, --i ) ) { + case 1: + rc = G10ERR_NI_CIPHER; + goto leave; + case 42: + if( i != 22 ) /* length of blowfish is 20 (+2 bytes checksum) */ + { rc = G10ERR_WRONG_SECKEY; goto leave; } + dek->algo = CIPHER_ALGO_BLOWFISH; + break; + default: + rc = G10ERR_CIPHER_ALGO; + goto leave; + } + /* copy the key to DEK and compare the checksum */ + csum = mpi_getbyte(dek_frame, 1) << 8; + csum |= mpi_getbyte(dek_frame, 0); + dek->keylen = i - 2; + for( i--, csum2=0, j=0; i > 1; i-- ) + csum2 += dek->key[j++] = mpi_getbyte(dek_frame, i); + if( csum != csum2 ) { + rc = G10ERR_WRONG_SECKEY; + goto leave; + } + if( DBG_CIPHER ) + log_hexdump("DEK is:", dek->key, dek->keylen ); + + leave: + mpi_free(dek_frame); + m_free(skey); + return rc; +} + + diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c new file mode 100644 index 000000000..3cae571ab --- /dev/null +++ b/g10/seckey-cert.c @@ -0,0 +1,157 @@ +/* seckey-cert.c - secret key certifucate packet handling + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "memory.h" +#include "packet.h" +#include "mpi.h" +#include "keydb.h" +#include "cipher.h" + + +static u16 +checksum( byte *p ) +{ + u16 n, a; + + n = *p++ << 8; + n |= *p++; + for(a=0; n; n-- ) + a += *p++; + return a; +} + + +/**************** + * Check the secret key certificate + */ +int +check_secret_key( PKT_seckey_cert *cert ) +{ + IDEA_context idea_ctx; /* FIXME: allocate this in secure space ! */ + byte iv[8]; + byte *mpibuf; + u16 n; + MPI temp_mpi; + int res; + u32 keyid[2]; + +#if IDEA_BLOCKSIZE != 8 || BLOWFISH_BLOCKSIZE != 8 + #error unsupportted blocksize +#endif + + if( cert->pubkey_algo != PUBKEY_ALGO_RSA ) + return G10ERR_PUBKEY_ALGO; /* unsupport algorithm */ + + if( cert->d.rsa.is_protected ) { /* remove the protection */ + DEK *dek = NULL; + BLOWFISH_context *blowfish_ctx=NULL; + + switch( cert->d.rsa.protect_algo ) { + case CIPHER_ALGO_NONE: + log_bug("unprotect seckey_cert is flagged protected\n"); + break; + case CIPHER_ALGO_IDEA: + case CIPHER_ALGO_BLOWFISH: + mpi_get_keyid( cert->d.rsa.rsa_n , keyid ); + dek = get_passphrase_hash( keyid, NULL ); + + /* idea_setkey( &idea_ctx, dpw );*/ + m_free(dek); /* pw is in secure memory, so m_free() burns it */ + memset( iv, 0, BLOWFISH_BLOCKSIZE ); + if( cert->d.rsa.protect_algo == CIPHER_ALGO_IDEA ) { + idea_setiv( &idea_ctx, iv ); + /* fixme: is it save to leave the IV unencrypted in the + * certificate or should we move it to secure storage? */ + idea_decode_cfb( &idea_ctx, cert->d.rsa.protect.idea.iv, + cert->d.rsa.protect.idea.iv, 8 ); + } + else { + blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx ); + blowfish_setiv( blowfish_ctx, iv ); + blowfish_decode_cfb( blowfish_ctx, + cert->d.rsa.protect.blowfish.iv, + cert->d.rsa.protect.blowfish.iv, 8 ); + } + cert->d.rsa.calc_csum = 0; + #define X(a) do { \ + mpibuf = (byte*)cert->d.rsa.rsa_##a; \ + n = ((mpibuf[0] << 8) | mpibuf[1])-2; \ + if( blowfish_ctx ) \ + blowfish_decode_cfb( blowfish_ctx, \ + mpibuf+4, mpibuf+4, n ); \ + else \ + idea_decode_cfb( &idea_ctx, mpibuf+4, mpibuf+4, n );\ + cert->d.rsa.calc_csum += checksum( mpibuf ); \ + cert->d.rsa.rsa_##a = mpi_decode_buffer( mpibuf ); \ + m_free( mpibuf ); \ + } while(0) + X(d); + X(p); + X(q); + X(u); + #undef X + m_free( blowfish_ctx ); + cert->d.rsa.is_protected = 0; + #if 0 + #define X(a) do { printf("\tRSA " #a ": "); \ + mpi_print(stdout, cert->d.rsa.rsa_##a, 1 ); \ + putchar('\n'); \ + } while(0) + X(n); + X(e); + X(d); + X(p); + X(q); + X(u); + #undef X + #endif + /* now let's see wether we have used the right passphrase */ + if( cert->d.rsa.calc_csum != cert->d.rsa.csum ) + return G10ERR_BAD_PASS; + temp_mpi = mpi_alloc(40); + mpi_mul(temp_mpi, cert->d.rsa.rsa_p, cert->d.rsa.rsa_q ); + res = mpi_cmp( temp_mpi, cert->d.rsa.rsa_n ); + mpi_free(temp_mpi); + if( res ) + return G10ERR_BAD_PASS; + break; + + default: + return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */ + } + } + /* must check the checksum here, because we didn't do it when + * parsing an unprotected certificate */ + if( cert->d.rsa.calc_csum != cert->d.rsa.csum ) { + log_error("checksum in secret key certificate is wrong\n"); + log_debug("stored csum=%04hx calculated csum=%04hx\n", + cert->d.rsa.csum, cert->d.rsa.calc_csum ); + return G10ERR_CHECKSUM; + } + return 0; +} + + diff --git a/g10/seskey.c b/g10/seskey.c new file mode 100644 index 000000000..d81697296 --- /dev/null +++ b/g10/seskey.c @@ -0,0 +1,101 @@ +/* seskey.c - make sesssion keys + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "cipher.h" +#include "mpi.h" + + + +/**************** + * Make a session key and put it into DEK + */ +void +make_session_key( DEK *dek ) +{ + switch( dek->algo ) { + case CIPHER_ALGO_BLOWFISH: + dek->keylen = 20; + randomize_buffer( dek->key, dek->keylen, 1 ); + break; + + default: log_bug("invalid algo %d in make_session_key()\n"); + } +} + + +/**************** + * Encode the session key. NBITS is the number of bits which should be used + * for packing teh session key. + * returns: A mpi with the session key (caller must free) + */ +MPI +encode_session_key( DEK *dek, unsigned nbits ) +{ + int nframe = (nbits+7) / 8; + byte *p; + MPI frame; + int i,n,c; + u16 csum; + + /* the current limitation is, that we can only use a session key + * which length is a multiple of BITS_PER_MPI_LIMB + * I think we can live with that. + */ + if( dek->keylen + 7 > nframe || (nbits % BITS_PER_MPI_LIMB) || !nframe ) + log_bug("can't encode a %d bit key in a %d bits frame\n", + dek->keylen*8, nbits ); + + /* We encode the session key in this way: + * + * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) + * + * RND are non-zero random bytes. + * A is the cipher algorithm ( 42 for Blowfish ) + * DEK is the encryption key (session key) length k depends on the + * cipher algorithm (20 is used with blowfish). + * CSUM is the 16 bit checksum over the DEK + */ + frame = mpi_alloc_secure( nframe / BYTES_PER_MPI_LIMB ); + csum = 0; + for( p = dek->key, i=0; i < dek->keylen; i++ ) + csum += *p++; + mpi_putbyte(frame, 0, csum ); + mpi_putbyte(frame, 1, csum >> 8 ); + for(n=2,i=dek->keylen-1, p = dek->key; i >= 0; i--, n++ ) + mpi_putbyte(frame, n, p[i] ); + mpi_putbyte(frame, n++, dek->algo ); + mpi_putbyte(frame, n++, 0 ); + while( n < nframe-2 ) { + while( !(c = get_random_byte(1)) ) + ; + mpi_putbyte(frame, n++, c ); + } + mpi_putbyte(frame, n++, 2 ); + mpi_putbyte(frame, n++, 0 ); + assert( n == nframe ); + return frame; +} + diff --git a/g10/sig-check.c b/g10/sig-check.c new file mode 100644 index 000000000..41ac89341 --- /dev/null +++ b/g10/sig-check.c @@ -0,0 +1,213 @@ +/* sig-check.c - Check a signature + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "packet.h" +#include "memory.h" +#include "mpi.h" +#include "keydb.h" +#include "cipher.h" + + +/**************** + * Check the signature which is contained in the rsa_integer. + * The md5handle should be currently open, so that this function + * is able to append some data, before getting the digest. + */ +int +signature_check( PKT_signature *sig, MD_HANDLE digest ) +{ + PKT_pubkey_cert *pkc = m_alloc_clear( sizeof *pkc ); + MPI result = mpi_alloc(35); + int rc=0, i, j, c, old_enc; + byte *dp; + + + if( get_pubkey( pkc, sig->keyid ) ) { + rc = G10ERR_NO_PUBKEY; + goto leave; + } + + if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { + RSA_public_key pkey; + pkey.n = pkc->d.rsa.rsa_n; + pkey.e = pkc->d.rsa.rsa_e; + rsa_public( result, sig->d.rsa.rsa_integer, &pkey ); + } + else { + log_debug("signature_check: unsupported pubkey algo %d\n", + pkc->pubkey_algo ); + rc = G10ERR_PUBKEY_ALGO; + goto leave; + } + + + /* Now RESULT contains the deciphered session key. + * + * The session key is stored in different ways: + * + * Old versions encodes the digest in in this format (msb is left): + * + * 0 1 MD5(16 bytes) 0 PAD(n bytes) 1 + * + * Later versions encodes the digest like this: + * + * 0 1 PAD(n bytes) 0 ASN(18 bytes) MD(16 bytes) + * + * RIPE MD 160 digests are encoded like this: + * + * 0 42 PAD(n bytes) 0 ASN(18 bytes) MD(20 bytes) + * + * FIXME: we should use another ASN! + * + * PAD consists of FF bytes. + * ASN is here the constant: 3020300c06082a864886f70d020505000410 + */ + old_enc = 0; + for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) { + if( !j ) { + if( !i && c != 1 ) + break; + else if( i && c == 0xff ) + ; /* skip the padding */ + else if( i && !c ) + j++; + else + break; + } + else if( ++j == 18 && c != 1 ) + break; + else if( j == 19 && c == 0 ) { + old_enc++; + break; + } + } + if( old_enc ) { + log_error("old encoding scheme is not supported\n"); + rc = G10ERR_GENERAL; + goto leave; + } + + if( sig->d.rsa.digest_algo == DIGEST_ALGO_RMD160 ) { + static byte asn[18] = /* stored reverse FIXME: need other values*/ + { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86, + 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 }; + + for(i=20,j=0; j < 18 && (c=mpi_getbyte(result, i)) != -1; i++, j++ ) + if( asn[j] != c ) + break; + if( j != 18 ) { /* ASN is wrong */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + if( !c ) { + for(; (c=mpi_getbyte(result, i)) != -1; i++ ) + if( c != 0xff ) + break; + if( c != 42 || mpi_getbyte(result, i) ) { + /* Padding or leading bytes in signature is wrong */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + if( mpi_getbyte(result, 19) != sig->d.rsa.digest_start[0] + || mpi_getbyte(result, 18) != sig->d.rsa.digest_start[1] ) { + /* Wrong key used to check the signature */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + } + + /* complete the digest */ + rmd160_putchar( digest.u.rmd, sig->sig_class ); + { u32 a = sig->timestamp; + rmd160_putchar( digest.u.rmd, (a >> 24) & 0xff ); + rmd160_putchar( digest.u.rmd, (a >> 16) & 0xff ); + rmd160_putchar( digest.u.rmd, (a >> 8) & 0xff ); + rmd160_putchar( digest.u.rmd, a & 0xff ); + } + dp = rmd160_final( digest.u.rmd ); + for(i=19; i >= 0; i--, dp++ ) + if( mpi_getbyte( result, i ) != *dp ) { + rc = G10ERR_BAD_SIGN; + goto leave; + } + } + else if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) { + static byte asn[18] = /* stored reverse */ + { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86, + 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 }; + + for(i=16,j=0; j < 18 && (c=mpi_getbyte(result, i)) != -1; i++, j++ ) + if( asn[j] != c ) + break; + if( j != 18 ) { /* ASN is wrong */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + if( !c ) { + for(; (c=mpi_getbyte(result, i)) != -1; i++ ) + if( c != 0xff ) + break; + if( c != 1 || mpi_getbyte(result, i) ) { + /* Padding or leading bytes in signature is wrong */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + if( mpi_getbyte(result, 15) != sig->d.rsa.digest_start[0] + || mpi_getbyte(result, 14) != sig->d.rsa.digest_start[1] ) { + /* Wrong key used to check the signature */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + } + + /* complete the digest */ + md5_putchar( digest.u.md5, sig->sig_class ); + { u32 a = sig->timestamp; + md5_putchar( digest.u.md5, (a >> 24) & 0xff ); + md5_putchar( digest.u.md5, (a >> 16) & 0xff ); + md5_putchar( digest.u.md5, (a >> 8) & 0xff ); + md5_putchar( digest.u.md5, a & 0xff ); + } + md5_final( digest.u.md5 ); + dp = md5_read( digest.u.md5 ); + for(i=15; i >= 0; i--, dp++ ) + if( mpi_getbyte( result, i ) != *dp ) { + rc = G10ERR_BAD_SIGN; + goto leave; + } + } + else { + rc = G10ERR_DIGEST_ALGO; + goto leave; + } + + leave: + mpi_free( result ); + if( pkc ) + free_pubkey_cert( pkc ); + return rc; +} + diff --git a/include/cipher.h b/include/cipher.h new file mode 100644 index 000000000..ac19c3fc0 --- /dev/null +++ b/include/cipher.h @@ -0,0 +1,87 @@ +/* cipher.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * ATTENTION: This code should not be exported from the United States + * nor should it be used their without a license agreement with PKP. + * The RSA alorithm is protected by U.S. Patent #4,405,829 which + * expires on September 20, 2000! + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_CIPHER_H +#define G10_CIPHER_H + +#define DBG_CIPHER cipher_debug_mode + +#include "mpi.h" +#include "../cipher/md5.h" +#include "../cipher/rmd.h" +#include "../cipher/rsa.h" +#include "../cipher/idea.h" +#include "../cipher/blowfish.h" +#include "../cipher/gost.h" +#include "../cipher/elgamal.h" + + +#define CIPHER_ALGO_NONE 0 +#define CIPHER_ALGO_IDEA 1 +#define CIPHER_ALGO_BLOWFISH 42 +#define CIPHER_ALGO_GOST 43 + +#define PUBKEY_ALGO_RSA 1 +#define PUBKEY_ALGO_ELGAMAL 42 + +#define DIGEST_ALGO_MD5 1 +#define DIGEST_ALGO_RMD160 42 + +#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_BLOWFISH +#define DEFAULT_PUBKEY_ALGO PUBKEY_ALGO_RSA +#define DEFAULT_DIGEST_ALGO DIGEST_ALGO_RMD160 + +typedef struct { + int algo; + int keylen; + byte key[20]; /* this is the largest used keylen */ +} DEK; + +typedef struct { + int algo; /* digest algo */ + union { + MD5HANDLE md5; + RMDHANDLE rmd; + } u; +} MD_HANDLE; + + +int cipher_debug_mode; + +/*-- random.c --*/ +void randomize_buffer( byte *buffer, size_t length, int level ); +byte get_random_byte( int level ); + +/*-- smallprime.c --*/ +extern ushort small_prime_numbers[]; + +/*-- primegen.c --*/ +MPI generate_random_prime( unsigned nbits ); + +/*-- seskey.c --*/ +void make_session_key( DEK *dek ); +MPI encode_session_key( DEK *dek, unsigned nbits ); + + +#endif /*G10_CIPHER_H*/ diff --git a/include/errors.h b/include/errors.h new file mode 100644 index 000000000..f2e7570cc --- /dev/null +++ b/include/errors.h @@ -0,0 +1,52 @@ +/* errors.h - erro code + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_ERRORS_H +#define G10_ERRORS_H + +#define G10ERR_GENERAL 1 +#define G10ERR_UNKNOWN_PACKET 2 +#define G10ERR_UNKNOWN_VERSION 3 /* Unknown version (in packet) */ +#define G10ERR_PUBKEY_ALGO 4 /* Unknown pubkey algorithm */ +#define G10ERR_DIGEST_ALGO 5 /* Unknown digest algorithm */ +#define G10ERR_BAD_PUBKEY 6 /* Bad public key */ +#define G10ERR_BAD_SECKEY 7 /* Bad secret key */ +#define G10ERR_BAD_SIGN 8 /* Bad signature */ +#define G10ERR_NO_PUBKEY 9 /* public key not found */ +#define G10ERR_CHECKSUM 10 /* checksum error */ +#define G10ERR_BAD_PASS 11 /* Bad passphrase */ +#define G10ERR_CIPHER_ALGO 12 /* Unknown cipher algorithm */ +#define G10ERR_KEYRING_OPEN 13 +#define G10ERR_INVALID_PACKET 14 +#define G10ERR_BAD_RING 15 +#define G10ERR_NO_USER_ID 16 +#define G10ERR_NO_SECKEY 17 /* secret key not available */ +#define G10ERR_WRONG_SECKEY 18 /* wrong seckey used */ +#define G10ERR_UNSUPPORTED 19 +#define G10ERR_BAD_KEY 20 /* bad (session) key */ +#define G10ERR_READ_FILE 21 +#define G10ERR_WRITE_FILE 22 +#define G10ERR_COMPR_ALGO 23 /* Unknown compress algorithm */ +#define G10ERR_OPEN_FILE 24 +#define G10ERR_CREATE_FILE 25 +#define G10ERR_PASSPHRASE 26 /* invalid passphrase */ +#define G10ERR_NI_PUBKEY 27 +#define G10ERR_NI_CIPHER 28 + +#endif /*G10_ERRORS_H*/ diff --git a/include/iobuf.h b/include/iobuf.h new file mode 100644 index 000000000..328cd8da5 --- /dev/null +++ b/include/iobuf.h @@ -0,0 +1,120 @@ +/* iobuf.h - I/O buffer + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef G10_IOBUF_H +#define G10_IOBUF_H + +#include "types.h" + + +#define DBG_IOBUF iobuf_debug_mode + + +#define IOBUFCTRL_INIT 1 +#define IOBUFCTRL_FREE 2 +#define IOBUFCTRL_UNDERFLOW 3 +#define IOBUFCTRL_FLUSH 4 +#define IOBUFCTRL_DESC 5 +#define IOBUFCTRL_USER 16 + +typedef struct iobuf_struct *IOBUF; + +struct iobuf_struct { + int usage; /* 1 input , 2 output, 3 temp */ + unsigned long nlimit; + unsigned long nbytes; + struct { + size_t size; /* allocated size */ + size_t start; /* number of invalid bytes at the begin of the buffer */ + size_t len; /* currently filled to this size */ + byte *buf; + } d; + struct { + size_t size; + size_t len; + char *buf; + } recorder; + int filter_eof; + int (*filter)( void *opaque, int control, + IOBUF chain, byte *buf, size_t *len); + void *filter_ov; /* value for opaque */ + IOBUF chain; /* next iobuf used for i/o if any (passed to filter) */ + int no, subno; + const char *desc; +}; + +int iobuf_debug_mode; + +IOBUF iobuf_alloc(int usage, size_t bufsize); +IOBUF iobuf_temp(void); +IOBUF iobuf_open( const char *fname ); +IOBUF iobuf_create( const char *fname ); +int iobuf_close( IOBUF iobuf ); +int iobuf_cancel( IOBUF iobuf ); + +int iobuf_push_filter( IOBUF a, int (*f)(void *opaque, int control, + IOBUF chain, byte *buf, size_t *len), void *ov ); +int iobuf_pop_filter( IOBUF a, int (*f)(void *opaque, int control, + IOBUF chain, byte *buf, size_t *len), void *ov ); +int iobuf_flush(IOBUF a); +void iobuf_clear_eof(IOBUF a); + +void iobuf_set_limit( IOBUF a, unsigned long nlimit ); + +int iobuf_readbyte(IOBUF a); +int iobuf_writebyte(IOBUF a, unsigned c); +int iobuf_write(IOBUF a, byte *buf, unsigned buflen ); + +int iobuf_write_temp( IOBUF a, IOBUF temp ); +size_t iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen ); + +void iobuf_start_recorder( IOBUF a ); +void iobuf_push_recorder( IOBUF a, int c ); +char *iobuf_stop_recorder( IOBUF a, size_t *n ); + +u32 iobuf_get_filelength( IOBUF a ); + +void iobuf_set_block_mode( IOBUF a, size_t n ); +int iobuf_in_block_mode( IOBUF a ); + +/* get a byte form the iobuf; must check for eof prior to this function + * this function returns values in the range 0 .. 255 or -1 to indicate EOF + * iobuf_get_noeof() does not return -1 to indicate EOF, but masks the + * returned value to be in the range 0 ..255. + */ +#define iobuf_get(a) \ + ( ((a)->recorder.buf || (a)->nlimit \ + || (a)->d.start >= (a)->d.len )? \ + iobuf_readbyte((a)) : ( (a)->nbytes++, (a)->d.buf[(a)->d.start++] ) ) +#define iobuf_get_noeof(a) (iobuf_get((a))&0xff) + + +/* write a byte to the iobuf and return true on write error + * This macro does only write the low order byte + */ +#define iobuf_put(a,c) iobuf_writebyte(a,c) + +#define iobuf_where(a) "[don't know]" +#define iobuf_id(a) ((a)->no) + +#define iobuf_get_temp_length(a) ( (a)->d.len ) +#define iobuf_is_temp(a) ( (a)->usage == 3 ) + +#endif /*G10_IOBUF_H*/ diff --git a/include/memory.h b/include/memory.h new file mode 100644 index 000000000..aa8bb706d --- /dev/null +++ b/include/memory.h @@ -0,0 +1,64 @@ +/* memory.h - memory allocation + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef G10_MEMORY_H +#define G10_MEMORY_H + +#ifdef M_DEBUG +#ifndef STR + #define STR(v) #v +#endif +#define M_DBGINFO(a) __FUNCTION__ "["__FILE__ ":" STR(a) "]" +#define m_alloc(n) m_debug_alloc((n), M_DBGINFO( __LINE__ ) ) +#define m_alloc_clear(n) m_debug_alloc_clear((n), M_DBGINFO(__LINE__) ) +#define m_alloc_secure(n) m_debug_alloc((n), M_DBGINFO(__LINE__) ) +#define m_alloc_secure_clear(n) m_debug_alloc((n), M_DBGINFO(__LINE__) ) +#define m_realloc(n,m) m_debug_realloc((n),(m), M_DBGINFO(__LINE__) ) +#define m_free(n) m_debug_free((n), M_DBGINFO(__LINE__) ) +#define m_check(n) m_debug_check((n), M_DBGINFO(__LINE__) ) + +void *m_debug_alloc( size_t n, const char *info ); +void *m_debug_alloc_clear( size_t n, const char *info ); +void *m_debug_alloc_secure( size_t n, const char *info ); +void *m_debug_alloc_secure_clear( size_t n, const char *info ); +void *m_debug_realloc( void *a, size_t n, const char *info ); +void m_debug_free( void *p, const char *info ); +void m_debug_check( const void *a, const char *info ); + +#else +void *m_alloc( size_t n ); +void *m_alloc_clear( size_t n ); +void *m_alloc_secure( size_t n ); +void *m_alloc_secure_clear( size_t n ); +void *m_realloc( void *a, size_t n ); +void m_free( void *p ); +void m_check( const void *a ); +#endif + + +size_t m_size( const void *a ); +int m_is_secure( const void *p ); + +#define DBG_MEMORY memory_debug_mode +#define DBG_MEMSTAT memory_stat_debug_mode +int memory_debug_mode; +int memory_stat_debug_mode; + +#endif /*G10_MEMORY_H*/ diff --git a/include/mpi.h b/include/mpi.h new file mode 100644 index 000000000..4470c609a --- /dev/null +++ b/include/mpi.h @@ -0,0 +1,147 @@ +/* mpi.h - Multi Precision Integers + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef G10_MPI_H +#define G10_MPI_H + +#include <stdio.h> +#include "iobuf.h" +#include "types.h" +#include "memory.h" + + +#define DBG_MPI mpi_debug_mode +int mpi_debug_mode; + +#if defined(__i386__) + #define BITS_PER_MPI_LIMB 32 + #define BYTES_PER_MPI_LIMB 4 + #define BYTES_PER_MPI_LIMB2 8 + typedef unsigned long int mpi_limb_t; + typedef signed long int mpi_limb_signed_t; +#else + #error add definions for this machine here +#endif + +typedef struct { + int alloced; /* array size (# of allocated limbs) */ + int nlimbs; /* number of valid limbs */ + int sign; /* indicates a negative number */ + int secure; /* array mut be allocated in secure memory space */ + mpi_limb_t *d; /* array with the limbs */ +} *MPI; + +#define MPI_NULL NULL + +#define mpi_get_nlimbs(a) ((a)->nlimbs) + +/*-- mpiutil.c --*/ + +#ifdef M_DEBUG + #define mpi_alloc(n) mpi_debug_alloc((n), M_DBGINFO( __LINE__ ) ) + #define mpi_alloc_secure(n) mpi_debug_alloc_secure((n), M_DBGINFO( __LINE__ ) ) + #define mpi_free(a) mpi_debug_free((a), M_DBGINFO(__LINE__) ) + #define mpi_resize(a,b) mpi_debug_resize((a),(b), M_DBGINFO(__LINE__) ) + #define mpi_copy(a) mpi_debug_copy((a), M_DBGINFO(__LINE__) ) + MPI mpi_debug_alloc( unsigned nlimbs, const char *info ); + MPI mpi_debug_alloc_secure( unsigned nlimbs, const char *info ); + void mpi_debug_free( MPI a, const char *info ); + void mpi_debug_resize( MPI a, unsigned nlimbs, const char *info ); + MPI mpi_debug_copy( MPI a, const char *info ); +#else + MPI mpi_alloc( unsigned nlimbs ); + MPI mpi_alloc_secure( unsigned nlimbs ); + void mpi_free( MPI a ); + void mpi_resize( MPI a, unsigned nlimbs ); + MPI mpi_copy( MPI a ); +#endif +void mpi_clear( MPI a ); +void mpi_set( MPI w, MPI u); +void mpi_set_ui( MPI w, ulong u); +MPI mpi_alloc_set_ui( unsigned long u); +void mpi_m_check( MPI a ); +void mpi_swap( MPI a, MPI b); + +/*-- mpicoder.c --*/ +int mpi_encode( IOBUF out, MPI a ); +int mpi_encode_csum( IOBUF out, MPI a, u16 *csum ); +int mpi_write( IOBUF out, byte *a); +int mpi_write_csum( IOBUF out, byte *a, u16 *csum); +#ifdef M_DEBUG + #define mpi_decode(a,b) mpi_debug_decode((a),(b), M_DBGINFO( __LINE__ ) ) + #define mpi_decode_buffer(a) mpi_debug_decode_buffer((a), M_DBGINFO( __LINE__ ) ) + MPI mpi_debug_decode(IOBUF inp, unsigned *nread, const char *info); + MPI mpi_debug_decode_buffer(byte *buffer, const char *info ); +#else + MPI mpi_decode(IOBUF inp, unsigned *nread); + MPI mpi_decode_buffer(byte *buffer ); +#endif +byte *mpi_read(IOBUF inp, unsigned *ret_nread); +int mpi_fromstr(MPI val, const char *str); +int mpi_print( FILE *fp, MPI a, int mode ); +u32 mpi_get_keyid( MPI a, u32 *keyid ); + +/*-- mpi-add.c --*/ +void mpi_add_ui(MPI w, MPI u, ulong v ); +void mpi_add(MPI w, MPI u, MPI v); +void mpi_sub_ui(MPI w, MPI u, ulong v ); +void mpi_sub( MPI w, MPI u, MPI v); + +/*-- mpi-mul.c --*/ +void mpi_mul_ui(MPI w, MPI u, ulong v ); +void mpi_mul_2exp( MPI w, MPI u, ulong cnt); +void mpi_mul( MPI w, MPI u, MPI v); + +/*-- mpi-div.c --*/ +ulong mpi_fdiv_r_ui( MPI rem, MPI dividend, ulong divisor ); +void mpi_fdiv_r( MPI rem, MPI dividend, MPI divisor ); +void mpi_fdiv_q( MPI quot, MPI dividend, MPI divisor ); +void mpi_fdiv_qr( MPI quot, MPI rem, MPI dividend, MPI divisor ); +void mpi_tdiv_r( MPI rem, MPI num, MPI den); +void mpi_tdiv_qr( MPI quot, MPI rem, MPI num, MPI den); +int mpi_divisible_ui(MPI dividend, ulong divisor ); + +/*-- mpi-gcd.c --*/ +int mpi_gcd( MPI g, MPI a, MPI b ); + +/*-- mpi-pow.c --*/ +void mpi_pow( MPI w, MPI u, MPI v); +void mpi_powm( MPI res, MPI base, MPI exp, MPI mod); + +/*-- mpi-cmp.c --*/ +int mpi_cmp_ui( MPI u, ulong v ); +int mpi_cmp( MPI u, MPI v ); + +/*-- mpi-scan.c --*/ +int mpi_getbyte( MPI a, unsigned index ); +void mpi_putbyte( MPI a, unsigned index, int value ); + +/*-- mpi-bit.c --*/ +unsigned mpi_get_nbits( MPI a ); +int mpi_test_bit( MPI a, unsigned n ); +void mpi_set_bit( MPI a, unsigned n ); +void mpi_clear_bit( MPI a, unsigned n ); +void mpi_set_bytes( MPI a, unsigned nbits, byte (*fnc)(int), int opaque ); + +/*-- mpi-inv.c --*/ +int mpi_inv_mod( MPI x, MPI u, MPI v ); + + +#endif /*G10_MPI_H*/ diff --git a/include/ttyio.h b/include/ttyio.h new file mode 100644 index 000000000..80f66d842 --- /dev/null +++ b/include/ttyio.h @@ -0,0 +1,29 @@ +/* ttyio.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_TTYIO_H +#define G10_TTYIO_H + +void tty_printf( const char *fmt, ... ); +char *tty_get( const char *prompt ); +char *tty_get_hidden( const char *prompt ); +void tty_kill_prompt(void); + + +#endif /*G10_TTYIO_H*/ diff --git a/include/types.h b/include/types.h new file mode 100644 index 000000000..7db849f41 --- /dev/null +++ b/include/types.h @@ -0,0 +1,76 @@ +/* types.h - some common typedefs + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef G10_TYPES_H +#define G10_TYPES_H + +#ifdef __linux__ + #include <linux/types.h> + #define HAVE_ULONG_TYPEDEF + #define HAVE_USHORT_TYPEDEF +#endif + + +/* Common code */ +#ifndef HAVE_ULONG_TYPEDEF + #define HAVE_ULONG_TYPEDEF + typedef unsigned long ulong; +#endif +#ifndef HAVE_USHORT_TYPEDEF + #define HAVE_USHORT_TYPEDEF + typedef unsigned short ushort; +#endif + + +typedef struct string_list { + struct string_list *next; + char d[1]; +} *STRLIST; + + + +/**************************************** + ******** machine dependent stuff ******* + ****************************************/ + +#if defined(__hpux) + #define HAVE_BIG_ENDIAN 1 +#else + #define HAVE_LITTLE_ENDIAN 1 +#endif + + +/*** some defaults ***/ +#ifndef HAVE_BYTE_TYPEDEF + #define HAVE_BYTE_TYPEDEF + typedef unsigned char byte; +#endif +#ifndef HAVE_U16_TYPEDEF + #define HAVE_U16_TYPEDEF + typedef unsigned short u16; +#endif +#ifndef HAVE_U32_TYPEDEF + #define HAVE_U32_TYPEDEF + typedef unsigned long u32; +#endif + + + +#endif /*G10_TYPES_H*/ diff --git a/include/util.h b/include/util.h new file mode 100644 index 000000000..6740e5edd --- /dev/null +++ b/include/util.h @@ -0,0 +1,100 @@ +/* util.h + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_UTIL_H +#define G10_UTIL_H + +#include "errors.h" +#include "types.h" +#include "mpi.h" + + +typedef struct { + int *argc; /* pointer to argc (value subject to change) */ + char ***argv; /* pointer to argv (value subject to change) */ + unsigned flags; /* Global flags (DO NOT CHANGE) */ + int err; /* print error about last option */ + /* 1 = warning, 2 = abort */ + int r_opt; /* return option */ + int r_type; /* type of return value (0 = no argument found)*/ + union { + int ret_int; + long ret_long; + ulong ret_ulong; + char *ret_str; + } r; /* Return values */ + struct { + int index; + int inarg; + int stopped; + const char *last; + } internal; /* DO NOT CHANGE */ +} ARGPARSE_ARGS; + +typedef struct { + int short_opt; + const char *long_opt; + unsigned flags; + const char *description; /* optional option description */ +} ARGPARSE_OPTS; + +/*-- logger.c --*/ +void printstr( int level, const char *fmt, ... ); +void log_bug( const char *fmt, ... ); +void log_fatal( const char *fmt, ... ); +void log_error( const char *fmt, ... ); +void log_info( const char *fmt, ... ); +void log_debug( const char *fmt, ... ); +void log_hexdump( const char *text, char *buf, size_t len ); +void log_mpidump( const char *text, MPI a ); + +/*-- errors.c --*/ +const char * g10_errstr( int no ); + +/*-- argparse.c --*/ +int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); +void usage( int level ); +const char *default_strusage( int level ); + + +/*-- (main program) --*/ +const char *strusage( int level ); + + +/*-- fileutil.c --*/ + +/*-- miscutil.c --*/ +u32 make_timestamp(void); + +/*-- strgutil.c --*/ +void free_strlist( STRLIST sl ); +#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0) +char *memistr( char *buf, size_t buflen, const char *sub ); +#define stricmp(a,b) strcasecmp((a),(b)) + + +/******** some macros ************/ +#ifndef STR + #define STR(v) #v +#endif +#define STR2(v) STR(v) +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define DIMof(type,member) DIM(((type *)0)->member) + +#endif /*G10_UTIL_H*/ diff --git a/mpi/Makefile.am b/mpi/Makefile.am new file mode 100644 index 000000000..5edd90c28 --- /dev/null +++ b/mpi/Makefile.am @@ -0,0 +1,27 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +noinst_LIBRARIES = mpi + + +mpi_SOURCES = longlong.h \ + mpi-add.c \ + mpi-bit.c \ + mpi-cmp.c \ + mpi-div.c \ + mpi-gcd.c \ + mpi-internal.h \ + mpi-inv.c \ + mpi-mul.c \ + mpi-pow.c \ + mpi-scan.c \ + mpicoder.c \ + mpihelp-add.c \ + mpihelp-cmp.c \ + mpihelp-div.c \ + mpihelp-mul.c \ + mpihelp-shift.c \ + mpihelp-sub.c \ + mpiutil.c + diff --git a/mpi/Makefile.in b/mpi/Makefile.in new file mode 100644 index 000000000..4f493a88e --- /dev/null +++ b/mpi/Makefile.in @@ -0,0 +1,271 @@ +# Makefile.in generated automatically by automake 1.0 from Makefile.am + +# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +INCLUDES = -I$(top_srcdir)/include + +noinst_LIBRARIES = mpi + +mpi_SOURCES = longlong.h \ + mpi-add.c \ + mpi-bit.c \ + mpi-cmp.c \ + mpi-div.c \ + mpi-gcd.c \ + mpi-internal.h \ + mpi-inv.c \ + mpi-mul.c \ + mpi-pow.c \ + mpi-scan.c \ + mpicoder.c \ + mpihelp-add.c \ + mpihelp-cmp.c \ + mpihelp-div.c \ + mpihelp-mul.c \ + mpihelp-shift.c \ + mpihelp-sub.c \ + mpiutil.c +mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs +CONFIG_HEADER = ../config.h +LIBRARIES = $(noinst_LIBRARIES) + +noinst_LIBFILES = libmpi.a + +CC = @CC@ +LEX = @LEX@ +YACC = @YACC@ + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(LDFLAGS) -o $@ +mpi_LIBADD = +mpi_OBJECTS = mpi-add.o mpi-bit.o mpi-cmp.o mpi-div.o mpi-gcd.o \ +mpi-inv.o mpi-mul.o mpi-pow.o mpi-scan.o mpicoder.o mpihelp-add.o \ +mpihelp-cmp.o mpihelp-div.o mpihelp-mul.o mpihelp-shift.o mpihelp-sub.o \ +mpiutil.o +EXTRA_mpi_SOURCES = +LIBFILES = libmpi.a +AR = ar +RANLIB = @RANLIB@ +DIST_COMMON = Makefile.am Makefile.in + + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA) +DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA) + +TAR = tar +DEP_FILES = $(srcdir)/.deps/mpi-add.P $(srcdir)/.deps/mpi-bit.P \ +$(srcdir)/.deps/mpi-cmp.P $(srcdir)/.deps/mpi-div.P \ +$(srcdir)/.deps/mpi-gcd.P $(srcdir)/.deps/mpi-inv.P \ +$(srcdir)/.deps/mpi-mul.P $(srcdir)/.deps/mpi-pow.P \ +$(srcdir)/.deps/mpi-scan.P $(srcdir)/.deps/mpicoder.P \ +$(srcdir)/.deps/mpihelp-add.P $(srcdir)/.deps/mpihelp-cmp.P \ +$(srcdir)/.deps/mpihelp-div.P $(srcdir)/.deps/mpihelp-mul.P \ +$(srcdir)/.deps/mpihelp-shift.P $(srcdir)/.deps/mpihelp-sub.P \ +$(srcdir)/.deps/mpiutil.P +SOURCES = $(mpi_SOURCES) +OBJECTS = $(mpi_OBJECTS) + +default: all + + +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in + cd $(top_srcdir) && automake $(subdir)/Makefile + +Makefile: $(top_builddir)/config.status Makefile.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + rm -f $(noinst_LIBFILES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) $< + +mostlyclean-compile: + rm -f *.o core + +clean-compile: + +distclean-compile: + rm -f *.tab.c + +maintainer-clean-compile: +$(mpi_OBJECTS): ../config.h + +libmpi.a: $(mpi_OBJECTS) $(mpi_LIBADD) + rm -f libmpi.a + $(AR) cru libmpi.a $(mpi_OBJECTS) $(mpi_LIBADD) + $(RANLIB) libmpi.a + +ID: $(HEADERS) $(SOURCES) + here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS) + +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) + here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + rm -f TAGS ID + +maintainer-clean-tags: + +subdir = mpi +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +distdir: $(DEP_DISTFILES) + @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \ + test -f $(distdir)/$$file \ + || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $(srcdir)/$$file $(distdir)/$$file; \ + done + +# This fragment is probably only useful for maintainers. It relies on +# GNU make and gcc. It is only included in the generated Makefile.in +# if `automake' is not passed the `--include-deps' flag. + +MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) + +-include $(srcdir)/.deps/.P +$(srcdir)/.deps/.P: $(BUILT_SOURCES) + cd $(srcdir) && test -d .deps || mkdir .deps + echo > $@ + +-include $(DEP_FILES) +$(DEP_FILES): $(srcdir)/.deps/.P + +$(srcdir)/.deps/%.P: $(srcdir)/%.c + @echo "mkdeps $< > $@" + @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \ + $(MKDEP) $< | sed "$$re" > $@-tmp + @if test -n "$o"; then \ + sed 's/\.o:/$$o:/' $@-tmp > $@; \ + rm $@-tmp; \ + else \ + mv $@-tmp $@; \ + fi + +# End of maintainer-only section +info: + +dvi: + +check: all + +installcheck: + +install-exec: + +install-data: + +install: install-exec install-data all + @: + +uninstall: + +all: $(LIBFILES) Makefile + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install +installdirs: + + +mostlyclean-generic: + test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + rm -f Makefile $(DISTCLEANFILES) + rm -f config.cache config.log $(CONFIG_HEADER) stamp-h + +maintainer-clean-generic: + test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean + +distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \ + distclean-generic clean + rm -f config.status + +maintainer-clean: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info dvi check installcheck \ +install-exec install-data install uninstall all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + +.SUFFIXES: +.SUFFIXES: .c .o + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mpi/longlong.h b/mpi/longlong.h new file mode 100644 index 000000000..006f69edd --- /dev/null +++ b/mpi/longlong.h @@ -0,0 +1,1398 @@ +/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. + +Copyright (C) 1991, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with this file; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ + +/* You have to define the following before including this file: + + UWtype -- An unsigned type, default type for operations (typically a "word") + UHWtype -- An unsigned type, at least half the size of UWtype. + UDWtype -- An unsigned type, at least twice as large a UWtype + W_TYPE_SIZE -- size in bits of UWtype + + SItype, USItype -- Signed and unsigned 32 bit types. + DItype, UDItype -- Signed and unsigned 64 bit types. + + On a 32 bit machine UWtype should typically be USItype; + on a 64 bit machine, UWtype should typically be UDItype. +*/ + +#define __BITS4 (W_TYPE_SIZE / 4) +#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) + +/* This is used to make sure no undesirable sharing between different libraries + that use this file takes place. */ +#ifndef __MPN +#define __MPN(x) __##x +#endif + +/* Define auxiliary asm macros. + + 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two + UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype + word product in HIGH_PROD and LOW_PROD. + + 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a + UDWtype product. This is just a variant of umul_ppmm. + + 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator) divides a UDWtype, composed by the UWtype integers + HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient + in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less + than DENOMINATOR for correct operation. If, in addition, the most + significant bit of DENOMINATOR must be 1, then the pre-processor symbol + UDIV_NEEDS_NORMALIZATION is defined to 1. + + 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator). Like udiv_qrnnd but the numbers are signed. The quotient + is rounded towards 0. + + 5) count_leading_zeros(count, x) counts the number of zero-bits from the + msb to the first non-zero bit in the UWtype X. This is the number of + steps X needs to be shifted left to set the msb. Undefined for X == 0, + unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value. + + 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts + from the least significant end. + + 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, + high_addend_2, low_addend_2) adds two UWtype integers, composed by + HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2 + respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow + (i.e. carry out) is not stored anywhere, and is lost. + + 8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, + high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, + composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and + LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE + and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, + and is lost. + + If any of these macros are left undefined for a particular CPU, + C macros are used. */ + +/* The CPUs come in alphabetical order below. + + Please add support for more CPUs here, or improve the current support + for the CPUs below! */ + +#if defined (__GNUC__) && !defined (NO_ASM) + +/* We sometimes need to clobber "cc" with gcc2, but that would not be + understood by gcc1. Use cpp to avoid major code duplication. */ +#if __GNUC__ < 2 +#define __CLOBBER_CC +#define __AND_CLOBBER_CC +#else /* __GNUC__ >= 2 */ +#define __CLOBBER_CC : "cc" +#define __AND_CLOBBER_CC , "cc" +#endif /* __GNUC__ < 2 */ + +#if (defined (__a29k__) || defined (_AM29K)) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add %1,%4,%5 + addc %0,%2,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub %1,%4,%5 + subc %0,%2,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "r" ((USItype)(al)), \ + "rI" ((USItype)(bl))) +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("multiplu %0,%1,%2" \ + : "=r" ((USItype)(xl)) \ + : "r" (__m0), \ + "r" (__m1)); \ + __asm__ ("multmu %0,%1,%2" \ + : "=r" ((USItype)(xh)) \ + : "r" (__m0), \ + "r" (__m1)); \ + } while (0) +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("dividu %0,%3,%4" \ + : "=r" ((USItype)(q)), \ + "=q" ((USItype)(r)) \ + : "1" ((USItype)(n1)), \ + "r" ((USItype)(n0)), \ + "r" ((USItype)(d))) +#define count_leading_zeros(count, x) \ + __asm__ ("clz %0,%1" \ + : "=r" ((USItype)(count)) \ + : "r" ((USItype)(x))) +#define COUNT_LEADING_ZEROS_0 32 +#endif /* __a29k__ */ + +#if defined (__alpha) && W_TYPE_SIZE == 64 +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + UDItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("umulh %r1,%2,%0" \ + : "=r" ((UDItype) ph) \ + : "%rJ" (__m0), \ + "rI" (__m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define UMUL_TIME 46 +#ifndef LONGLONG_STANDALONE +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { UDItype __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ + } while (0) +extern UDItype __udiv_qrnnd (); +#define UDIV_TIME 220 +#endif /* LONGLONG_STANDALONE */ +#endif /* __alpha */ + +#if defined (__arm__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("adds %1, %4, %5 + adc %0, %2, %3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subs %1, %4, %5 + sbc %0, %2, %3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "r" ((USItype)(al)), \ + "rI" ((USItype)(bl))) +#define umul_ppmm(xh, xl, a, b) \ + __asm__ ("%@ Inlined umul_ppmm + mov %|r0, %2, lsr #16 + mov %|r2, %3, lsr #16 + bic %|r1, %2, %|r0, lsl #16 + bic %|r2, %3, %|r2, lsl #16 + mul %1, %|r1, %|r2 + mul %|r2, %|r0, %|r2 + mul %|r1, %0, %|r1 + mul %0, %|r0, %0 + adds %|r1, %|r2, %|r1 + addcs %0, %0, #65536 + adds %1, %1, %|r1, lsl #16 + adc %0, %0, %|r1, lsr #16" \ + : "=&r" ((USItype)(xh)), \ + "=r" ((USItype)(xl)) \ + : "r" ((USItype)(a)), \ + "r" ((USItype)(b)) \ + : "r0", "r1", "r2") +#define UMUL_TIME 20 +#define UDIV_TIME 100 +#endif /* __arm__ */ + +#if defined (__clipper__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("mulwux %2,%0" \ + : "=r" (__xx.__ll) \ + : "%0" ((USItype)(u)), \ + "r" ((USItype)(v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define smul_ppmm(w1, w0, u, v) \ + ({union {DItype __ll; \ + struct {SItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("mulwx %2,%0" \ + : "=r" (__xx.__ll) \ + : "%0" ((SItype)(u)), \ + "r" ((SItype)(v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define __umulsidi3(u, v) \ + ({UDItype __w; \ + __asm__ ("mulwux %2,%0" \ + : "=r" (__w) \ + : "%0" ((USItype)(u)), \ + "r" ((USItype)(v))); \ + __w; }) +#endif /* __clipper__ */ + +#if defined (__gmicro__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add.w %5,%1 + addx %3,%0" \ + : "=g" ((USItype)(sh)), \ + "=&g" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub.w %5,%1 + subx %3,%0" \ + : "=g" ((USItype)(sh)), \ + "=&g" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define umul_ppmm(ph, pl, m0, m1) \ + __asm__ ("mulx %3,%0,%1" \ + : "=g" ((USItype)(ph)), \ + "=r" ((USItype)(pl)) \ + : "%0" ((USItype)(m0)), \ + "g" ((USItype)(m1))) +#define udiv_qrnnd(q, r, nh, nl, d) \ + __asm__ ("divx %4,%0,%1" \ + : "=g" ((USItype)(q)), \ + "=r" ((USItype)(r)) \ + : "1" ((USItype)(nh)), \ + "0" ((USItype)(nl)), \ + "g" ((USItype)(d))) +#define count_leading_zeros(count, x) \ + __asm__ ("bsch/1 %1,%0" \ + : "=g" (count) \ + : "g" ((USItype)(x)), \ + "0" ((USItype)0)) +#endif + +#if defined (__hppa) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add %4,%5,%1 + addc %2,%3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%rM" ((USItype)(ah)), \ + "rM" ((USItype)(bh)), \ + "%rM" ((USItype)(al)), \ + "rM" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub %4,%5,%1 + subb %2,%3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "rM" ((USItype)(ah)), \ + "rM" ((USItype)(bh)), \ + "rM" ((USItype)(al)), \ + "rM" ((USItype)(bl))) +#if defined (_PA_RISC1_1) +#define umul_ppmm(wh, wl, u, v) \ + do { \ + union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __asm__ ("xmpyu %1,%2,%0" \ + : "=*f" (__xx.__ll) \ + : "*f" ((USItype)(u)), \ + "*f" ((USItype)(v))); \ + (wh) = __xx.__i.__h; \ + (wl) = __xx.__i.__l; \ + } while (0) +#define UMUL_TIME 8 +#define UDIV_TIME 60 +#else +#define UMUL_TIME 40 +#define UDIV_TIME 80 +#endif +#ifndef LONGLONG_STANDALONE +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { USItype __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ + } while (0) +extern USItype __udiv_qrnnd (); +#endif /* LONGLONG_STANDALONE */ +#define count_leading_zeros(count, x) \ + do { \ + USItype __tmp; \ + __asm__ ( \ + "ldi 1,%0 + extru,= %1,15,16,%%r0 ; Bits 31..16 zero? + extru,tr %1,15,16,%1 ; No. Shift down, skip add. + ldo 16(%0),%0 ; Yes. Perform add. + extru,= %1,23,8,%%r0 ; Bits 15..8 zero? + extru,tr %1,23,8,%1 ; No. Shift down, skip add. + ldo 8(%0),%0 ; Yes. Perform add. + extru,= %1,27,4,%%r0 ; Bits 7..4 zero? + extru,tr %1,27,4,%1 ; No. Shift down, skip add. + ldo 4(%0),%0 ; Yes. Perform add. + extru,= %1,29,2,%%r0 ; Bits 3..2 zero? + extru,tr %1,29,2,%1 ; No. Shift down, skip add. + ldo 2(%0),%0 ; Yes. Perform add. + extru %1,30,1,%1 ; Extract bit 1. + sub %0,%1,%0 ; Subtract it. + " : "=r" (count), "=r" (__tmp) : "1" (x)); \ + } while (0) +#endif /* hppa */ + +#if (defined (__i370__) || defined (__mvs__)) && W_TYPE_SIZE == 32 +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mr %0,%3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (__m0), \ + "r" (__m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + (xh) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define smul_ppmm(xh, xl, m0, m1) \ + do { \ + union {DItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __asm__ ("mr %0,%3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (m0), \ + "r" (m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + } while (0) +#define sdiv_qrnnd(q, r, n1, n0, d) \ + do { \ + union {DItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __xx.__i.__h = n1; __xx.__i.__l = n0; \ + __asm__ ("dr %0,%2" \ + : "=r" (__xx.__ll) \ + : "0" (__xx.__ll), "r" (d)); \ + (q) = __xx.__i.__l; (r) = __xx.__i.__h; \ + } while (0) +#endif + +#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addl %5,%1 + adcl %3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subl %5,%1 + sbbl %3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mull %3" \ + : "=a" ((USItype)(w0)), \ + "=d" ((USItype)(w1)) \ + : "%0" ((USItype)(u)), \ + "rm" ((USItype)(v))) +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divl %4" \ + : "=a" ((USItype)(q)), \ + "=d" ((USItype)(r)) \ + : "0" ((USItype)(n0)), \ + "1" ((USItype)(n1)), \ + "rm" ((USItype)(d))) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("bsrl %1,%0" \ + : "=r" (__cbtmp) : "rm" ((USItype)(x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#define count_trailing_zeros(count, x) \ + __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))) +#ifndef UMUL_TIME +#define UMUL_TIME 40 +#endif +#ifndef UDIV_TIME +#define UDIV_TIME 40 +#endif +#endif /* 80x86 */ + +#if defined (__i860__) && W_TYPE_SIZE == 32 +#define rshift_rhlc(r,h,l,c) \ + __asm__ ("shr %3,r0,r0\;shrd %1,%2,%0" \ + "=r" (r) : "r" (h), "r" (l), "rn" (c)) +#endif /* i860 */ + +#if defined (__i960__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("cmpo 1,0\;addc %5,%4,%1\;addc %3,%2,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%dI" ((USItype)(ah)), \ + "dI" ((USItype)(bh)), \ + "%dI" ((USItype)(al)), \ + "dI" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("cmpo 0,0\;subc %5,%4,%1\;subc %3,%2,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "dI" ((USItype)(ah)), \ + "dI" ((USItype)(bh)), \ + "dI" ((USItype)(al)), \ + "dI" ((USItype)(bl))) +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("emul %2,%1,%0" \ + : "=d" (__xx.__ll) \ + : "%dI" ((USItype)(u)), \ + "dI" ((USItype)(v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define __umulsidi3(u, v) \ + ({UDItype __w; \ + __asm__ ("emul %2,%1,%0" \ + : "=d" (__w) \ + : "%dI" ((USItype)(u)), \ + "dI" ((USItype)(v))); \ + __w; }) +#define udiv_qrnnd(q, r, nh, nl, d) \ + do { \ + union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __nn; \ + __nn.__i.__h = (nh); __nn.__i.__l = (nl); \ + __asm__ ("ediv %d,%n,%0" \ + : "=d" (__rq.__ll) \ + : "dI" (__nn.__ll), \ + "dI" ((USItype)(d))); \ + (r) = __rq.__i.__l; (q) = __rq.__i.__h; \ + } while (0) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("scanbit %1,%0" \ + : "=r" (__cbtmp) \ + : "r" ((USItype)(x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#define COUNT_LEADING_ZEROS_0 (-32) /* sic */ +#if defined (__i960mx) /* what is the proper symbol to test??? */ +#define rshift_rhlc(r,h,l,c) \ + do { \ + union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __nn; \ + __nn.__i.__h = (h); __nn.__i.__l = (l); \ + __asm__ ("shre %2,%1,%0" \ + : "=d" (r) : "dI" (__nn.__ll), "dI" (c)); \ + } +#endif /* i960mx */ +#endif /* i960 */ + +#if (defined (__mc68000__) || defined (__mc68020__) || defined (__NeXT__) || defined(mc68020)) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add%.l %5,%1 + addx%.l %3,%0" \ + : "=d" ((USItype)(sh)), \ + "=&d" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "d" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub%.l %5,%1 + subx%.l %3,%0" \ + : "=d" ((USItype)(sh)), \ + "=&d" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "d" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#if (defined (__mc68020__) || defined (__NeXT__) || defined(mc68020)) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mulu%.l %3,%1:%0" \ + : "=d" ((USItype)(w0)), \ + "=d" ((USItype)(w1)) \ + : "%0" ((USItype)(u)), \ + "dmi" ((USItype)(v))) +#define UMUL_TIME 45 +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divu%.l %4,%1:%0" \ + : "=d" ((USItype)(q)), \ + "=d" ((USItype)(r)) \ + : "0" ((USItype)(n0)), \ + "1" ((USItype)(n1)), \ + "dmi" ((USItype)(d))) +#define UDIV_TIME 90 +#define sdiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divs%.l %4,%1:%0" \ + : "=d" ((USItype)(q)), \ + "=d" ((USItype)(r)) \ + : "0" ((USItype)(n0)), \ + "1" ((USItype)(n1)), \ + "dmi" ((USItype)(d))) +#define count_leading_zeros(count, x) \ + __asm__ ("bfffo %1{%b2:%b2},%0" \ + : "=d" ((USItype)(count)) \ + : "od" ((USItype)(x)), "n" (0)) +#define COUNT_LEADING_ZEROS_0 32 +#else /* not mc68020 */ +#define umul_ppmm(xh, xl, a, b) \ + do { USItype __umul_tmp1, __umul_tmp2; \ + __asm__ ("| Inlined umul_ppmm + move%.l %5,%3 + move%.l %2,%0 + move%.w %3,%1 + swap %3 + swap %0 + mulu %2,%1 + mulu %3,%0 + mulu %2,%3 + swap %2 + mulu %5,%2 + add%.l %3,%2 + jcc 1f + add%.l %#0x10000,%0 +1: move%.l %2,%3 + clr%.w %2 + swap %2 + swap %3 + clr%.w %3 + add%.l %3,%1 + addx%.l %2,%0 + | End inlined umul_ppmm" \ + : "=&d" ((USItype)(xh)), "=&d" ((USItype)(xl)), \ + "=d" (__umul_tmp1), "=&d" (__umul_tmp2) \ + : "%2" ((USItype)(a)), "d" ((USItype)(b))); \ + } while (0) +#define UMUL_TIME 100 +#define UDIV_TIME 400 +#endif /* not mc68020 */ +#endif /* mc68000 */ + +#if defined (__m88000__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addu.co %1,%r4,%r5 + addu.ci %0,%r2,%r3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%rJ" ((USItype)(ah)), \ + "rJ" ((USItype)(bh)), \ + "%rJ" ((USItype)(al)), \ + "rJ" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subu.co %1,%r4,%r5 + subu.ci %0,%r2,%r3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "rJ" ((USItype)(ah)), \ + "rJ" ((USItype)(bh)), \ + "rJ" ((USItype)(al)), \ + "rJ" ((USItype)(bl))) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("ff1 %0,%1" \ + : "=r" (__cbtmp) \ + : "r" ((USItype)(x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#define COUNT_LEADING_ZEROS_0 63 /* sic */ +#if defined (__m88110__) +#define umul_ppmm(wh, wl, u, v) \ + do { \ + union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __x; \ + __asm__ ("mulu.d %0,%1,%2" : "=r" (__x.__ll) : "r" (u), "r" (v)); \ + (wh) = __x.__i.__h; \ + (wl) = __x.__i.__l; \ + } while (0) +#define udiv_qrnnd(q, r, n1, n0, d) \ + ({union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __x, __q; \ + __x.__i.__h = (n1); __x.__i.__l = (n0); \ + __asm__ ("divu.d %0,%1,%2" \ + : "=r" (__q.__ll) : "r" (__x.__ll), "r" (d)); \ + (r) = (n0) - __q.__l * (d); (q) = __q.__l; }) +#define UMUL_TIME 5 +#define UDIV_TIME 25 +#else +#define UMUL_TIME 17 +#define UDIV_TIME 150 +#endif /* __m88110__ */ +#endif /* __m88000__ */ + +#if defined (__mips__) && W_TYPE_SIZE == 32 +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("multu %2,%3" \ + : "=l" ((USItype)(w0)), \ + "=h" ((USItype)(w1)) \ + : "d" ((USItype)(u)), \ + "d" ((USItype)(v))) +#else +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("multu %2,%3 + mflo %0 + mfhi %1" \ + : "=d" ((USItype)(w0)), \ + "=d" ((USItype)(w1)) \ + : "d" ((USItype)(u)), \ + "d" ((USItype)(v))) +#endif +#define UMUL_TIME 10 +#define UDIV_TIME 100 +#endif /* __mips__ */ + +#if (defined (__mips) && __mips >= 3) && W_TYPE_SIZE == 64 +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("dmultu %2,%3" \ + : "=l" ((UDItype)(w0)), \ + "=h" ((UDItype)(w1)) \ + : "d" ((UDItype)(u)), \ + "d" ((UDItype)(v))) +#else +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("dmultu %2,%3 + mflo %0 + mfhi %1" \ + : "=d" ((UDItype)(w0)), \ + "=d" ((UDItype)(w1)) \ + : "d" ((UDItype)(u)), \ + "d" ((UDItype)(v))) +#endif +#define UMUL_TIME 20 +#define UDIV_TIME 140 +#endif /* __mips__ */ + +#if defined (__ns32000__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("meid %2,%0" \ + : "=g" (__xx.__ll) \ + : "%0" ((USItype)(u)), \ + "g" ((USItype)(v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define __umulsidi3(u, v) \ + ({UDItype __w; \ + __asm__ ("meid %2,%0" \ + : "=g" (__w) \ + : "%0" ((USItype)(u)), \ + "g" ((USItype)(v))); \ + __w; }) +#define udiv_qrnnd(q, r, n1, n0, d) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ + __asm__ ("deid %2,%0" \ + : "=g" (__xx.__ll) \ + : "0" (__xx.__ll), \ + "g" ((USItype)(d))); \ + (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) +#define count_trailing_zeros(count,x) \ + do { + __asm__ ("ffsd %2,%0" \ + : "=r" ((USItype) (count)) \ + : "0" ((USItype) 0), \ + "r" ((USItype) (x))); \ + } while (0) +#endif /* __ns32000__ */ + +#if (defined (_ARCH_PPC) || defined (_IBMR2)) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + else \ + __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + } while (0) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (ah) && (ah) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (ah) && (ah) ==~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else \ + __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + } while (0) +#define count_leading_zeros(count, x) \ + __asm__ ("{cntlz|cntlzw} %0,%1" \ + : "=r" ((USItype)(count)) \ + : "r" ((USItype)(x))) +#define COUNT_LEADING_ZEROS_0 32 +#if defined (_ARCH_PPC) +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhwu %0,%1,%2" \ + : "=r" ((USItype) ph) \ + : "%r" (__m0), \ + "r" (__m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define UMUL_TIME 15 +#define smul_ppmm(ph, pl, m0, m1) \ + do { \ + SItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhw %0,%1,%2" \ + : "=r" ((SItype) ph) \ + : "%r" (__m0), \ + "r" (__m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define SMUL_TIME 14 +#define UDIV_TIME 120 +#else +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mul %0,%2,%3" \ + : "=r" ((USItype)(xh)), \ + "=q" ((USItype)(xl)) \ + : "r" (__m0), \ + "r" (__m1)); \ + (xh) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define UMUL_TIME 8 +#define smul_ppmm(xh, xl, m0, m1) \ + __asm__ ("mul %0,%2,%3" \ + : "=r" ((SItype)(xh)), \ + "=q" ((SItype)(xl)) \ + : "r" (m0), \ + "r" (m1)) +#define SMUL_TIME 4 +#define sdiv_qrnnd(q, r, nh, nl, d) \ + __asm__ ("div %0,%2,%4" \ + : "=r" ((SItype)(q)), "=q" ((SItype)(r)) \ + : "r" ((SItype)(nh)), "1" ((SItype)(nl)), "r" ((SItype)(d))) +#define UDIV_TIME 100 +#endif +#endif /* Power architecture variants. */ + +#if defined (__pyr__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addw %5,%1 + addwc %3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subw %5,%1 + subwb %3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +/* This insn works on Pyramids with AP, XP, or MI CPUs, but not with SP. */ +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __asm__ ("movw %1,%R0 + uemul %2,%0" \ + : "=&r" (__xx.__ll) \ + : "g" ((USItype) (u)), \ + "g" ((USItype)(v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#endif /* __pyr__ */ + +#if defined (__ibm032__) /* RT/ROMP */ && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("a %1,%5 + ae %0,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "r" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("s %1,%5 + se %0,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "r" ((USItype)(bl))) +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ( \ + "s r2,r2 + mts r10,%2 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + cas %0,r2,r0 + mfs r10,%1" \ + : "=r" ((USItype)(ph)), \ + "=r" ((USItype)(pl)) \ + : "%r" (__m0), \ + "r" (__m1) \ + : "r2"); \ + (ph) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define UMUL_TIME 20 +#define UDIV_TIME 200 +#define count_leading_zeros(count, x) \ + do { \ + if ((x) >= 0x10000) \ + __asm__ ("clz %0,%1" \ + : "=r" ((USItype)(count)) \ + : "r" ((USItype)(x) >> 16)); \ + else \ + { \ + __asm__ ("clz %0,%1" \ + : "=r" ((USItype)(count)) \ + : "r" ((USItype)(x))); \ + (count) += 16; \ + } \ + } while (0) +#endif /* RT/ROMP */ + +#if defined (__sh2__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ( \ + "dmulu.l %2,%3 + sts macl,%1 + sts mach,%0" \ + : "=r" ((USItype)(w1)), \ + "=r" ((USItype)(w0)) \ + : "r" ((USItype)(u)), \ + "r" ((USItype)(v)) \ + : "macl", "mach") +#define UMUL_TIME 5 +#endif + +#if defined (__sparc__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addcc %r4,%5,%1 + addx %r2,%3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%rJ" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "%rJ" ((USItype)(al)), \ + "rI" ((USItype)(bl)) \ + __CLOBBER_CC) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subcc %r4,%5,%1 + subx %r2,%3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "rJ" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "rJ" ((USItype)(al)), \ + "rI" ((USItype)(bl)) \ + __CLOBBER_CC) +#if defined (__sparc_v8__) +/* Don't match immediate range because, 1) it is not often useful, + 2) the 'I' flag thinks of the range as a 13 bit signed interval, + while we want to match a 13 bit interval, sign extended to 32 bits, + but INTERPRETED AS UNSIGNED. */ +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("umul %2,%3,%1;rd %%y,%0" \ + : "=r" ((USItype)(w1)), \ + "=r" ((USItype)(w0)) \ + : "r" ((USItype)(u)), \ + "r" ((USItype)(v))) +#define UMUL_TIME 5 +#ifndef SUPERSPARC /* SuperSPARC's udiv only handles 53 bit dividends */ +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { \ + USItype __q; \ + __asm__ ("mov %1,%%y;nop;nop;nop;udiv %2,%3,%0" \ + : "=r" ((USItype)(__q)) \ + : "r" ((USItype)(n1)), \ + "r" ((USItype)(n0)), \ + "r" ((USItype)(d))); \ + (r) = (n0) - __q * (d); \ + (q) = __q; \ + } while (0) +#define UDIV_TIME 25 +#endif /* SUPERSPARC */ +#else /* ! __sparc_v8__ */ +#if defined (__sparclite__) +/* This has hardware multiply but not divide. It also has two additional + instructions scan (ffs from high bit) and divscc. */ +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("umul %2,%3,%1;rd %%y,%0" \ + : "=r" ((USItype)(w1)), \ + "=r" ((USItype)(w0)) \ + : "r" ((USItype)(u)), \ + "r" ((USItype)(v))) +#define UMUL_TIME 5 +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("! Inlined udiv_qrnnd + wr %%g0,%2,%%y ! Not a delayed write for sparclite + tst %%g0 + divscc %3,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%0 + rd %%y,%1 + bl,a 1f + add %1,%4,%1 +1: ! End of inline udiv_qrnnd" \ + : "=r" ((USItype)(q)), \ + "=r" ((USItype)(r)) \ + : "r" ((USItype)(n1)), \ + "r" ((USItype)(n0)), \ + "rI" ((USItype)(d)) \ + : "%g1" __AND_CLOBBER_CC) +#define UDIV_TIME 37 +#define count_leading_zeros(count, x) \ + __asm__ ("scan %1,0,%0" \ + : "=r" ((USItype)(x)) \ + : "r" ((USItype)(count))) +/* Early sparclites return 63 for an argument of 0, but they warn that future + implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0 + undefined. */ +#endif /* __sparclite__ */ +#endif /* __sparc_v8__ */ +/* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd. */ +#ifndef umul_ppmm +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("! Inlined umul_ppmm + wr %%g0,%2,%%y ! SPARC has 0-3 delay insn after a wr + sra %3,31,%%g2 ! Don't move this insn + and %2,%%g2,%%g2 ! Don't move this insn + andcc %%g0,0,%%g1 ! Don't move this insn + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,0,%%g1 + add %%g1,%%g2,%0 + rd %%y,%1" \ + : "=r" ((USItype)(w1)), \ + "=r" ((USItype)(w0)) \ + : "%rI" ((USItype)(u)), \ + "r" ((USItype)(v)) \ + : "%g1", "%g2" __AND_CLOBBER_CC) +#define UMUL_TIME 39 /* 39 instructions */ +#endif +#ifndef udiv_qrnnd +#ifndef LONGLONG_STANDALONE +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { USItype __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ + } while (0) +extern USItype __udiv_qrnnd (); +#define UDIV_TIME 140 +#endif /* LONGLONG_STANDALONE */ +#endif /* udiv_qrnnd */ +#endif /* __sparc__ */ + +#if defined (__vax__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addl2 %5,%1 + adwc %3,%0" \ + : "=g" ((USItype)(sh)), \ + "=&g" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subl2 %5,%1 + sbwc %3,%0" \ + : "=g" ((USItype)(sh)), \ + "=&g" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("emul %1,%2,$0,%0" \ + : "=g" (__xx.__ll) \ + : "g" (__m0), \ + "g" (__m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + (xh) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define sdiv_qrnnd(q, r, n1, n0, d) \ + do { \ + union {DItype __ll; \ + struct {SItype __l, __h;} __i; \ + } __xx; \ + __xx.__i.__h = n1; __xx.__i.__l = n0; \ + __asm__ ("ediv %3,%2,%0,%1" \ + : "=g" (q), "=g" (r) \ + : "g" (__xx.__ll), "g" (d)); \ + } while (0) +#endif /* __vax__ */ + +#if defined (__z8000__) && W_TYPE_SIZE == 16 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add %H1,%H5\n\tadc %H0,%H3" \ + : "=r" ((unsigned int)(sh)), \ + "=&r" ((unsigned int)(sl)) \ + : "%0" ((unsigned int)(ah)), \ + "r" ((unsigned int)(bh)), \ + "%1" ((unsigned int)(al)), \ + "rQR" ((unsigned int)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub %H1,%H5\n\tsbc %H0,%H3" \ + : "=r" ((unsigned int)(sh)), \ + "=&r" ((unsigned int)(sl)) \ + : "0" ((unsigned int)(ah)), \ + "r" ((unsigned int)(bh)), \ + "1" ((unsigned int)(al)), \ + "rQR" ((unsigned int)(bl))) +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union {long int __ll; \ + struct {unsigned int __h, __l;} __i; \ + } __xx; \ + unsigned int __m0 = (m0), __m1 = (m1); \ + __asm__ ("mult %S0,%H3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (__m0), \ + "rQR" (__m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + (xh) += ((((signed int) __m0 >> 15) & __m1) \ + + (((signed int) __m1 >> 15) & __m0)); \ + } while (0) +#endif /* __z8000__ */ + +#endif /* __GNUC__ */ + + +#if !defined (umul_ppmm) && defined (__umulsidi3) +#define umul_ppmm(ph, pl, m0, m1) \ + { \ + UDWtype __ll = __umulsidi3 (m0, m1); \ + ph = (UWtype) (__ll >> W_TYPE_SIZE); \ + pl = (UWtype) __ll; \ + } +#endif + +#if !defined (__umulsidi3) +#define __umulsidi3(u, v) \ + ({UWtype __hi, __lo; \ + umul_ppmm (__hi, __lo, u, v); \ + ((UDWtype) __hi << W_TYPE_SIZE) | __lo; }) +#endif + +/* If this machine has no inline assembler, use C macros. */ + +#if !defined (add_ssaaaa) +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) + (bl); \ + (sh) = (ah) + (bh) + (__x < (al)); \ + (sl) = __x; \ + } while (0) +#endif + +#if !defined (sub_ddmmss) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) - (bl); \ + (sh) = (ah) - (bh) - (__x > (al)); \ + (sl) = __x; \ + } while (0) +#endif + +#if !defined (umul_ppmm) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + UWtype __x0, __x1, __x2, __x3; \ + UHWtype __ul, __vl, __uh, __vh; \ + UWtype __u = (u), __v = (v); \ + \ + __ul = __ll_lowpart (__u); \ + __uh = __ll_highpart (__u); \ + __vl = __ll_lowpart (__v); \ + __vh = __ll_highpart (__v); \ + \ + __x0 = (UWtype) __ul * __vl; \ + __x1 = (UWtype) __ul * __vh; \ + __x2 = (UWtype) __uh * __vl; \ + __x3 = (UWtype) __uh * __vh; \ + \ + __x1 += __ll_highpart (__x0);/* this can't give carry */ \ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += __ll_B; /* yes, add it in the proper pos. */ \ + \ + (w1) = __x3 + __ll_highpart (__x1); \ + (w0) = (__ll_lowpart (__x1) << W_TYPE_SIZE/2) + __ll_lowpart (__x0);\ + } while (0) +#endif + +#if !defined (umul_ppmm) +#define smul_ppmm(w1, w0, u, v) \ + do { \ + UWtype __w1; \ + UWtype __m0 = (u), __m1 = (v); \ + umul_ppmm (__w1, w0, __m0, __m1); \ + (w1) = __w1 - (-(__m0 >> (W_TYPE_SIZE - 1)) & __m1) \ + - (-(__m1 >> (W_TYPE_SIZE - 1)) & __m0); \ + } while (0) +#endif + +/* Define this unconditionally, so it can be used for debugging. */ +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (UWtype) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through + __udiv_w_sdiv (defined in libgcc or elsewhere). */ +#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd) +#define udiv_qrnnd(q, r, nh, nl, d) \ + do { \ + UWtype __r; \ + (q) = __MPN(udiv_w_sdiv) (&__r, nh, nl, d); \ + (r) = __r; \ + } while (0) +#endif + +/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ +#if !defined (udiv_qrnnd) +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c +#endif + +#if !defined (count_leading_zeros) +extern +#ifdef __STDC__ +const +#endif +unsigned char __clz_tab[]; +#define count_leading_zeros(count, x) \ + do { \ + UWtype __xr = (x); \ + UWtype __a; \ + \ + if (W_TYPE_SIZE <= 32) \ + { \ + __a = __xr < ((UWtype) 1 << 2*__BITS4) \ + ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \ + : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 : 3*__BITS4);\ + } \ + else \ + { \ + for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ + if (((__xr >> __a) & 0xff) != 0) \ + break; \ + } \ + \ + (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ + } while (0) +/* This version gives a well-defined value for zero. */ +#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE +#endif + +#if !defined (count_trailing_zeros) +/* Define count_trailing_zeros using count_leading_zeros. The latter might be + defined in asm, but if it is not, the C version above is good enough. */ +#define count_trailing_zeros(count, x) \ + do { \ + UWtype __ctz_x = (x); \ + UWtype __ctz_c; \ + count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \ + (count) = W_TYPE_SIZE - 1 - __ctz_c; \ + } while (0) +#endif + +#ifndef UDIV_NEEDS_NORMALIZATION +#define UDIV_NEEDS_NORMALIZATION 0 +#endif diff --git a/mpi/mpi-add.c b/mpi/mpi-add.c new file mode 100644 index 000000000..047a2fa35 --- /dev/null +++ b/mpi/mpi-add.c @@ -0,0 +1,221 @@ +/* mpi-add.c - MPI functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> + +#include "mpi-internal.h" + + +/**************** + * Add the unsigned integer V to the mpi-integer U and store the + * result in W. U and V may be the same. + */ +void +mpi_add_ui(MPI w, MPI u, unsigned long v ) +{ + mpi_ptr_t wp, up; + mpi_size_t usize, wsize; + int usign, wsign; + + usize = u->nlimbs; + usign = u->sign; + wsign = 0; + + /* If not space for W (and possible carry), increase space. */ + wsize = usize + 1; + if( w->alloced < wsize ) + mpi_resize(w, wsize); + + /* These must be after realloc (U may be the same as W). */ + up = u->d; + wp = w->d; + + if( !usize ) { /* simple */ + wp[0] = v; + wsize = v? 1:0; + } + else if( !usign ) { /* mpi is not negative */ + mpi_limb_t cy; + cy = mpihelp_add_1(wp, up, usize, v); + wp[usize] = cy; + wsize = usize + cy; + } + else { /* The signs are different. Need exact comparison to determine + * which operand to subtract from which. */ + if( usize == 1 && up[0] < v ) { + wp[0] = v - up[0]; + wsize = 1; + } + else { + mpihelp_sub_1(wp, up, usize, v); + /* Size can decrease with at most one limb. */ + wsize = (usize - (wp[usize-1]? 0:1)); + wsign = 1; + } + } + + w->nlimbs = wsize; + w->sign = wsign; +} + + +void +mpi_add(MPI w, MPI u, MPI v) +{ + mpi_ptr_t wp, up, vp; + mpi_size_t usize, vsize, wsize; + int usign, vsign, wsign; + + usize = u->nlimbs; + vsize = v->nlimbs; + usign = u->sign; + vsign = v->sign; + + if( usize < vsize ) { /* Swap U and V. */ + { MPI t; t = u; u = v; v = t; } + { mpi_size_t t = usize; usize = vsize; vsize = t; } + { int t = usign; usign = vsign; vsign = t; } + } + + /* If not space for w (and possible carry), increase space. */ + wsize = usize + 1; + if( w->alloced < wsize ) + mpi_resize(w, wsize); + wsign = 0; + + /* These must be after realloc (u or v may be the same as w). */ + up = u->d; + vp = v->d; + wp = w->d; + + if( !vsize ) { /* simple */ + MPN_COPY(wp, up, usize ); + wsize = usize; + wsign = usign; + } + else if( usign != vsign ) { /* different sign */ + /* This test is right since USIZE >= VSIZE */ + if( usize != vsize ) { + mpihelp_sub(wp, up, usize, vp, vsize); + wsize = usize; + MPN_NORMALIZE(wp, wsize); + wsign = usign; + } + else if( mpihelp_cmp(up, vp, usize) < 0 ) { + mpihelp_sub_n(wp, vp, up, usize); + wsize = usize; + MPN_NORMALIZE(wp, wsize); + if( !usign ) + wsign = 1; + } + else { + mpihelp_sub_n(wp, up, vp, usize); + wsize = usize; + MPN_NORMALIZE(wp, wsize); + if( usign ) + wsign = 1; + } + } + else { /* U and V have same sign. Add them. */ + mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize); + wp[usize] = cy; + wsize = usize + cy; + if( usign ) + wsize = 1; + } + + w->nlimbs = wsize; + w->sign = wsign; +} + + +/**************** + * Subtract the unsigned integer V from the mpi-integer U and store the + * result in W. + */ +void +mpi_sub_ui(MPI w, MPI u, unsigned long v ) +{ + mpi_ptr_t wp, up; + mpi_size_t usize, wsize; + int usign, wsign; + + usize = u->nlimbs; + usign = u->sign; + wsign = 0; + + /* If not space for W (and possible carry), increase space. */ + wsize = usize + 1; + if( w->alloced < wsize ) + mpi_resize(w, wsize); + + /* These must be after realloc (U may be the same as W). */ + up = u->d; + wp = w->d; + + if( !usize ) { /* simple */ + wp[0] = v; + wsize = v? 1:0; + wsign = 1; + } + else if( usign ) { /* mpi and v are negative */ + mpi_limb_t cy; + cy = mpihelp_add_1(wp, up, usize, v); + wp[usize] = cy; + wsize = usize + cy; + } + else { /* The signs are different. Need exact comparison to determine + * which operand to subtract from which. */ + if( usize == 1 && up[0] < v ) { + wp[0] = v - up[0]; + wsize = 1; + wsign = 1; + } + else { + mpihelp_sub_1(wp, up, usize, v); + /* Size can decrease with at most one limb. */ + wsize = (usize - (wp[usize-1]? 1:0)); + } + } + + w->nlimbs = wsize; + w->sign = wsign; +} + +void +mpi_sub(MPI w, MPI u, MPI v) +{ + if( w == v ) { + MPI vv = mpi_copy(v); + vv->sign = !vv->sign; + mpi_add( w, u, vv ); + m_free(vv); + } + else { + /* fixme: this is not thread-save (we temp. modify v) */ + v->sign = !v->sign; + mpi_add( w, u, v ); + v->sign = !v->sign; + } +} + + diff --git a/mpi/mpi-bit.c b/mpi/mpi-bit.c new file mode 100644 index 000000000..9cb346aa4 --- /dev/null +++ b/mpi/mpi-bit.c @@ -0,0 +1,133 @@ +/* mpi-bit.c - MPI bit level fucntions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include "mpi-internal.h" + + +/**************** + * Return the number of bits in A. + * fixme: we should not count leading zero bits + */ +unsigned +mpi_get_nbits( MPI a ) +{ + return a->nlimbs * BITS_PER_MPI_LIMB; +} + + +/**************** + * Test wether bit N is set. + */ +int +mpi_test_bit( MPI a, unsigned n ) +{ + unsigned limbno, bitno; + mpi_limb_t limb; + + limbno = n / BITS_PER_MPI_LIMB; + bitno = n % BITS_PER_MPI_LIMB; + + if( limbno >= a->nlimbs ) + return 0; /* too far left: this is a 0 */ + limb = a->d[limbno]; + return (limb & (1 << bitno))? 1: 0; +} + + +/**************** + * Set bit N of A. + */ +void +mpi_set_bit( MPI a, unsigned n ) +{ + unsigned limbno, bitno; + + limbno = n / BITS_PER_MPI_LIMB; + bitno = n % BITS_PER_MPI_LIMB; + + if( limbno >= a->nlimbs ) { /* resize */ + if( a->alloced >= limbno ) + mpi_resize(a, limbno+1 ); + a->nlimbs = limbno+1; + } + a->d[limbno] |= (1<<bitno); +} + +/**************** + * Clear bit N of A. + */ +void +mpi_clear_bit( MPI a, unsigned n ) +{ + unsigned limbno, bitno; + + limbno = n / BITS_PER_MPI_LIMB; + bitno = n % BITS_PER_MPI_LIMB; + + if( limbno >= a->nlimbs ) + return; /* don't need to clear this bit, it's to far to left */ + a->d[limbno] &= ~(1 << bitno); +} + + +void +mpi_set_bytes( MPI a, unsigned nbits, byte (*fnc)(int), int opaque ) +{ + byte *p; + unsigned nlimbs, nlimbs2, xbits, xbytes; + unsigned n; + int i; + + nlimbs = nbits / BITS_PER_MPI_LIMB; + xbits = nbits % BITS_PER_MPI_LIMB; + nlimbs2 = xbits? (nlimbs+1):nlimbs; + xbytes = xbits / 8; + xbits = xbits % 8; + if( a->alloced < nlimbs2 ) + mpi_resize(a, nlimbs2 ); + a->nlimbs = nlimbs2; + for(n=0; n < nlimbs; n++ ) { + p = (byte*)(a->d+n); + #ifdef HAVE_LITTLE_ENDIAN + for(i=0; i < BYTES_PER_MPI_LIMB; i++ ) + p[i] = fnc(opaque); + #else + for(i=BYTES_PER_MPI_LIMB-1; i>=0; i-- ) + p[i] = fnc(opaque); + #endif + } + if( xbytes ) { + p = (byte*)(a->d+n); + #ifdef HAVE_LITTLE_ENDIAN + for(i=0; i < xbytes; i++ ) + p[i] = fnc(opaque); + #else + for(i=xbytes-1; i>=0; i-- ) + p[i] = fnc(opaque); + #endif + } + assert(!xbits); +} + + diff --git a/mpi/mpi-cmp.c b/mpi/mpi-cmp.c new file mode 100644 index 000000000..83e85ceb0 --- /dev/null +++ b/mpi/mpi-cmp.c @@ -0,0 +1,72 @@ +/* mpi-cmp.c - MPI functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi-internal.h" + +int +mpi_cmp_ui( MPI u, unsigned long v ) +{ + mpi_limb_t limb = v; + + if( !u->nlimbs && !limb ) + return 0; + if( u->sign ) + return -1; + if( u->nlimbs > 1 ) + return 1; + + if( u->d[0] == limb ) + return 0; + else if( u->d[0] > limb ) + return 1; + else + return -1; +} + +int +mpi_cmp( MPI u, MPI v ) +{ + mpi_size_t usize = u->nlimbs; + mpi_size_t vsize = v->nlimbs; + int cmp; + + /* FIXME: are the numbers always normalized? */ + if( !u->sign && v->sign ) + return 1; + else if( u->sign && !v->sign ) + return -1; + else if( usize != vsize && !u->sign && !v->sign ) + return usize - vsize; + else if( usize != vsize && u->sign && v->sign ) + return vsize + usize; + else if( !usize ) + return 0; + else if( !(cmp=mpihelp_cmp( u->d, v->d, usize )) ) + return 0; + else if( (cmp < 0?1:0) == (u->sign?1:0)) + return 1; + else + return -1; +} + + diff --git a/mpi/mpi-div.c b/mpi/mpi-div.c new file mode 100644 index 000000000..2955575a8 --- /dev/null +++ b/mpi/mpi-div.c @@ -0,0 +1,282 @@ +/* mpi-div.c - MPI functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi-internal.h" +#include "longlong.h" + + + +void +mpi_fdiv_r( MPI rem, MPI dividend, MPI divisor ) +{ + int divisor_sign = divisor->sign; + MPI temp_divisor = NULL; + + /* We need the original value of the divisor after the remainder has been + * preliminary calculated. We have to copy it to temporary space if it's + * the same variable as REM. */ + if( rem == divisor ) { + temp_divisor = mpi_copy( divisor ); + divisor = temp_divisor; + } + + mpi_tdiv_r( rem, dividend, divisor ); + + if( ((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs ) + mpi_add( rem, rem, divisor); + + if( temp_divisor ) + mpi_free(temp_divisor); +} + + + +/**************** + * Division rounding the quotient towards -infinity. + * The remainder gets the same sign as the denominator. + * rem is optional + */ + +ulong +mpi_fdiv_r_ui( MPI rem, MPI dividend, ulong divisor ) +{ + mpi_limb_t rlimb; + + rlimb = mpihelp_mod_1( dividend->d, dividend->nlimbs, divisor ); + if( rlimb && dividend->sign ) + rlimb = divisor - rlimb; + + if( rem ) { + rem->d[0] = rlimb; + rem->nlimbs = rlimb? 1:0; + } + return rlimb; +} + + +void +mpi_fdiv_q( MPI quot, MPI dividend, MPI divisor ) +{ + MPI tmp = mpi_alloc( mpi_get_nlimbs(quot) ); + mpi_fdiv_qr( quot, tmp, dividend, divisor); + mpi_free(tmp); +} + +void +mpi_fdiv_qr( MPI quot, MPI rem, MPI dividend, MPI divisor ) +{ + int divisor_sign = divisor->sign; + MPI temp_divisor = NULL; + + if( quot == divisor || rem == divisor ) { + temp_divisor = mpi_copy( divisor ); + divisor = temp_divisor; + } + + mpi_tdiv_qr( quot, rem, dividend, divisor ); + + if( (divisor_sign ^ dividend->sign) && rem->nlimbs ) { + mpi_sub_ui( quot, quot, 1 ); + mpi_add( rem, rem, divisor); + } + + if( temp_divisor ) + mpi_free(temp_divisor); +} + + +/* If den == quot, den needs temporary storage. + * If den == rem, den needs temporary storage. + * If num == quot, num needs temporary storage. + * If den has temporary storage, it can be normalized while being copied, + * i.e no extra storage should be allocated. + */ + +void +mpi_tdiv_r( MPI rem, MPI num, MPI den) +{ + mpi_tdiv_qr(NULL, rem, num, den ); +} + +void +mpi_tdiv_qr( MPI quot, MPI rem, MPI num, MPI den) +{ + mpi_ptr_t np, dp; + mpi_ptr_t qp, rp; + mpi_size_t nsize = num->nlimbs; + mpi_size_t dsize = den->nlimbs; + mpi_size_t qsize, rsize; + mpi_size_t sign_remainder = num->sign; + mpi_size_t sign_quotient = num->sign ^ den->sign; + unsigned normalization_steps; + mpi_limb_t q_limb; + mpi_ptr_t marker[5]; + int markidx=0; + + /* Ensure space is enough for quotient and remainder. + * We need space for an extra limb in the remainder, because it's + * up-shifted (normalized) below. */ + rsize = nsize + 1; + if( rem->alloced < rsize ) + mpi_resize( rem, rsize); + + qsize = rsize - dsize; /* qsize cannot be bigger than this. */ + if( qsize <= 0 ) { + if( num != rem ) { + rem->nlimbs = num->nlimbs; + rem->sign = num->sign; + MPN_COPY(rem->d, num->d, nsize); + } + if( quot ) { + /* This needs to follow the assignment to rem, in case the + * numerator and quotient are the same. */ + quot->nlimbs = 0; + quot->sign = 0; + } + return; + } + + if( quot && quot->alloced < qsize ) + mpi_resize( quot, qsize); + + /* Read pointers here, when reallocation is finished. */ + np = num->d; + dp = den->d; + rp = rem->d; + + /* Optimize division by a single-limb divisor. */ + if( dsize == 1 ) { + mpi_limb_t rlimb; + if( quot ) { + qp = quot->d; + rlimb = mpihelp_divmod_1( qp, np, nsize, dp[0] ); + qsize -= qp[qsize - 1] == 0; + quot->nlimbs = qsize; + quot->sign = sign_quotient; + } + else + rlimb = mpihelp_mod_1( np, nsize, dp[0] ); + rp[0] = rlimb; + rsize = rlimb != 0?1:0; + rem->nlimbs = rsize; + rem->sign = sign_remainder; + return; + } + + + if( quot ) { + qp = quot->d; + /* Make sure QP and NP point to different objects. Otherwise the + * numerator would be gradually overwritten by the quotient limbs. */ + if(qp == np) { /* Copy NP object to temporary space. */ + np = marker[markidx++] = mpi_alloc_limb_space(nsize); + MPN_COPY(np, qp, nsize); + } + } + else /* Put quotient at top of remainder. */ + qp = rp + dsize; + + count_leading_zeros( normalization_steps, dp[dsize - 1] ); + + /* Normalize the denominator, i.e. make its most significant bit set by + * shifting it NORMALIZATION_STEPS bits to the left. Also shift the + * numerator the same number of steps (to keep the quotient the same!). + */ + if( normalization_steps ) { + mpi_ptr_t tp; + mpi_limb_t nlimb; + + /* Shift up the denominator setting the most significant bit of + * the most significant word. Use temporary storage not to clobber + * the original contents of the denominator. */ + tp = marker[markidx++] = mpi_alloc_limb_space(dsize); + mpihelp_lshift( tp, dp, dsize, normalization_steps ); + dp = tp; + + /* Shift up the numerator, possibly introducing a new most + * significant word. Move the shifted numerator in the remainder + * meanwhile. */ + nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps); + if( nlimb ) { + rp[nsize] = nlimb; + rsize = nsize + 1; + } + else + rsize = nsize; + } + else { + /* The denominator is already normalized, as required. Copy it to + * temporary space if it overlaps with the quotient or remainder. */ + if( dp == rp || (quot && (dp == qp))) { + mpi_ptr_t tp; + + tp = marker[markidx++] = mpi_alloc_limb_space(dsize); + MPN_COPY( tp, dp, dsize ); + dp = tp; + } + + /* Move the numerator to the remainder. */ + if( rp != np ) + MPN_COPY(rp, np, nsize); + + rsize = nsize; + } + + q_limb = mpihelp_divrem( qp, 0, rp, rsize, dp, dsize ); + + if( quot ) { + qsize = rsize - dsize; + if(q_limb) { + qp[qsize] = q_limb; + qsize += 1; + } + + quot->nlimbs = qsize; + quot->sign = sign_quotient; + } + + rsize = dsize; + MPN_NORMALIZE (rp, rsize); + + if( normalization_steps && rsize ) { + mpihelp_rshift(rp, rp, rsize, normalization_steps); + rsize -= rp[rsize - 1] == 0?1:0; + } + + rem->nlimbs = rsize; + rem->sign = sign_remainder; + while( markidx ) + mpi_free_limb_space(marker[--markidx]); +} + + +/**************** + * Check wether dividend is divisible by divisor + * (note: divisor must fit into a limb) + */ +int +mpi_divisible_ui(MPI dividend, ulong divisor ) +{ + return !mpihelp_mod_1( dividend->d, dividend->nlimbs, divisor ); +} + diff --git a/mpi/mpi-gcd.c b/mpi/mpi-gcd.c new file mode 100644 index 000000000..f31e917f6 --- /dev/null +++ b/mpi/mpi-gcd.c @@ -0,0 +1,54 @@ +/* mpi-gcd.c - MPI functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi-internal.h" + +/**************** + * Find the greatest common divisor G of A and B. + * Return: true if this 1, false in all other cases + */ +int +mpi_gcd( MPI g, MPI xa, MPI xb ) +{ + MPI a, b; + + a = mpi_copy(xa); + b = mpi_copy(xb); + + /* TAOCP Vol II, 4.5.2, Algorithm A */ + a->sign = 0; + b->sign = 0; + while( mpi_cmp_ui( b, 0 ) ) { + mpi_fdiv_r( g, a, b ); /* g used as temorary variable */ + mpi_set(a,b); + mpi_set(b,g); + } + mpi_set(g, a); + + mpi_free(a); + mpi_free(b); + return !mpi_cmp_ui( g, 1); +} + + + diff --git a/mpi/mpi-internal.h b/mpi/mpi-internal.h new file mode 100644 index 000000000..b5c00b6c4 --- /dev/null +++ b/mpi/mpi-internal.h @@ -0,0 +1,198 @@ +/* mpi-internal.h - Internal to the Multi Precision Integers + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef G10_MPI_INTERNAL_H +#define G10_MPI_INTERNAL_H + +#include "mpi.h" + + + +typedef mpi_limb_t *mpi_ptr_t; /* pointer to a limb */ +typedef int mpi_size_t; /* (must be a signed type) */ + +#define ABS(x) (x >= 0 ? x : -x) +#define MIN(l,o) ((l) < (o) ? (l) : (o)) +#define MAX(h,i) ((h) > (i) ? (h) : (i)) +#define RESIZE_IF_NEEDED(a,b) \ + do { \ + if( (a)->alloced < (b) ) \ + mpi_resize((a), (b)); \ + } while(0) + +/* Copy N limbs from S to D. */ +#define MPN_COPY( d, s, n) \ + do { \ + mpi_size_t _i; \ + for( _i = 0; _i < (n); _i++ ) \ + (d)[_i] = (s)[_i]; \ + } while(0) + +#define MPN_COPY_DECR( d, s, n ) \ + do { \ + mpi_size_t _i; \ + for( _i = (n)-1; _i >= 0; _i--) \ + (d)[_i] = (s)[_i]; \ + } while(0) + +/* Zero N limbs at D */ +#define MPN_ZERO(d, n) \ + do { \ + int _i; \ + for( _i = 0; _i < (n); _i++ ) \ + (d)[_i] = 0; \ + } while (0) + +#define MPN_NORMALIZE(d, n) \ + do { \ + while( (n) > 0 ) { \ + if( (d)[(n)-1] ) \ + break; \ + (n)--; \ + } \ + } while(0) + +#define MPN_NORMALIZE_NOT_ZERO(d, n) \ + do { \ + for(;;) { \ + if( (d)[(n)-1] ) \ + break; \ + (n)--; \ + } \ + } while(0) + +#define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace) \ + do { \ + if( (size) < KARATSUBA_THRESHOLD ) \ + mul_n_basecase (prodp, up, vp, size); \ + else \ + mul_n (prodp, up, vp, size, tspace); \ + } while (0); + + +/* Divide the two-limb number in (NH,,NL) by D, with DI being the largest + * limb not larger than (2**(2*BITS_PER_MP_LIMB))/D - (2**BITS_PER_MP_LIMB). + * If this would yield overflow, DI should be the largest possible number + * (i.e., only ones). For correct operation, the most significant bit of D + * has to be set. Put the quotient in Q and the remainder in R. + */ +#define UDIV_QRNND_PREINV(q, r, nh, nl, d, di) \ + do { \ + mpi_limb_t _q, _ql, _r; \ + mpi_limb_t _xh, _xl; \ + umul_ppmm (_q, _ql, (nh), (di)); \ + _q += (nh); /* DI is 2**BITS_PER_MPI_LIMB too small */ \ + umul_ppmm (_xh, _xl, _q, (d)); \ + sub_ddmmss (_xh, _r, (nh), (nl), _xh, _xl); \ + if( _xh ) { \ + sub_ddmmss (_xh, _r, _xh, _r, 0, (d)); \ + _q++; \ + if( _xh) { \ + sub_ddmmss (_xh, _r, _xh, _r, 0, (d)); \ + _q++; \ + } \ + } \ + if( _r >= (d) ) { \ + _r -= (d); \ + _q++; \ + } \ + (r) = _r; \ + (q) = _q; \ + } while (0) + + +/*-- mpiutil.c --*/ +#ifdef M_DEBUG + #define mpi_alloc_limb_space(n) mpi_debug_alloc_limb_space((n), M_DBGINFO( __LINE__ ) ) + #define mpi_free_limb_space(n) mpi_debug_free_limb_space((n), M_DBGINFO( __LINE__ ) ) + mpi_ptr_t mpi_debug_alloc_limb_space( unsigned nlimbs, const char *info ); + void mpi_debug_free_limb_space( mpi_ptr_t a, const char *info ); +#else + mpi_ptr_t mpi_alloc_limb_space( unsigned nlimbs ); + void mpi_free_limb_space( mpi_ptr_t a ); +#endif +void mpi_assign_limb_space( MPI a, mpi_ptr_t ap, unsigned nlimbs ); + +/*-- mpihelp-add.c --*/ +mpi_limb_t mpihelp_add_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb ); +mpi_limb_t mpihelp_add_n( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_ptr_t s2_ptr, mpi_size_t size); +mpi_limb_t mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, + mpi_ptr_t s2_ptr, mpi_size_t s2_size); + +/*-- mpihelp-sub.c --*/ +mpi_limb_t mpihelp_sub_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb ); +mpi_limb_t mpihelp_sub_n( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_ptr_t s2_ptr, mpi_size_t size); +mpi_limb_t mpihelp_sub(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, + mpi_ptr_t s2_ptr, mpi_size_t s2_size); + +/*-- mpihelp-cmp.c --*/ +int mpihelp_cmp( mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size ); + +/*-- mpihelp-mul.c --*/ +mpi_limb_t mpihelp_addmul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb); +mpi_limb_t mpihelp_submul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb); +mpi_limb_t mpihelp_mul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb); +void mpihelp_mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, + mpi_size_t size); +mpi_limb_t mpihelp_mul( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize, + mpi_ptr_t vp, mpi_size_t vsize); + +/*-- mpihelp-div.c --*/ +mpi_limb_t mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, + mpi_limb_t divisor_limb); +mpi_limb_t mpihelp_divrem( mpi_ptr_t qp, mpi_size_t qextra_limbs, + mpi_ptr_t np, mpi_size_t nsize, + mpi_ptr_t dp, mpi_size_t dsize); +mpi_limb_t mpihelp_divmod_1( mpi_ptr_t quot_ptr, + mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, + mpi_limb_t divisor_limb); + +/*-- mpihelp-shift.c --*/ +mpi_limb_t mpihelp_lshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, + unsigned cnt); +mpi_limb_t mpihelp_rshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, + unsigned cnt); + + +/* Define stuff for longlong.h. */ +#define W_TYPE_SIZE BITS_PER_MPI_LIMB + typedef mpi_limb_t UWtype; + typedef unsigned int UHWtype; +#if defined (__GNUC__) + typedef unsigned int UQItype __attribute__ ((mode (QI))); + typedef int SItype __attribute__ ((mode (SI))); + typedef unsigned int USItype __attribute__ ((mode (SI))); + typedef int DItype __attribute__ ((mode (DI))); + typedef unsigned int UDItype __attribute__ ((mode (DI))); +#else + typedef unsigned char UQItype; + typedef long SItype; + typedef unsigned long USItype; +#endif + + +#endif /*G10_MPI_INTERNAL_H*/ diff --git a/mpi/mpi-inv.c b/mpi/mpi-inv.c new file mode 100644 index 000000000..acde6055a --- /dev/null +++ b/mpi/mpi-inv.c @@ -0,0 +1,127 @@ +/* mpi-inv.c - MPI functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi-internal.h" + +/**************** + * Calculate the multiplicative inverse X of U mod V + * That is: Find the solution for + * 1 = (u*x) mod v + * This has only a unique solution if U and V are relatively prime. + * Returns 0 if a solution was found. + */ +int +mpi_inv_mod( MPI x, MPI u, MPI v ) +{ + #if 0 + /* Extended Euclid's algorithm (See TAOPC Vol II, 4.52. Alg X) */ + MPI u1, u2, u3, v1, v2, v3, q, t1, t2, t3; + + u1 = mpi_alloc_set_ui(1); + u2 = mpi_alloc_set_ui(0); + u3 = mpi_copy(u); + v1 = mpi_alloc_set_ui(0); + v2 = mpi_alloc_set_ui(1); + v3 = mpi_copy(v); + q = mpi_alloc( mpi_get_nlimbs(u) ); + t1 = mpi_alloc( mpi_get_nlimbs(u) ); + t2 = mpi_alloc( mpi_get_nlimbs(u) ); + t3 = mpi_alloc( mpi_get_nlimbs(u) ); + while( mpi_cmp_ui( v3, 0 ) ) { + /*log_debug("----------------------\n"); + log_mpidump("q =", u1); + log_mpidump("u1=", u1); + log_mpidump("u2=", u2); + log_mpidump("u3=", u3); + log_mpidump("v1=", v1); + log_mpidump("v2=", v2); + log_mpidump("v3=", v3); */ + mpi_fdiv_q( q, u3, v3 ); + mpi_mul(t1, v1, q); mpi_mul(t2, v2, q); mpi_mul(t3, v3, q); + mpi_sub(t1, u1, t1); mpi_sub(t2, u2, t2); mpi_sub(t3, u3, t3); + + mpi_set(u1, v1); mpi_set(u2, v2); mpi_set(u3, v3); + mpi_set(v1, t1); mpi_set(v2, t2); mpi_set(v3, t3); + } + mpi_set(x, u3); + + mpi_free(u1); + mpi_free(u2); + mpi_free(u3); + mpi_free(v1); + mpi_free(v2); + mpi_free(v3); + mpi_free(q); + mpi_free(t1); + mpi_free(t2); + mpi_free(t3); + #endif + + /***************************** + * 1. Init: g0 = u g1 = v v0 = 0 v1 = 1 + * 2. Test: if g1 is 0 terminate. Result = v0 < 0: v0 + n + * else: v0 + * 3. Divide: div,rem = g0 / g1 + * t1 = v0 - div * v1 + * v0 = v1 + * v1 = t1 + * g0 = g1 + * g1 = rem + * continue with step 2. + */ + MPI g0, g1, v0, v1, div, rem, t1; + + g0 = mpi_copy(v); + g1 = mpi_copy(u); + v0 = mpi_alloc_set_ui( 0 ); + v1 = mpi_alloc_set_ui( 1 ); + div = mpi_alloc(mpi_get_nlimbs(v)); + rem = mpi_alloc(mpi_get_nlimbs(v)); + t1 = mpi_alloc(mpi_get_nlimbs(v)); + while( mpi_cmp_ui( g1, 0) ) { + mpi_fdiv_qr(div, rem, g0, g1); + mpi_mul(t1, div, v1); + mpi_sub(t1, v0, t1); + mpi_set(v0, v1); + mpi_set(v1, t1); + mpi_set(g0, g1); + mpi_set(g1, rem); + + } + if( mpi_cmp_ui( v0, 0) < 0 ) + mpi_add( x, v0, v); + else + mpi_set( x, v0); + + mpi_free(g0); + mpi_free(g1); + mpi_free(v0); + mpi_free(v1); + mpi_free(div); + mpi_free(rem); + mpi_free(t1); + return 0; +} + + + diff --git a/mpi/mpi-mul.c b/mpi/mpi-mul.c new file mode 100644 index 000000000..03f2b4b44 --- /dev/null +++ b/mpi/mpi-mul.c @@ -0,0 +1,178 @@ +/* mpi-mul.c - MPI functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi-internal.h" + + +void +mpi_mul_ui( MPI prod, MPI mult, unsigned long small_mult ) +{ + mpi_size_t size, prod_size; + mpi_ptr_t prod_ptr; + mpi_limb_t cy; + int sign; + + size = mult->nlimbs; + sign = mult->sign; + + if( !size || !small_mult ) { + prod->nlimbs = 0; + prod->sign = 0; + return; + } + + prod_size = size + 1; + if( prod->alloced < prod_size ) + mpi_resize( prod, prod_size ); + prod_ptr = prod->d; + + cy = mpihelp_mul_1( prod_ptr, mult->d, size, (mpi_limb_t)small_mult ); + if( cy ) + prod_ptr[size++] = cy; + prod->nlimbs = size; + prod->sign = sign; +} + + +void +mpi_mul_2exp( MPI w, MPI u, unsigned long cnt) +{ + mpi_size_t usize, wsize, limb_cnt; + mpi_ptr_t wp; + mpi_limb_t wlimb; + int usign, wsign; + + usize = u->nlimbs; + usign = u->sign; + + if( !usize ) { + w->nlimbs = 0; + w->sign = 0; + return; + } + + limb_cnt = cnt / BITS_PER_MPI_LIMB; + wsize = usize + limb_cnt + 1; + if( w->alloced < wsize ) + mpi_resize(w, wsize ); + wp = w->d; + wsize = usize + limb_cnt; + wsign = usign; + + cnt %= BITS_PER_MPI_LIMB; + if( cnt ) { + wlimb = mpihelp_lshift( wp + limb_cnt, u->d, usize, cnt ); + if( wlimb ) { + wp[wsize] = wlimb; + wsize++; + } + } + else { + MPN_COPY_DECR( wp + limb_cnt, u->d, usize ); + } + + /* Zero all whole limbs at low end. Do it here and not before calling + * mpn_lshift, not to lose for U == W. */ + MPN_ZERO( wp, limb_cnt ); + + w->nlimbs = wsize; + w->sign = wsign; +} + + + +void +mpi_mul( MPI w, MPI u, MPI v) +{ + mpi_size_t usize, vsize, wsize; + mpi_ptr_t up, vp, wp; + mpi_limb_t cy; + int usign, vsign, sign_product; + int assign_wp=0; + mpi_ptr_t tmp_limb=NULL; + + if( u->nlimbs < v->nlimbs ) { /* Swap U and V. */ + usize = v->nlimbs; + usign = v->sign; + up = v->d; + vsize = u->nlimbs; + vsign = u->sign; + vp = u->d; + } + else { + usize = u->nlimbs; + usign = u->sign; + up = u->d; + vsize = v->nlimbs; + vsign = v->sign; + vp = v->d; + } + sign_product = usign ^ vsign; + wp = w->d; + + /* Ensure W has space enough to store the result. */ + wsize = usize + vsize; + if( w->alloced < wsize ) { + if( wp == up || wp == vp ) { + wp = mpi_alloc_limb_space( wsize ); + assign_wp = 1; + } + else { + mpi_resize(w, wsize ); + wp = w->d; + } + } + else { /* Make U and V not overlap with W. */ + if( wp == up ) { + /* W and U are identical. Allocate temporary space for U. */ + up = tmp_limb = mpi_alloc_limb_space( usize ); + /* Is V identical too? Keep it identical with U. */ + if( wp == vp ) + vp = up; + /* Copy to the temporary space. */ + MPN_COPY( up, wp, usize ); + } + else if( wp == vp ) { + /* W and V are identical. Allocate temporary space for V. */ + vp = tmp_limb = mpi_alloc_limb_space( vsize ); + /* Copy to the temporary space. */ + MPN_COPY( vp, wp, vsize ); + } + } + + if( !vsize ) + wsize = 0; + else { + cy = mpihelp_mul( wp, up, usize, vp, vsize ); + wsize -= cy? 0:1; + } + + if( assign_wp ) + mpi_assign_limb_space( w, wp, wsize ); + w->nlimbs = wsize; + w->sign = sign_product; + if( tmp_limb ) + mpi_free_limb_space( tmp_limb ); +} + + diff --git a/mpi/mpi-pow.c b/mpi/mpi-pow.c new file mode 100644 index 000000000..14fe4de47 --- /dev/null +++ b/mpi/mpi-pow.c @@ -0,0 +1,247 @@ +/* mpi-pow.c - MPI functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi-internal.h" +#include "longlong.h" +#include <assert.h> + + +/**************** + * RES = BASE ^ EXP mod MOD + */ +void +mpi_powm( MPI res, MPI base, MPI exp, MPI mod) +{ + mpi_ptr_t rp, ep, mp, bp; + mpi_size_t esize, msize, bsize, rsize; + int esign, msign, bsign, rsign; + mpi_size_t size; + int mod_shift_cnt; + int negative_result; + mpi_ptr_t mp_marker=NULL, bp_marker=NULL, ep_marker=NULL; + mpi_ptr_t xp_marker=NULL; + int assign_rp=0; + + esize = exp->nlimbs; + msize = mod->nlimbs; + size = 2 * msize; + esign = exp->sign; + msign = mod->sign; + + rp = res->d; + ep = exp->d; + + if( !msize ) + msize = 1 / msize; /* provoke a signal */ + + if( !esize ) { + /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 + * depending on if MOD equals 1. */ + rp[0] = 1; + res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1; + res->sign = 0; + goto leave; + } + + /* Normalize MOD (i.e. make its most significant bit set) as required by + * mpn_divrem. This will make the intermediate values in the calculation + * slightly larger, but the correct result is obtained after a final + * reduction using the original MOD value. */ + mp = mp_marker = mpi_alloc_limb_space(msize); + count_leading_zeros( mod_shift_cnt, mod->d[msize-1] ); + if( mod_shift_cnt ) + mpihelp_lshift( mp, mod->d, msize, mod_shift_cnt ); + else + MPN_COPY( mp, mod->d, msize ); + + bsize = base->nlimbs; + bsign = base->sign; + if( bsize > msize ) { /* The base is larger than the module. Reduce it. */ + /* Allocate (BSIZE + 1) with space for remainder and quotient. + * (The quotient is (bsize - msize + 1) limbs.) */ + bp = bp_marker = mpi_alloc_limb_space( bsize + 1); + MPN_COPY( bp, base->d, bsize ); + /* We don't care about the quotient, store it above the remainder, + * at BP + MSIZE. */ + mpihelp_divrem( bp + msize, 0, bp, bsize, mp, msize ); + bsize = msize; + /* Canonicalize the base, since we are going to multiply with it + * quite a few times. */ + MPN_NORMALIZE( bp, bsize ); + } + else + bp = base->d; + + if( !bsize ) { + res->nlimbs = 0; + res->sign = 0; + goto leave; + } + + if( res->alloced < size ) { + /* We have to allocate more space for RES. If any of the input + * parameters are identical to RES, defer deallocation of the old + * space. */ + if( rp == ep || rp == mp || rp == bp ) { + rp = mpi_alloc_limb_space( size ); + assign_rp = 1; + } + else { + mpi_resize( res, size ); + rp = res->d; + } + } + else { /* Make BASE, EXP and MOD not overlap with RES. */ + if( rp == bp ) { + /* RES and BASE are identical. Allocate temp. space for BASE. */ + assert( !bp_marker ); + bp = bp_marker = mpi_alloc_limb_space( bsize ); + MPN_COPY(bp, rp, bsize); + } + if( rp == ep ) { + /* RES and EXP are identical. Allocate temp. space for EXP. */ + ep = ep_marker = mpi_alloc_limb_space( esize ); + MPN_COPY(ep, rp, esize); + } + if( rp == mp ) { + /* RES and MOD are identical. Allocate temporary space for MOD.*/ + assert( !mp_marker ); + mp = mp_marker = mpi_alloc_limb_space( msize ); + MPN_COPY(mp, rp, msize); + } + } + + MPN_COPY( rp, bp, bsize ); + rsize = bsize; + rsign = bsign; + + { + mpi_size_t i; + mpi_ptr_t xp = xp_marker = mpi_alloc_limb_space( 2 * (msize + 1) ); + int c; + mpi_limb_t e; + mpi_limb_t carry_limb; + + negative_result = (ep[0] & 1) && base->sign; + + i = esize - 1; + e = ep[i]; + count_leading_zeros (c, e); + e = (e << c) << 1; /* shift the exp bits to the left, lose msb */ + c = BITS_PER_MPI_LIMB - 1 - c; + + /* Main loop. + * + * Make the result be pointed to alternately by XP and RP. This + * helps us avoid block copying, which would otherwise be necessary + * with the overlap restrictions of mpihelp_divmod. With 50% probability + * the result after this loop will be in the area originally pointed + * by RP (==RES->d), and with 50% probability in the area originally + * pointed to by XP. + */ + for(;;) { + while( c ) { + mpi_ptr_t tp; + mpi_size_t xsize; + + mpihelp_mul_n(xp, rp, rp, rsize); + xsize = 2 * rsize; + if( xsize > msize ) { + mpihelp_divrem(xp + msize, 0, xp, xsize, mp, msize); + xsize = msize; + } + + tp = rp; rp = xp; xp = tp; + rsize = xsize; + + if( (mpi_limb_signed_t)e < 0 ) { + mpihelp_mul( xp, rp, rsize, bp, bsize ); + xsize = rsize + bsize; + if( xsize > msize ) { + mpihelp_divrem(xp + msize, 0, xp, xsize, mp, msize); + xsize = msize; + } + + tp = rp; rp = xp; xp = tp; + rsize = xsize; + } + e <<= 1; + c--; + } + + i--; + if( i < 0 ) + break; + e = ep[i]; + c = BITS_PER_MPI_LIMB; + } + + /* We shifted MOD, the modulo reduction argument, left MOD_SHIFT_CNT + * steps. Adjust the result by reducing it with the original MOD. + * + * Also make sure the result is put in RES->d (where it already + * might be, see above). + */ + if( mod_shift_cnt ) { + carry_limb = mpihelp_lshift( res->d, rp, rsize, mod_shift_cnt); + rp = res->d; + if( carry_limb ) { + rp[rsize] = carry_limb; + rsize++; + } + } + else { + MPN_COPY( res->d, rp, rsize); + rp = res->d; + } + + if( rsize >= msize ) { + mpihelp_divrem(rp + msize, 0, rp, rsize, mp, msize); + rsize = msize; + } + + /* Remove any leading zero words from the result. */ + if( mod_shift_cnt ) + mpihelp_rshift( rp, rp, rsize, mod_shift_cnt); + MPN_NORMALIZE (rp, rsize); + } + + if( negative_result && rsize ) { + if( mod_shift_cnt ) + mpihelp_rshift( mp, mp, msize, mod_shift_cnt); + mpihelp_sub( rp, mp, msize, rp, rsize); + rsize = msize; + rsign = msign; + MPN_NORMALIZE(rp, rsize); + } + res->nlimbs = rsize; + res->sign = rsign; + + leave: + if( assign_rp ) mpi_assign_limb_space( res, rp, size ); + if( mp_marker ) mpi_free_limb_space( mp_marker ); + if( bp_marker ) mpi_free_limb_space( bp_marker ); + if( ep_marker ) mpi_free_limb_space( ep_marker ); + if( xp_marker ) mpi_free_limb_space( xp_marker ); +} + diff --git a/mpi/mpi-scan.c b/mpi/mpi-scan.c new file mode 100644 index 000000000..8626032a0 --- /dev/null +++ b/mpi/mpi-scan.c @@ -0,0 +1,88 @@ +/* mpi-scan.c - MPI functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi-internal.h" + +/**************** + * Scan through an mpi and return byte for byte. a -1 is returned to indicate + * the end of the mpi. Scanning is done from the lsb to the msb, returned + * values are in the range of 0 .. 255. + * + * FIXME: This code is VERY ugly! + */ +int +mpi_getbyte( MPI a, unsigned index ) +{ + int i, j; + unsigned n; + mpi_ptr_t ap; + mpi_limb_t limb; + + ap = a->d; + for(n=0,i=0; i < a->nlimbs; i++ ) { + limb = ap[i]; + for( j=0; j < BYTES_PER_MPI_LIMB; j++, n++ ) + if( n == index ) + return (limb >> j*8) & 0xff; + } + return -1; +} + + +/**************** + * Put a value at position INDEX into A. index counts from lsb to msb + */ +void +mpi_putbyte( MPI a, unsigned index, int c ) +{ + int i, j; + unsigned n; + mpi_ptr_t ap; + mpi_limb_t limb; + +#if BYTES_PER_MPI_LIMB != 4 + #error please enhance this function, its ugly - i know. +#endif + c &= 0xff; + ap = a->d; + for(n=0,i=0; i < a->alloced; i++ ) { + limb = ap[i]; + for( j=0; j < BYTES_PER_MPI_LIMB; j++, n++ ) + if( n == index ) { + if( j == 0 ) + limb = (limb & 0xffffff00) | c; + else if( j == 1 ) + limb = (limb & 0xffff00ff) | (c<<8); + else if( j == 2 ) + limb = (limb & 0xff00ffff) | (c<<16); + else + limb = (limb & 0x00ffffff) | (c<<24); + if( a->nlimbs <= i ) + a->nlimbs = i+1; + ap[i] = limb; + return; + } + } + abort(); /* index out of range */ +} + diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c new file mode 100644 index 000000000..23454c0f9 --- /dev/null +++ b/mpi/mpicoder.c @@ -0,0 +1,392 @@ +/* mpicoder.c - Coder for the external representation of MPIs + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "mpi.h" +#include "iobuf.h" +#include "memory.h" +#include "util.h" + +#ifdef M_DEBUG + #undef mpi_decode + #undef mpi_decode_buffer +#endif + +#define MAX_EXTERN_MPI_BITS 16384 + +/**************** + * write an mpi to out. + */ +int +mpi_encode( IOBUF out, MPI a ) +{ + u16 dummy; + return mpi_encode_csum( out, a, &dummy ); +} + +int +mpi_encode_csum( IOBUF out, MPI a, u16 *csum ) +{ + int i; + byte c; + unsigned nbits = a->nlimbs * BITS_PER_MPI_LIMB; + mpi_limb_t limb; + +#if BYTES_PER_MPI_LIMB != 4 + #error Make this function work with other LIMB sizes +#endif + if( nbits > MAX_EXTERN_MPI_BITS ) + log_bug("mpi_encode: mpi too large (%u bits)\n", nbits); + iobuf_put(out, (c=nbits >>8) ); *csum += c; + iobuf_put(out, (c=nbits) ); *csum += c; + for(i=a->nlimbs-1; i >= 0; i-- ) { + limb = a->d[i]; + iobuf_put(out, (c=limb >> 24) ); *csum += c; + iobuf_put(out, (c=limb >> 16) ); *csum += c; + iobuf_put(out, (c=limb >> 8) ); *csum += c; + iobuf_put(out, (c=limb ) ); *csum += c; + } + return 0; +} + +/**************** + * encode the MPI into a newly allocated buffer, the buffer is + * so constructed, that it can be used for mpi_write. The caller + * must free the returned buffer. The buffer is allocated in the same + * type of memory space as A is. + */ +byte * +mpi_encode_buffer( MPI a ) +{ + abort(); + return NULL; +} + +/**************** + * write an mpi to out. This is a special function to handle + * encrypted values. It simply writes the buffer a to OUT. + * A is a special buffer, starting with 2 bytes giving it's length + * (in big endian order) and 2 bytes giving it's length in bits (also + * big endian) + */ +int +mpi_write( IOBUF out, byte *a) +{ + u16 dummy; + return mpi_write_csum( out, a, &dummy ); +} + +int +mpi_write_csum( IOBUF out, byte *a, u16 *csum) +{ + int rc; + unsigned n; + + n = *a++ << 8; + n |= *a++; + rc = iobuf_write(out, a, n ); + for( ; n; n--, a++ ) + *csum += *a; + return rc; +} + +/**************** + * Decode an external representation and return an MPI + * The external format is a 16 bit unsigned value stored in network byte order, + * giving the number of bits for the following integer. The integer is stored + * with MSB first (left padded with zeroes to align on a byte boundary). + */ +MPI +#ifdef M_DEBUG +mpi_debug_decode(IOBUF inp, unsigned *ret_nread, const char *info) +#else +mpi_decode(IOBUF inp, unsigned *ret_nread) +#endif +{ + int c, i, j; + unsigned nbits, nbytes, nlimbs, nread=0; + mpi_limb_t a; + MPI val = MPI_NULL; + + if( (c = iobuf_get(inp)) == -1 ) + goto leave; + nbits = c << 8; + if( (c = iobuf_get(inp)) == -1 ) + goto leave; + nbits |= c; + if( nbits > MAX_EXTERN_MPI_BITS ) { + log_error("mpi too large (%u bits)\n", nbits); + goto leave; + } + nread = 2; + + nbytes = (nbits+7) / 8; + nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; + #ifdef M_DEBUG + val = mpi_debug_alloc( nlimbs, info ); + #else + val = mpi_alloc( nlimbs ); + #endif + i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; + i %= BYTES_PER_MPI_LIMB; + j= val->nlimbs = nlimbs; + val->sign = 0; + for( ; j > 0; j-- ) { + a = 0; + for(; i < BYTES_PER_MPI_LIMB; i++ ) { + a <<= 8; + a |= iobuf_get(inp) & 0xff; nread++; + } + i = 0; + val->d[j-1] = a; + } + + leave: + if( nread > *ret_nread ) + log_error("Ooops: mpi crosses packet border"); + else + *ret_nread = nread; + return val; +} + + +/**************** + * Decode an MPI from the buffer, the buffer starts with two bytes giving + * the length of the data to follow, the original data follows. + * The MPI is alloced from secure MPI space + */ +MPI +#ifdef M_DEBUG +mpi_debug_decode_buffer(byte *buffer, const char *info ) +#else +mpi_decode_buffer(byte *buffer ) +#endif +{ + int i, j; + u16 buflen; + unsigned nbits, nbytes, nlimbs; + mpi_limb_t a; + byte *p = buffer; + MPI val; + + if( !buffer ) + log_bug("mpi_decode_buffer: no buffer\n"); + buflen = *p++ << 8; + buflen |= *p++; + nbits = *p++ << 8; + nbits |= *p++; + nbytes = (nbits+7) / 8; + if( nbytes+2 != buflen ) + log_bug("mpi_decode_buffer: length conflict\n"); + nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; + #ifdef M_DEBUG + val = mpi_debug_alloc_secure( nlimbs, info ); + #else + val = mpi_alloc_secure( nlimbs ); + #endif + i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; + i %= BYTES_PER_MPI_LIMB; + j= val->nlimbs = nlimbs; + val->sign = 0; + for( ; j > 0; j-- ) { + a = 0; + for(; i < BYTES_PER_MPI_LIMB; i++ ) { + a <<= 8; + a |= *p++; + } + i = 0; + val->d[j-1] = a; + } + return val; +} + + +/**************** + * Read a MPI from the external medium and return it in a newly allocated + * buffer (This buffer is allocated in the secure memory space, because + * we properly need this to decipher this string). + * Return: the allocated string and in RET_NREAD the number of bytes + * read (including the 2 length bytes), the returned buffer will + * be prefixed with two bytes describing the length of the following + * data. + */ +byte * +mpi_read(IOBUF inp, unsigned *ret_nread) +{ + int c; + u16 buflen; + unsigned nbits, nbytes, nread; + byte *p, *buf; + + if( (c = iobuf_get(inp)) == -1 ) + return NULL; + nbits = c << 8; + if( (c = iobuf_get(inp)) == -1 ) + return NULL; + nbits |= c; + if( nbits > MAX_EXTERN_MPI_BITS ) { + log_error("mpi too large (%u bits)\n", nbits); + return NULL; + } + nread = 2; + + nbytes = (nbits+7) / 8; + buflen = nbytes + 2; + p = buf = m_alloc_secure( buflen+2 ); + *p++ = buflen >> 8; + *p++ = buflen & 0xff; + *p++ = nbits >> 8; + *p++ = nbits & 0xff; + for( ; nbytes ; nbytes--, nread++ ) + *p++ = iobuf_get(inp) & 0xff; + + if( nread > *ret_nread ) + log_error("Ooops: mpi crosses packet border"); + else + *ret_nread = nread; + return buf; +} + + +/**************** + * Make a mpi from a character string. + */ +int +mpi_fromstr(MPI val, const char *str) +{ + int hexmode=0, sign=0, prepend_zero=0, i, j, c, c1, c2; + unsigned nbits, nbytes, nlimbs; + mpi_limb_t a; + + if( *str == '-' ) { + sign = 1; + str++; + } + if( *str == '0' && str[1] == 'x' ) + hexmode = 1; + else + return 1; /* other bases are not yet supported */ + str += 2; + + nbits = strlen(str)*4; + if( nbits % 8 ) + prepend_zero = 1; + nbytes = (nbits+7) / 8; + nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; + if( val->alloced < nlimbs ) + mpi_resize(val, nlimbs ); + i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; + i %= BYTES_PER_MPI_LIMB; + j= val->nlimbs = nlimbs; + val->sign = sign; + for( ; j > 0; j-- ) { + a = 0; + for(; i < BYTES_PER_MPI_LIMB; i++ ) { + if( prepend_zero ) { + c1 = '0'; + prepend_zero = 0; + } + else + c1 = *str++; + assert(c1); + c2 = *str++; + assert(c2); + if( c1 >= '0' && c1 <= '9' ) + c = c1 - '0'; + else if( c1 >= 'a' && c1 <= 'f' ) + c = c1 - 'a' + 10; + else if( c1 >= 'A' && c1 <= 'F' ) + c = c1 - 'A' + 10; + else { + mpi_clear(val); + return 1; + } + c <<= 4; + if( c2 >= '0' && c2 <= '9' ) + c |= c2 - '0'; + else if( c2 >= 'a' && c2 <= 'f' ) + c |= c2 - 'a' + 10; + else if( c2 >= 'A' && c2 <= 'F' ) + c |= c2 - 'A' + 10; + else { + mpi_clear(val); + return 1; + } + a <<= 8; + a |= c; + } + i = 0; + val->d[j-1] = a; + } + + return 0; +} + + +/**************** + * print an MPI to the give stream and return the number of characters + * printed. + */ +int +mpi_print( FILE *fp, MPI a, int mode ) +{ + int i, n=0; + + if( a == MPI_NULL ) + return fprintf(fp, "[MPI_NULL]"); + if( !mode ) + n += fprintf(fp, "[%d bits]", a->nlimbs * BITS_PER_MPI_LIMB ); + else { + if( a->sign ) + putc('-', fp); + for(i=a->nlimbs; i > 0 ; i-- ) { + n += fprintf(fp, i!=a->nlimbs? "%0" STR2(BYTES_PER_MPI_LIMB2) + "lX":"%lX", (unsigned long)a->d[i-1] ); + } + if( !a->nlimbs ) + putc('0', fp ); + } + return n; +} + + +/**************** + * Special function to get the low 8 bytes from a mpi, + * this can be used as a keyid, KEYID is an 2 element array. + * Does return the low 4 bytes. + */ +u32 +mpi_get_keyid( MPI a, u32 *keyid ) +{ +#if BYTES_PER_MPI_LIMB != 4 + #error Make this function work with other LIMB sizes +#endif + if( keyid ) { + keyid[0] = a->nlimbs >= 2? a->d[1] : 0; + keyid[1] = a->nlimbs >= 1? a->d[0] : 0; + } + return a->nlimbs >= 1? a->d[0] : 0; +} + + diff --git a/mpi/mpih-add.c b/mpi/mpih-add.c new file mode 100644 index 000000000..90ce8d76a --- /dev/null +++ b/mpi/mpih-add.c @@ -0,0 +1,109 @@ +/* mpihelp-add.c - MPI helper functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> + +#include "mpi-internal.h" + +/**************** + * Add to S1_PTR with size S1_SIZE the limb S2_LIMB and + * store the result in RES_PTR. Return the carry + * S1_SIZE must be > 0. + */ +/*_EXTERN_INLINE */ +mpi_limb_t +mpihelp_add_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb) +{ + mpi_limb_t x; + + x = *s1_ptr++; + s2_limb += x; + *res_ptr++ = s2_limb; + if( s2_limb < x ) { /* sum is less than the left operand: handle carry */ + while( --s1_size ) { + x = *s1_ptr++ + 1; /* add carry */ + *res_ptr++ = x; /* and store */ + if( x ) /* not 0 (no overflow): we can stop */ + goto leave; + } + return 1; /* return carry (size of s1 to small) */ + } + + leave: + if( res_ptr != s1_ptr ) { /* not the same variable */ + mpi_size_t i; /* copy the rest */ + for( i=0; i < s1_size-1; i++ ) + res_ptr[i] = s1_ptr[i]; + } + return 0; /* no carry */ +} + + +/* FIXME: this should be done in assembly */ +mpi_limb_t +mpihelp_add_n( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_ptr_t s2_ptr, mpi_size_t size) +{ + mpi_limb_t x, y, cy; + mpi_size_t j; + + /* The loop counter and index J goes from -SIZE to -1. This way + the loop becomes faster. */ + j = -size; + + /* Offset the base pointers to compensate for the negative indices. */ + s1_ptr -= j; + s2_ptr -= j; + res_ptr -= j; + + cy = 0; + do { + y = s2_ptr[j]; + x = s1_ptr[j]; + y += cy; /* add previous carry to one addend */ + cy = y < cy? 1:0; /* get out carry from that addition */ + y += x; /* add other addend */ + cy += y < x? 1:0; /* get out carry from that add, combine */ + res_ptr[j] = y; + } while( ++j ); + + return cy; +} + + +/*_EXTERN_INLINE*/ +mpi_limb_t +mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, + mpi_ptr_t s2_ptr, mpi_size_t s2_size) +{ + mpi_limb_t cy = 0; + + if( s2_size ) + cy = mpihelp_add_n( res_ptr, s1_ptr, s2_ptr, s2_size ); + + if( s1_size - s2_size ) + cy = mpihelp_add_1( res_ptr + s2_size, s1_ptr + s2_size, + s1_size - s2_size, cy); + return cy; +} + diff --git a/mpi/mpih-cmp.c b/mpi/mpih-cmp.c new file mode 100644 index 000000000..821c0ce8c --- /dev/null +++ b/mpi/mpih-cmp.c @@ -0,0 +1,53 @@ +/* mpihelp-sub.c - MPI helper functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> + +#include "mpi-internal.h" + +/**************** + * Compare OP1_PTR/OP1_SIZE with OP2_PTR/OP2_SIZE. + * There are no restrictions on the relative sizes of + * the two arguments. + * Return 1 if OP1 > OP2, 0 if they are equal, and -1 if OP1 < OP2. + */ +int +mpihelp_cmp( mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size ) +{ + mpi_size_t i; + mpi_limb_t op1_word, op2_word; + + for( i = size - 1; i >= 0 ; i--) { + op1_word = op1_ptr[i]; + op2_word = op2_ptr[i]; + if( op1_word != op2_word ) + goto diff; + } + return 0; + + diff: + /* This can *not* be simplified to + * op2_word - op2_word + * since that expression might give signed overflow. */ + return (op1_word > op2_word) ? 1 : -1; +} + diff --git a/mpi/mpih-div.c b/mpi/mpih-div.c new file mode 100644 index 000000000..ca939a750 --- /dev/null +++ b/mpi/mpih-div.c @@ -0,0 +1,528 @@ +/* mpihelp-div.c - MPI helper functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi-internal.h" +#include "longlong.h" + +#ifndef UMUL_TIME + #define UMUL_TIME 1 +#endif +#ifndef UDIV_TIME + #define UDIV_TIME UMUL_TIME +#endif + +/* FIXME: We should be using invert_limb (or invert_normalized_limb) + * here (not udiv_qrnnd). + */ + +mpi_limb_t +mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, + mpi_limb_t divisor_limb) +{ + mpi_size_t i; + mpi_limb_t n1, n0, r; + int dummy; + + /* Botch: Should this be handled at all? Rely on callers? */ + if( !dividend_size ) + return 0; + + /* If multiplication is much faster than division, and the + * dividend is large, pre-invert the divisor, and use + * only multiplications in the inner loop. + * + * This test should be read: + * Does it ever help to use udiv_qrnnd_preinv? + * && Does what we save compensate for the inversion overhead? + */ + if( UDIV_TIME > (2 * UMUL_TIME + 6) + && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME ) { + int normalization_steps; + + count_leading_zeros( normalization_steps, divisor_limb ); + if( normalization_steps ) { + mpi_limb_t divisor_limb_inverted; + + divisor_limb <<= normalization_steps; + + /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The + * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the + * most significant bit (with weight 2**N) implicit. + * + * Special case for DIVISOR_LIMB == 100...000. + */ + if( !(divisor_limb << 1) ) + divisor_limb_inverted = ~(mpi_limb_t)0; + else + udiv_qrnnd(divisor_limb_inverted, dummy, + -divisor_limb, 0, divisor_limb); + + n1 = dividend_ptr[dividend_size - 1]; + r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); + + /* Possible optimization: + * if (r == 0 + * && divisor_limb > ((n1 << normalization_steps) + * | (dividend_ptr[dividend_size - 2] >> ...))) + * ...one division less... + */ + for( i = dividend_size - 2; i >= 0; i--) { + n0 = dividend_ptr[i]; + UDIV_QRNND_PREINV(dummy, r, r, + ((n1 << normalization_steps) + | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))), + divisor_limb, divisor_limb_inverted); + n1 = n0; + } + UDIV_QRNND_PREINV(dummy, r, r, + n1 << normalization_steps, + divisor_limb, divisor_limb_inverted); + return r >> normalization_steps; + } + else { + mpi_limb_t divisor_limb_inverted; + + /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The + * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the + * most significant bit (with weight 2**N) implicit. + * + * Special case for DIVISOR_LIMB == 100...000. + */ + if( !(divisor_limb << 1) ) + divisor_limb_inverted = ~(mpi_limb_t)0; + else + udiv_qrnnd(divisor_limb_inverted, dummy, + -divisor_limb, 0, divisor_limb); + + i = dividend_size - 1; + r = dividend_ptr[i]; + + if( r >= divisor_limb ) + r = 0; + else + i--; + + for( ; i >= 0; i--) { + n0 = dividend_ptr[i]; + UDIV_QRNND_PREINV(dummy, r, r, + n0, divisor_limb, divisor_limb_inverted); + } + return r; + } + } + else { + if( UDIV_NEEDS_NORMALIZATION ) { + int normalization_steps; + + count_leading_zeros(normalization_steps, divisor_limb); + if( normalization_steps ) { + divisor_limb <<= normalization_steps; + + n1 = dividend_ptr[dividend_size - 1]; + r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); + + /* Possible optimization: + * if (r == 0 + * && divisor_limb > ((n1 << normalization_steps) + * | (dividend_ptr[dividend_size - 2] >> ...))) + * ...one division less... + */ + for(i = dividend_size - 2; i >= 0; i--) { + n0 = dividend_ptr[i]; + udiv_qrnnd (dummy, r, r, + ((n1 << normalization_steps) + | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))), + divisor_limb); + n1 = n0; + } + udiv_qrnnd (dummy, r, r, + n1 << normalization_steps, + divisor_limb); + return r >> normalization_steps; + } + } + /* No normalization needed, either because udiv_qrnnd doesn't require + * it, or because DIVISOR_LIMB is already normalized. */ + i = dividend_size - 1; + r = dividend_ptr[i]; + + if(r >= divisor_limb) + r = 0; + else + i--; + + for(; i >= 0; i--) { + n0 = dividend_ptr[i]; + udiv_qrnnd (dummy, r, r, n0, divisor_limb); + } + return r; + } +} + +/* Divide num (NP/NSIZE) by den (DP/DSIZE) and write + * the NSIZE-DSIZE least significant quotient limbs at QP + * and the DSIZE long remainder at NP. If QEXTRA_LIMBS is + * non-zero, generate that many fraction bits and append them after the + * other quotient limbs. + * Return the most significant limb of the quotient, this is always 0 or 1. + * + * Preconditions: + * 0. NSIZE >= DSIZE. + * 1. The most significant bit of the divisor must be set. + * 2. QP must either not overlap with the input operands at all, or + * QP + DSIZE >= NP must hold true. (This means that it's + * possible to put the quotient in the high part of NUM, right after the + * remainder in NUM. + * 3. NSIZE >= DSIZE, even if QEXTRA_LIMBS is non-zero. + */ + +mpi_limb_t +mpihelp_divrem( mpi_ptr_t qp, mpi_size_t qextra_limbs, + mpi_ptr_t np, mpi_size_t nsize, + mpi_ptr_t dp, mpi_size_t dsize) +{ + mpi_limb_t most_significant_q_limb = 0; + + switch(dsize) { + case 0: + /* We are asked to divide by zero, so go ahead and do it! (To make + the compiler not remove this statement, return the value.) */ + return 1 / dsize; + + case 1: + { + mpi_size_t i; + mpi_limb_t n1; + mpi_limb_t d; + + d = dp[0]; + n1 = np[nsize - 1]; + + if( n1 >= d ) { + n1 -= d; + most_significant_q_limb = 1; + } + + qp += qextra_limbs; + for( i = nsize - 2; i >= 0; i--) + udiv_qrnnd( qp[i], n1, n1, np[i], d ); + qp -= qextra_limbs; + + for( i = qextra_limbs - 1; i >= 0; i-- ) + udiv_qrnnd (qp[i], n1, n1, 0, d); + + np[0] = n1; + } + break; + + case 2: + { + mpi_size_t i; + mpi_limb_t n1, n0, n2; + mpi_limb_t d1, d0; + + np += nsize - 2; + d1 = dp[1]; + d0 = dp[0]; + n1 = np[1]; + n0 = np[0]; + + if( n1 >= d1 && (n1 > d1 || n0 >= d0) ) { + sub_ddmmss (n1, n0, n1, n0, d1, d0); + most_significant_q_limb = 1; + } + + for( i = qextra_limbs + nsize - 2 - 1; i >= 0; i-- ) { + mpi_limb_t q; + mpi_limb_t r; + + if( i >= qextra_limbs ) + np--; + else + np[0] = 0; + + if( n1 == d1 ) { + /* Q should be either 111..111 or 111..110. Need special + * treatment of this rare case as normal division would + * give overflow. */ + q = ~(mpi_limb_t)0; + + r = n0 + d1; + if( r < d1 ) { /* Carry in the addition? */ + add_ssaaaa( n1, n0, r - d0, np[0], 0, d0 ); + qp[i] = q; + continue; + } + n1 = d0 - (d0 != 0?1:0); + n0 = -d0; + } + else { + udiv_qrnnd (q, r, n1, n0, d1); + umul_ppmm (n1, n0, d0, q); + } + + n2 = np[0]; + q_test: + if( n1 > r || (n1 == r && n0 > n2) ) { + /* The estimated Q was too large. */ + q--; + sub_ddmmss (n1, n0, n1, n0, 0, d0); + r += d1; + if( r >= d1 ) /* If not carry, test Q again. */ + goto q_test; + } + + qp[i] = q; + sub_ddmmss (n1, n0, r, n2, n1, n0); + } + np[1] = n1; + np[0] = n0; + } + break; + + default: + { + mpi_size_t i; + mpi_limb_t dX, d1, n0; + + np += nsize - dsize; + dX = dp[dsize - 1]; + d1 = dp[dsize - 2]; + n0 = np[dsize - 1]; + + if( n0 >= dX ) { + if(n0 > dX || mpihelp_cmp(np, dp, dsize - 1) >= 0 ) { + mpihelp_sub_n(np, np, dp, dsize); + n0 = np[dsize - 1]; + most_significant_q_limb = 1; + } + } + + for( i = qextra_limbs + nsize - dsize - 1; i >= 0; i--) { + mpi_limb_t q; + mpi_limb_t n1, n2; + mpi_limb_t cy_limb; + + if( i >= qextra_limbs ) { + np--; + n2 = np[dsize]; + } + else { + n2 = np[dsize - 1]; + MPN_COPY_DECR (np + 1, np, dsize); + np[0] = 0; + } + + if( n0 == dX ) { + /* This might over-estimate q, but it's probably not worth + * the extra code here to find out. */ + q = ~(mpi_limb_t)0; + } + else { + mpi_limb_t r; + + udiv_qrnnd(q, r, n0, np[dsize - 1], dX); + umul_ppmm(n1, n0, d1, q); + + while( n1 > r || (n1 == r && n0 > np[dsize - 2])) { + q--; + r += dX; + if( r < dX ) /* I.e. "carry in previous addition?" */ + break; + n1 -= n0 < d1; + n0 -= d1; + } + } + + /* Possible optimization: We already have (q * n0) and (1 * n1) + * after the calculation of q. Taking advantage of that, we + * could make this loop make two iterations less. */ + cy_limb = mpihelp_submul_1(np, dp, dsize, q); + + if( n2 != cy_limb ) { + mpihelp_add_n(np, np, dp, dsize); + q--; + } + + qp[i] = q; + n0 = np[dsize - 1]; + } + } + } + + return most_significant_q_limb; +} + + +/**************** + * Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB. + * Write DIVIDEND_SIZE limbs of quotient at QUOT_PTR. + * Return the single-limb remainder. + * There are no constraints on the value of the divisor. + * + * QUOT_PTR and DIVIDEND_PTR might point to the same limb. + */ + +mpi_limb_t +mpihelp_divmod_1( mpi_ptr_t quot_ptr, + mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, + mpi_limb_t divisor_limb) +{ + mpi_size_t i; + mpi_limb_t n1, n0, r; + int dummy; + + if( !dividend_size ) + return 0; + + /* If multiplication is much faster than division, and the + * dividend is large, pre-invert the divisor, and use + * only multiplications in the inner loop. + * + * This test should be read: + * Does it ever help to use udiv_qrnnd_preinv? + * && Does what we save compensate for the inversion overhead? + */ + if( UDIV_TIME > (2 * UMUL_TIME + 6) + && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME ) { + int normalization_steps; + + count_leading_zeros( normalization_steps, divisor_limb ); + if( normalization_steps ) { + mpi_limb_t divisor_limb_inverted; + + divisor_limb <<= normalization_steps; + + /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The + * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the + * most significant bit (with weight 2**N) implicit. + */ + /* Special case for DIVISOR_LIMB == 100...000. */ + if( !(divisor_limb << 1) ) + divisor_limb_inverted = ~(mpi_limb_t)0; + else + udiv_qrnnd(divisor_limb_inverted, dummy, + -divisor_limb, 0, divisor_limb); + + n1 = dividend_ptr[dividend_size - 1]; + r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); + + /* Possible optimization: + * if (r == 0 + * && divisor_limb > ((n1 << normalization_steps) + * | (dividend_ptr[dividend_size - 2] >> ...))) + * ...one division less... + */ + for( i = dividend_size - 2; i >= 0; i--) { + n0 = dividend_ptr[i]; + UDIV_QRNND_PREINV( quot_ptr[i + 1], r, r, + ((n1 << normalization_steps) + | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))), + divisor_limb, divisor_limb_inverted); + n1 = n0; + } + UDIV_QRNND_PREINV( quot_ptr[0], r, r, + n1 << normalization_steps, + divisor_limb, divisor_limb_inverted); + return r >> normalization_steps; + } + else { + mpi_limb_t divisor_limb_inverted; + + /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The + * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the + * most significant bit (with weight 2**N) implicit. + */ + /* Special case for DIVISOR_LIMB == 100...000. */ + if( !(divisor_limb << 1) ) + divisor_limb_inverted = ~(mpi_limb_t) 0; + else + udiv_qrnnd(divisor_limb_inverted, dummy, + -divisor_limb, 0, divisor_limb); + + i = dividend_size - 1; + r = dividend_ptr[i]; + + if( r >= divisor_limb ) + r = 0; + else + quot_ptr[i--] = 0; + + for( ; i >= 0; i-- ) { + n0 = dividend_ptr[i]; + UDIV_QRNND_PREINV( quot_ptr[i], r, r, + n0, divisor_limb, divisor_limb_inverted); + } + return r; + } + } + else { + if(UDIV_NEEDS_NORMALIZATION) { + int normalization_steps; + + count_leading_zeros (normalization_steps, divisor_limb); + if( normalization_steps ) { + divisor_limb <<= normalization_steps; + + n1 = dividend_ptr[dividend_size - 1]; + r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); + + /* Possible optimization: + * if (r == 0 + * && divisor_limb > ((n1 << normalization_steps) + * | (dividend_ptr[dividend_size - 2] >> ...))) + * ...one division less... + */ + for( i = dividend_size - 2; i >= 0; i--) { + n0 = dividend_ptr[i]; + udiv_qrnnd (quot_ptr[i + 1], r, r, + ((n1 << normalization_steps) + | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))), + divisor_limb); + n1 = n0; + } + udiv_qrnnd (quot_ptr[0], r, r, + n1 << normalization_steps, + divisor_limb); + return r >> normalization_steps; + } + } + /* No normalization needed, either because udiv_qrnnd doesn't require + * it, or because DIVISOR_LIMB is already normalized. */ + i = dividend_size - 1; + r = dividend_ptr[i]; + + if(r >= divisor_limb) + r = 0; + else + quot_ptr[i--] = 0; + + for(; i >= 0; i--) { + n0 = dividend_ptr[i]; + udiv_qrnnd( quot_ptr[i], r, r, n0, divisor_limb ); + } + return r; + } +} + + diff --git a/mpi/mpih-mul.c b/mpi/mpih-mul.c new file mode 100644 index 000000000..c579a93fe --- /dev/null +++ b/mpi/mpih-mul.c @@ -0,0 +1,557 @@ +/* mpihelp-mul.c - MPI helper functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi-internal.h" +#include "longlong.h" + +/* If KARATSUBA_THRESHOLD is not already defined, define it to a + * value which is good on most machines. */ +#ifndef KARATSUBA_THRESHOLD + #define KARATSUBA_THRESHOLD 32 +#endif + +/* The code can't handle KARATSUBA_THRESHOLD smaller than 2. */ +#if KARATSUBA_THRESHOLD < 2 + #undef KARATSUBA_THRESHOLD + #define KARATSUBA_THRESHOLD 2 +#endif + + +#define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace) \ + do { \ + if( (size) < KARATSUBA_THRESHOLD ) \ + mul_n_basecase (prodp, up, vp, size); \ + else \ + mul_n (prodp, up, vp, size, tspace); \ + } while (0); + +#define MPN_SQR_N_RECURSE(prodp, up, size, tspace) \ + do { \ + if ((size) < KARATSUBA_THRESHOLD) \ + sqr_n_basecase (prodp, up, size); \ + else \ + sqr_n (prodp, up, size, tspace); \ + } while (0); + + + +mpi_limb_t +mpihelp_addmul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb) +{ + mpi_limb_t cy_limb; + mpi_size_t j; + mpi_limb_t prod_high, prod_low; + mpi_limb_t x; + + /* The loop counter and index J goes from -SIZE to -1. This way + * the loop becomes faster. */ + j = -s1_size; + res_ptr -= j; + s1_ptr -= j; + + cy_limb = 0; + do { + umul_ppmm( prod_high, prod_low, s1_ptr[j], s2_limb ); + + prod_low += cy_limb; + cy_limb = (prod_low < cy_limb?1:0) + prod_high; + + x = res_ptr[j]; + prod_low = x + prod_low; + cy_limb += prod_low < x?1:0; + res_ptr[j] = prod_low; + } while ( ++j ); + return cy_limb; +} + + +mpi_limb_t +mpihelp_submul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb) +{ + mpi_limb_t cy_limb; + mpi_size_t j; + mpi_limb_t prod_high, prod_low; + mpi_limb_t x; + + /* The loop counter and index J goes from -SIZE to -1. This way + * the loop becomes faster. */ + j = -s1_size; + res_ptr -= j; + s1_ptr -= j; + + cy_limb = 0; + do { + umul_ppmm( prod_high, prod_low, s1_ptr[j], s2_limb); + + prod_low += cy_limb; + cy_limb = (prod_low < cy_limb?1:0) + prod_high; + + x = res_ptr[j]; + prod_low = x - prod_low; + cy_limb += prod_low > x?1:0; + res_ptr[j] = prod_low; + } while( ++j ); + + return cy_limb; +} + +mpi_limb_t +mpihelp_mul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, + mpi_limb_t s2_limb) +{ + mpi_limb_t cy_limb; + mpi_size_t j; + mpi_limb_t prod_high, prod_low; + + /* The loop counter and index J goes from -S1_SIZE to -1. This way + * the loop becomes faster. */ + j = -s1_size; + + /* Offset the base pointers to compensate for the negative indices. */ + s1_ptr -= j; + res_ptr -= j; + + cy_limb = 0; + do { + umul_ppmm( prod_high, prod_low, s1_ptr[j], s2_limb ); + prod_low += cy_limb; + cy_limb = (prod_low < cy_limb?1:0) + prod_high; + res_ptr[j] = prod_low; + } while( ++j ); + + return cy_limb; +} + + +/* Multiply the natural numbers u (pointed to by UP) and v (pointed to by VP), + * both with SIZE limbs, and store the result at PRODP. 2 * SIZE limbs are + * always stored. Return the most significant limb. + * + * Argument constraints: + * 1. PRODP != UP and PRODP != VP, i.e. the destination + * must be distinct from the multiplier and the multiplicand. + * + * + * Handle simple cases with traditional multiplication. + * + * This is the most critical code of multiplication. All multiplies rely + * on this, both small and huge. Small ones arrive here immediately. Huge + * ones arrive here as this is the base case for Karatsuba's recursive + * algorithm below. + */ + +static mpi_limb_t +mul_n_basecase( mpi_ptr_t prodp, mpi_ptr_t up, + mpi_ptr_t vp, mpi_size_t size) +{ + mpi_size_t i; + mpi_limb_t cy; + mpi_limb_t v_limb; + + /* Multiply by the first limb in V separately, as the result can be + * stored (not added) to PROD. We also avoid a loop for zeroing. */ + v_limb = vp[0]; + if( v_limb <= 1 ) { + if( v_limb == 1 ) + MPN_COPY( prodp, up, size ); + else + MPN_ZERO( prodp, size ); + cy = 0; + } + else + cy = mpihelp_mul_1( prodp, up, size, v_limb ); + + prodp[size] = cy; + prodp++; + + /* For each iteration in the outer loop, multiply one limb from + * U with one limb from V, and add it to PROD. */ + for( i = 1; i < size; i++ ) { + v_limb = vp[i]; + if( v_limb <= 1 ) { + cy = 0; + if( v_limb == 1 ) + cy = mpihelp_add_n(prodp, prodp, up, size); + } + else + cy = mpihelp_addmul_1(prodp, up, size, v_limb); + + prodp[size] = cy; + prodp++; + } + + return cy; +} + + +static void +mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, + mpi_size_t size, mpi_ptr_t tspace ) +{ + if( size & 1 ) { + /* The size is odd, the code code below doesn't handle that. + * Multiply the least significant (size - 1) limbs with a recursive + * call, and handle the most significant limb of S1 and S2 + * separately. + * A slightly faster way to do this would be to make the Karatsuba + * code below behave as if the size were even, and let it check for + * odd size in the end. I.e., in essence move this code to the end. + * Doing so would save us a recursive call, and potentially make the + * stack grow a lot less. + */ + mpi_size_t esize = size - 1; /* even size */ + mpi_limb_t cy_limb; + + MPN_MUL_N_RECURSE( prodp, up, vp, esize, tspace ); + cy_limb = mpihelp_addmul_1( prodp + esize, up, esize, vp[esize] ); + prodp[esize + esize] = cy_limb; + cy_limb = mpihelp_addmul_1( prodp + esize, vp, size, up[esize] ); + prodp[esize + size] = cy_limb; + } + else { + /* Anatolij Alekseevich Karatsuba's divide-and-conquer algorithm. + * + * Split U in two pieces, U1 and U0, such that + * U = U0 + U1*(B**n), + * and V in V1 and V0, such that + * V = V0 + V1*(B**n). + * + * UV is then computed recursively using the identity + * + * 2n n n n + * UV = (B + B )U V + B (U -U )(V -V ) + (B + 1)U V + * 1 1 1 0 0 1 0 0 + * + * Where B = 2**BITS_PER_MP_LIMB. + */ + mpi_size_t hsize = size >> 1; + mpi_limb_t cy; + int negflg; + + /* Product H. ________________ ________________ + * |_____U1 x V1____||____U0 x V0_____| + * Put result in upper part of PROD and pass low part of TSPACE + * as new TSPACE. + */ + MPN_MUL_N_RECURSE(prodp + size, up + hsize, vp + hsize, hsize, tspace); + + /* Product M. ________________ + * |_(U1-U0)(V0-V1)_| + */ + if( mpihelp_cmp(up + hsize, up, hsize) >= 0 ) { + mpihelp_sub_n(prodp, up + hsize, up, hsize); + negflg = 0; + } + else { + mpihelp_sub_n(prodp, up, up + hsize, hsize); + negflg = 1; + } + if( mpihelp_cmp(vp + hsize, vp, hsize) >= 0 ) { + mpihelp_sub_n(prodp + hsize, vp + hsize, vp, hsize); + negflg ^= 1; + } + else { + mpihelp_sub_n(prodp + hsize, vp, vp + hsize, hsize); + /* No change of NEGFLG. */ + } + /* Read temporary operands from low part of PROD. + * Put result in low part of TSPACE using upper part of TSPACE + * as new TSPACE. + */ + MPN_MUL_N_RECURSE(tspace, prodp, prodp + hsize, hsize, tspace + size); + + /* Add/copy product H. */ + MPN_COPY (prodp + hsize, prodp + size, hsize); + cy = mpihelp_add_n( prodp + size, prodp + size, + prodp + size + hsize, hsize); + + /* Add product M (if NEGFLG M is a negative number) */ + if(negflg) + cy -= mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace, size); + else + cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size); + + /* Product L. ________________ ________________ + * |________________||____U0 x V0_____| + * Read temporary operands from low part of PROD. + * Put result in low part of TSPACE using upper part of TSPACE + * as new TSPACE. + */ + MPN_MUL_N_RECURSE(tspace, up, vp, hsize, tspace + size); + + /* Add/copy Product L (twice) */ + + cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size); + if( cy ) + mpihelp_add_1(prodp + hsize + size, prodp + hsize + size, hsize, cy); + + MPN_COPY(prodp, tspace, hsize); + cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize, hsize); + if( cy ) + mpihelp_add_1(prodp + size, prodp + size, size, 1); + } +} + + +static void +sqr_n_basecase( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size ) +{ + mpi_size_t i; + mpi_limb_t cy_limb; + mpi_limb_t v_limb; + + /* Multiply by the first limb in V separately, as the result can be + * stored (not added) to PROD. We also avoid a loop for zeroing. */ + v_limb = up[0]; + if( v_limb <= 1 ) { + if( v_limb == 1 ) + MPN_COPY( prodp, up, size ); + else + MPN_ZERO(prodp, size); + cy_limb = 0; + } + else + cy_limb = mpihelp_mul_1( prodp, up, size, v_limb ); + + prodp[size] = cy_limb; + prodp++; + + /* For each iteration in the outer loop, multiply one limb from + * U with one limb from V, and add it to PROD. */ + for( i=1; i < size; i++) { + v_limb = up[i]; + if( v_limb <= 1 ) { + cy_limb = 0; + if( v_limb == 1 ) + cy_limb = mpihelp_add_n(prodp, prodp, up, size); + } + else + cy_limb = mpihelp_addmul_1(prodp, up, size, v_limb); + + prodp[size] = cy_limb; + prodp++; + } +} + + +static void +sqr_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace) +{ + if( size & 1 ) { + /* The size is odd, the code code below doesn't handle that. + * Multiply the least significant (size - 1) limbs with a recursive + * call, and handle the most significant limb of S1 and S2 + * separately. + * A slightly faster way to do this would be to make the Karatsuba + * code below behave as if the size were even, and let it check for + * odd size in the end. I.e., in essence move this code to the end. + * Doing so would save us a recursive call, and potentially make the + * stack grow a lot less. + */ + mpi_size_t esize = size - 1; /* even size */ + mpi_limb_t cy_limb; + + MPN_SQR_N_RECURSE( prodp, up, esize, tspace ); + cy_limb = mpihelp_addmul_1( prodp + esize, up, esize, up[esize] ); + prodp[esize + esize] = cy_limb; + cy_limb = mpihelp_addmul_1( prodp + esize, up, size, up[esize] ); + + prodp[esize + size] = cy_limb; + } + else { + mpi_size_t hsize = size >> 1; + mpi_limb_t cy; + + /* Product H. ________________ ________________ + * |_____U1 x U1____||____U0 x U0_____| + * Put result in upper part of PROD and pass low part of TSPACE + * as new TSPACE. + */ + MPN_SQR_N_RECURSE(prodp + size, up + hsize, hsize, tspace); + + /* Product M. ________________ + * |_(U1-U0)(U0-U1)_| + */ + if( mpihelp_cmp( up + hsize, up, hsize) >= 0 ) + mpihelp_sub_n( prodp, up + hsize, up, hsize); + else + mpihelp_sub_n (prodp, up, up + hsize, hsize); + + /* Read temporary operands from low part of PROD. + * Put result in low part of TSPACE using upper part of TSPACE + * as new TSPACE. */ + MPN_SQR_N_RECURSE(tspace, prodp, hsize, tspace + size); + + /* Add/copy product H */ + MPN_COPY(prodp + hsize, prodp + size, hsize); + cy = mpihelp_add_n(prodp + size, prodp + size, + prodp + size + hsize, hsize); + + /* Add product M (if NEGFLG M is a negative number). */ + cy -= mpihelp_sub_n (prodp + hsize, prodp + hsize, tspace, size); + + /* Product L. ________________ ________________ + * |________________||____U0 x U0_____| + * Read temporary operands from low part of PROD. + * Put result in low part of TSPACE using upper part of TSPACE + * as new TSPACE. */ + MPN_SQR_N_RECURSE (tspace, up, hsize, tspace + size); + + /* Add/copy Product L (twice). */ + cy += mpihelp_add_n (prodp + hsize, prodp + hsize, tspace, size); + if( cy ) + mpihelp_add_1(prodp + hsize + size, prodp + hsize + size, + hsize, cy); + + MPN_COPY(prodp, tspace, hsize); + cy = mpihelp_add_n (prodp + hsize, prodp + hsize, tspace + hsize, hsize); + if( cy ) + mpihelp_add_1 (prodp + size, prodp + size, size, 1); + } +} + + +/* This should be made into an inline function in gmp.h. */ +void +mpihelp_mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size) +{ + if( up == vp ) { + if( size < KARATSUBA_THRESHOLD ) + sqr_n_basecase( prodp, up, size ); + else { + mpi_ptr_t tspace; + tspace = mpi_alloc_limb_space( 2 * size ); + sqr_n( prodp, up, size, tspace ); + mpi_free_limb_space( tspace ); + } + } + else { + if( size < KARATSUBA_THRESHOLD ) + mul_n_basecase( prodp, up, vp, size ); + else { + mpi_ptr_t tspace; + tspace = mpi_alloc_limb_space( 2 * size ); + mul_n (prodp, up, vp, size, tspace); + mpi_free_limb_space( tspace ); + } + } +} + + +/* Multiply the natural numbers u (pointed to by UP, with USIZE limbs) + * and v (pointed to by VP, with VSIZE limbs), and store the result at + * PRODP. USIZE + VSIZE limbs are always stored, but if the input + * operands are normalized. Return the most significant limb of the + * result. + * + * NOTE: The space pointed to by PRODP is overwritten before finished + * with U and V, so overlap is an error. + * + * Argument constraints: + * 1. USIZE >= VSIZE. + * 2. PRODP != UP and PRODP != VP, i.e. the destination + * must be distinct from the multiplier and the multiplicand. + */ + +mpi_limb_t +mpihelp_mul( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize, + mpi_ptr_t vp, mpi_size_t vsize) +{ + mpi_ptr_t prod_endp = prodp + usize + vsize - 1; + mpi_limb_t cy; + mpi_ptr_t tspace; + + if( vsize < KARATSUBA_THRESHOLD ) { + mpi_size_t i; + mpi_limb_t v_limb; + + if( !vsize ) + return 0; + + /* Multiply by the first limb in V separately, as the result can be + * stored (not added) to PROD. We also avoid a loop for zeroing. */ + v_limb = vp[0]; + if( v_limb <= 1 ) { + if( v_limb == 1 ) + MPN_COPY( prodp, up, usize ); + else + MPN_ZERO( prodp, usize ); + cy = 0; + } + else + cy = mpihelp_mul_1( prodp, up, usize, v_limb ); + + prodp[usize] = cy; + prodp++; + + /* For each iteration in the outer loop, multiply one limb from + * U with one limb from V, and add it to PROD. */ + for( i = 1; i < vsize; i++ ) { + v_limb = vp[i]; + if( v_limb <= 1 ) { + cy = 0; + if( v_limb == 1 ) + cy = mpihelp_add_n(prodp, prodp, up, usize); + } + else + cy = mpihelp_addmul_1(prodp, up, usize, v_limb); + + prodp[usize] = cy; + prodp++; + } + + return cy; + } + + tspace = mpi_alloc_limb_space( 2 * vsize ); + MPN_MUL_N_RECURSE( prodp, up, vp, vsize, tspace ); + + prodp += vsize; + up += vsize; + usize -= vsize; + if( usize >= vsize ) { + mpi_ptr_t tp = mpi_alloc_limb_space( 2 * vsize ); + do { + MPN_MUL_N_RECURSE( tp, up, vp, vsize, tspace ); + cy = mpihelp_add_n( prodp, prodp, tp, vsize ); + mpihelp_add_1( prodp + vsize, tp + vsize, vsize, cy ); + prodp += vsize; + up += vsize; + usize -= vsize; + } while( usize >= vsize ); + mpi_free_limb_space( tp ); + } + + if( usize ) { + mpihelp_mul( tspace, vp, vsize, up, usize ); + cy = mpihelp_add_n( prodp, prodp, tspace, vsize); + mpihelp_add_1( prodp + vsize, tspace + vsize, usize, cy ); + } + + mpi_free_limb_space( tspace ); + return *prod_endp; +} + + diff --git a/mpi/mpih-shift.c b/mpi/mpih-shift.c new file mode 100644 index 000000000..a8fe26aa2 --- /dev/null +++ b/mpi/mpih-shift.c @@ -0,0 +1,94 @@ +/* mpihelp-shift.c - MPI helper functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi-internal.h" + +/* Shift U (pointed to by UP and USIZE digits long) CNT bits to the left + * and store the USIZE least significant digits of the result at WP. + * Return the bits shifted out from the most significant digit. + * + * Argument constraints: + * 1. 0 < CNT < BITS_PER_MP_LIMB + * 2. If the result is to be written over the input, WP must be >= UP. + */ + +mpi_limb_t +mpihelp_lshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, + unsigned int cnt) +{ + mpi_limb_t high_limb, low_limb; + unsigned sh_1, sh_2; + mpi_size_t i; + mpi_limb_t retval; + + sh_1 = cnt; + wp += 1; + sh_2 = BITS_PER_MPI_LIMB - sh_1; + i = usize - 1; + low_limb = up[i]; + retval = low_limb >> sh_2; + high_limb = low_limb; + while( --i >= 0 ) { + low_limb = up[i]; + wp[i] = (high_limb << sh_1) | (low_limb >> sh_2); + high_limb = low_limb; + } + wp[i] = high_limb << sh_1; + + return retval; +} + + +/* Shift U (pointed to by UP and USIZE limbs long) CNT bits to the right + * and store the USIZE least significant limbs of the result at WP. + * The bits shifted out to the right are returned. + * + * Argument constraints: + * 1. 0 < CNT < BITS_PER_MP_LIMB + * 2. If the result is to be written over the input, WP must be <= UP. + */ + +mpi_limb_t +mpihelp_rshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned cnt) +{ + mpi_limb_t high_limb, low_limb; + unsigned sh_1, sh_2; + mpi_size_t i; + mpi_limb_t retval; + + sh_1 = cnt; + wp -= 1; + sh_2 = BITS_PER_MPI_LIMB - sh_1; + high_limb = up[0]; + retval = high_limb << sh_2; + low_limb = high_limb; + for( i=1; i < usize; i++) { + high_limb = up[i]; + wp[i] = (low_limb >> sh_1) | (high_limb << sh_2); + low_limb = high_limb; + } + wp[i] = low_limb >> sh_1; + + return retval; +} + diff --git a/mpi/mpih-sub.c b/mpi/mpih-sub.c new file mode 100644 index 000000000..3831d81c3 --- /dev/null +++ b/mpi/mpih-sub.c @@ -0,0 +1,106 @@ +/* mpihelp-sub.c - MPI helper functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> + +#include "mpi-internal.h" + + +/*_EXTERN_INLINE*/ +mpi_limb_t +mpihelp_sub_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_size_t s1_size, mpi_limb_t s2_limb ) +{ + mpi_limb_t x; + + x = *s1_ptr++; + s2_limb = x - s2_limb; + *res_ptr++ = s2_limb; + if( s2_limb > x ) { + while( --s1_size ) { + x = *s1_ptr++; + *res_ptr++ = x - 1; + if( x ) + goto leave; + } + return 1; + } + + leave: + if( res_ptr != s1_ptr ) { + mpi_size_t i; + for( i=0; i < s1_size-1; i++ ) + res_ptr[i] = s1_ptr[i]; + } + return 0; +} + + +/* FIXME: this should be done in assembly */ +mpi_limb_t +mpihelp_sub_n( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, + mpi_ptr_t s2_ptr, mpi_size_t size) +{ + mpi_limb_t x, y, cy; + mpi_size_t j; + + /* The loop counter and index J goes from -SIZE to -1. This way + the loop becomes faster. */ + j = -size; + + /* Offset the base pointers to compensate for the negative indices. */ + s1_ptr -= j; + s2_ptr -= j; + res_ptr -= j; + + cy = 0; + do { + y = s2_ptr[j]; + x = s1_ptr[j]; + y += cy; /* add previous carry to subtrahend */ + cy = y < cy ? 1:0; /* get out carry from that addition */ + y = x - y; /* main subtract */ + cy += y > x? 1:0; /* get out carry from the subtract, combine */ + res_ptr[j] = y; + } while( ++j ); + + return cy; +} + + +/*_EXTERN_INLINE*/ +mpi_limb_t +mpihelp_sub( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, + mpi_ptr_t s2_ptr, mpi_size_t s2_size) +{ + mpi_limb_t cy = 0; + + if( s2_size ) + cy = mpihelp_sub_n(res_ptr, s1_ptr, s2_ptr, s2_size); + + if( s1_size - s2_size ) + cy = mpihelp_sub_1(res_ptr + s2_size, s1_ptr + s2_size, + s1_size - s2_size, cy); + return cy; +} + + diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c new file mode 100644 index 000000000..752ce7f84 --- /dev/null +++ b/mpi/mpiutil.c @@ -0,0 +1,326 @@ +/* mpiutil.c - Utility functions for MPI + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "mpi.h" +#include "mpi-internal.h" +#include "memory.h" +#include "util.h" + + +#ifdef M_DEBUG + #undef mpi_alloc + #undef mpi_alloc_secure + #undef mpi_free +#endif + +typedef struct unused_obj { + struct unused_obj *next; + unsigned length; + union { + MPI mpi; + mpi_limb_t *limb; + } u; +} *unused_obj_t; + +static unused_obj_t unused_objs; +static unused_obj_t unused_mpis; +static unused_obj_t unused_limbs; + + +MPI +#ifdef M_DEBUG +mpi_debug_alloc( unsigned nlimbs, const char *info ) +#else +mpi_alloc( unsigned nlimbs ) +#endif +{ + MPI a; + + if( unused_mpis ) { + unused_obj_t u; + + if( DBG_MEMORY ) + log_debug("mpi_alloc(%lu) reusing\n", nlimbs*BITS_PER_MPI_LIMB ); + a = unused_mpis->u.mpi; + u = unused_mpis; + unused_mpis = unused_mpis->next; + u->next = unused_objs; + unused_objs = u; + } + else { + if( DBG_MEMORY ) + log_debug("mpi_alloc(%lu) new\n", nlimbs*BITS_PER_MPI_LIMB ); + #ifdef M_DEBUG + a = m_debug_alloc( sizeof *a, info ); + #else + a = m_alloc( sizeof *a ); + #endif + } + #ifdef M_DEBUG + a->d = mpi_debug_alloc_limb_space( nlimbs, info ); + #else + a->d = mpi_alloc_limb_space( nlimbs ); + #endif + a->alloced = nlimbs; + a->nlimbs = 0; + a->sign = 0; + return a; +} + +void +mpi_m_check( MPI a ) +{ + m_check(a); + m_check(a->d); +} + +MPI +#ifdef M_DEBUG +mpi_debug_alloc_secure( unsigned nlimbs, const char *info ) +#else +mpi_alloc_secure( unsigned nlimbs ) +#endif +{ + MPI a; + + a = m_alloc( sizeof *a ); + #ifdef M_DEBUG + a->d = m_debug_alloc_secure( nlimbs * sizeof(mpi_limb_t), info ); + #else + a->d = m_alloc_secure( nlimbs * sizeof(mpi_limb_t) ); + #endif + a->alloced = nlimbs; + a->nlimbs = 0; + a->sign = 0; + return a; +} + + +mpi_ptr_t +#ifdef M_DEBUG +mpi_debug_alloc_limb_space( unsigned nlimbs, const char *info ) +#else +mpi_alloc_limb_space( unsigned nlimbs ) +#endif +{ + unused_obj_t u; + size_t len = nlimbs * sizeof(mpi_limb_t); + + for(u=unused_limbs; u; u = u->next ) + if( u->length >= len ) { + u->length = 0; + if( DBG_MEMORY ) + log_debug("mpi_alloc_limb_space(%lu) reusing\n", len*8 ); + return u->u.limb; + } + if( DBG_MEMORY ) + log_debug("mpi_alloc_limb_space(%u) new\n", len*8 ); + #ifdef M_DEBUG + return m_debug_alloc( len, info ); + #else + return m_alloc( len ); + #endif +} + +void +#ifdef M_DEBUG +mpi_debug_free_limb_space( mpi_ptr_t a, const char *info ) +#else +mpi_free_limb_space( mpi_ptr_t a ) +#endif +{ + unused_obj_t u; + + if( !a ) + return; + if( DBG_MEMORY ) + log_debug("mpi_free_limb_space of size %lu\n", (ulong)m_size(a)*8 ); + for(u=unused_limbs; u; u = u->next ) + if( !u->length ) { + u->length = m_size(a); + u->u.limb = a; + return; + } + + if( (u=unused_objs) ) + unused_objs = unused_objs->next; + else + u = m_alloc( sizeof *u ); + u->length = m_size(a); + u->u.limb = a; + u->next = unused_limbs; + unused_limbs = u; +} + + +void +mpi_assign_limb_space( MPI a, mpi_ptr_t ap, unsigned nlimbs ) +{ + mpi_free_limb_space(a->d); + a->d = ap; + a->alloced = nlimbs; +} + + + +/**************** + * Resize the array of A to NLIMBS. the additional space is cleared + * (set to 0) [done by m_realloc()] + */ +void +#ifdef M_DEBUG +mpi_debug_resize( MPI a, unsigned nlimbs, const char *info ) +#else +mpi_resize( MPI a, unsigned nlimbs ) +#endif +{ + if( nlimbs <= a->alloced ) + return; /* no need to do it */ + #ifdef M_DEBUG + if( a->d ) + a->d = m_debug_realloc(a->d, nlimbs * sizeof(mpi_limb_t), info ); + else + a->d = m_debug_alloc_clear( nlimbs * sizeof(mpi_limb_t), info ); + #else + if( a->d ) + a->d = m_realloc(a->d, nlimbs * sizeof(mpi_limb_t) ); + else + a->d = m_alloc_clear( nlimbs * sizeof(mpi_limb_t) ); + #endif + a->alloced = nlimbs; +} + +void +mpi_clear( MPI a ) +{ + a->nlimbs = 0; +} + + +void +#ifdef M_DEBUG +mpi_debug_free( MPI a, const char *info ) +#else +mpi_free( MPI a ) +#endif +{ + unused_obj_t u; + + if( !a ) + return; + if( DBG_MEMORY ) + log_debug("mpi_free\n" ); + #ifdef M_DEBUG + mpi_debug_free_limb_space(a->d, info); + #else + mpi_free_limb_space(a->d); + #endif + + if( (u=unused_objs) ) + unused_objs = unused_objs->next; + else + u = m_alloc( sizeof *u ); + u->u.mpi = a; + u->next = unused_mpis; + unused_mpis = u; +} + + +MPI +#ifdef M_DEBUG +mpi_debug_copy( MPI a, const char *info ) +#else +mpi_copy( MPI a ) +#endif +{ + int i; + MPI b; + + if( a ) { + #ifdef M_DEBUG + b = mpi_debug_alloc( a->nlimbs, info ); + #else + b = mpi_alloc( a->nlimbs ); + #endif + b->nlimbs = a->nlimbs; + for(i=0; i < b->nlimbs; i++ ) + b->d[i] = a->d[i]; + } + else + b = NULL; + return b; +} + + +void +mpi_set( MPI w, MPI u) +{ + mpi_ptr_t wp, up; + mpi_size_t usize = u->nlimbs; + int usign = u->sign; + + RESIZE_IF_NEEDED(w, usize); + wp = w->d; + up = u->d; + MPN_COPY( wp, up, usize ); + w->nlimbs = usize; + w->sign = usign; +} + + +void +mpi_set_ui( MPI w, unsigned long u) +{ + RESIZE_IF_NEEDED(w, 1); + w->d[0] = u; + w->nlimbs = u? 1:0; + w->sign = 0; +} + + +MPI +mpi_alloc_set_ui( unsigned long u) +{ + #ifdef M_DEBUG + MPI w = mpi_debug_alloc(1,"alloc_set_ui"); + #else + MPI w = mpi_alloc(1); + #endif + w->d[0] = u; + w->nlimbs = u? 1:0; + w->sign = 0; + return w; +} + + +void +mpi_swap( MPI a, MPI b) +{ + MPI x; + + x = a; a = b; b = x; +} + + diff --git a/scripts/install-sh b/scripts/install-sh new file mode 100755 index 000000000..e8436696c --- /dev/null +++ b/scripts/install-sh @@ -0,0 +1,250 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/scripts/mkinstalldirs b/scripts/mkinstalldirs new file mode 100755 index 000000000..d0fd194fd --- /dev/null +++ b/scripts/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Public domain + +# $Id$ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 000000000..9788f7023 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 000000000..a23b8d349 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,12 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +bin_PROGRAMS = mpicalc + +mpicalc_SOURCES = mpicalc.c + + +LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil + + diff --git a/tools/Makefile.in b/tools/Makefile.in new file mode 100644 index 000000000..b9f55a889 --- /dev/null +++ b/tools/Makefile.in @@ -0,0 +1,252 @@ +# Makefile.in generated automatically by automake 1.0 from Makefile.am + +# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +INCLUDES = -I$(top_srcdir)/include + +bin_PROGRAMS = mpicalc + +mpicalc_SOURCES = mpicalc.c + +LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil +mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs +CONFIG_HEADER = ../config.h +PROGRAMS = $(bin_PROGRAMS) + + +CC = @CC@ +LEX = @LEX@ +YACC = @YACC@ + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(LDFLAGS) -o $@ +mpicalc_OBJECTS = mpicalc.o +EXTRA_mpicalc_SOURCES = +mpicalc_LDADD = $(LDADD) +DIST_COMMON = Makefile.am Makefile.in + + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA) +DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA) + +TAR = tar +DEP_FILES = $(srcdir)/.deps/mpicalc.P +SOURCES = $(mpicalc_SOURCES) +OBJECTS = $(mpicalc_OBJECTS) + +default: all + + +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in + cd $(top_srcdir) && automake $(subdir)/Makefile + +Makefile: $(top_builddir)/config.status Makefile.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + $(mkinstalldirs) $(bindir) + list="$(bin_PROGRAMS)"; for p in $$list; do \ + if test -f $$p; then \ + $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + list="$(bin_PROGRAMS)"; for p in $$list; do \ + rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \ + done + +.c.o: + $(COMPILE) $< + +mostlyclean-compile: + rm -f *.o core + +clean-compile: + +distclean-compile: + rm -f *.tab.c + +maintainer-clean-compile: +$(mpicalc_OBJECTS): ../config.h + +mpicalc: $(mpicalc_OBJECTS) $(mpicalc_DEPENDENCIES) + $(LINK) $(mpicalc_OBJECTS) $(mpicalc_LDADD) $(LIBS) + +ID: $(HEADERS) $(SOURCES) + here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS) + +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) + here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + rm -f TAGS ID + +maintainer-clean-tags: + +subdir = tools +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +distdir: $(DEP_DISTFILES) + @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \ + test -f $(distdir)/$$file \ + || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $(srcdir)/$$file $(distdir)/$$file; \ + done + +# This fragment is probably only useful for maintainers. It relies on +# GNU make and gcc. It is only included in the generated Makefile.in +# if `automake' is not passed the `--include-deps' flag. + +MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) + +-include $(srcdir)/.deps/.P +$(srcdir)/.deps/.P: $(BUILT_SOURCES) + cd $(srcdir) && test -d .deps || mkdir .deps + echo > $@ + +-include $(DEP_FILES) +$(DEP_FILES): $(srcdir)/.deps/.P + +$(srcdir)/.deps/%.P: $(srcdir)/%.c + @echo "mkdeps $< > $@" + @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \ + $(MKDEP) $< | sed "$$re" > $@-tmp + @if test -n "$o"; then \ + sed 's/\.o:/$$o:/' $@-tmp > $@; \ + rm $@-tmp; \ + else \ + mv $@-tmp $@; \ + fi + +# End of maintainer-only section +info: + +dvi: + +check: all + +installcheck: + +install-exec: install-binPROGRAMS + +install-data: + +install: install-exec install-data all + @: + +uninstall: uninstall-binPROGRAMS + +all: $(PROGRAMS) Makefile + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install +installdirs: + $(mkinstalldirs) $(bindir) + + +mostlyclean-generic: + test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + rm -f Makefile $(DISTCLEANFILES) + rm -f config.cache config.log $(CONFIG_HEADER) stamp-h + +maintainer-clean-generic: + test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +clean: clean-binPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean + +distclean: distclean-binPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean + rm -f config.status + +maintainer-clean: maintainer-clean-binPROGRAMS maintainer-clean-compile \ + maintainer-clean-tags maintainer-clean-generic \ + distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: default mostlyclean-binPROGRAMS distclean-binPROGRAMS \ +clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \ +install-binPROGRAMS mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info dvi check installcheck \ +install-exec install-data install uninstall all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + +.SUFFIXES: +.SUFFIXES: .c .o + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tools/bftest.c b/tools/bftest.c new file mode 100644 index 000000000..bbfcd5dd1 --- /dev/null +++ b/tools/bftest.c @@ -0,0 +1,85 @@ +/* bftest.c - Blowfish test program + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "util.h" +#include "blowfish.h" + +static void +my_usage(void) +{ + fprintf(stderr, "usage: bftest [-e][-d] key\n"); + exit(1); +} + +const char * +strusage( int level ) +{ + return default_strusage(level); +} + +int +main(int argc, char **argv) +{ + int encode=0; + BLOWFISH_context ctx; + char buf[100]; + char iv[BLOWFISH_BLOCKSIZE]; + int n, size=8; + + if( argc > 1 && !strcmp(argv[1], "-e") ) { + encode++; + argc--; argv++; + } + else if( argc > 1 && !strcmp(argv[1], "-E") ) { + encode++; + argc--; argv++; + size = 10; + } + else if( argc > 1 && !strcmp(argv[1], "-d") ) { + argc--; argv++; + } + else if( argc > 1 && !strcmp(argv[1], "-D") ) { + argc--; argv++; + size = 10; + } + if( argc != 2 ) + my_usage(); + argc--; argv++; + + blowfish_setkey( &ctx, *argv, strlen(*argv) ); + memset(iv,0, BLOWFISH_BLOCKSIZE); + blowfish_setiv( &ctx, iv ); + while( (n = fread( buf, 1, size, stdin )) > 0 ) { + if( encode ) + blowfish_encode_cfb( &ctx, buf, buf, n ); + else + blowfish_decode_cfb( &ctx, buf, buf, n ); + if( fwrite( buf, 1, n, stdout) != n ) + log_fatal("write error\n"); + } + + return 0; +} + diff --git a/tools/mpicalc.c b/tools/mpicalc.c new file mode 100644 index 000000000..2402695d7 --- /dev/null +++ b/tools/mpicalc.c @@ -0,0 +1,341 @@ +/* mpitest.c - test the mpi functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This is a RPN calculator; values must be given in hex. + * Operaion is like dc(1) except that the input/output radix is + * always 16 and you can use a '-' to prefix a negative number. + * Addition operators: ++ and --. All operators must be delimeted by a blank + * + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +#include "util.h" +#include "mpi.h" + +#define STACKSIZE 100 +static MPI stack[STACKSIZE]; +static int stackidx; + + +const char * +strusage( int level ) +{ + const char *p; + switch( level ) { + case 10: + case 0: p = "mpicalc - v" VERSION "; " + "Copyright 1997 Werner Koch (dd9jn)" ; break; + case 13: p = "mpicalc"; break; + case 14: p = VERSION; break; + case 1: + case 11: p = "Usage: mpicalc (-h for help)"; + break; + case 2: + case 12: p = + "\nSyntax: mpicalc [options] [files]\n" + "MPI RPN calculator\n"; + break; + default: p = default_strusage(level); + } + return p; +} + + +static void +do_add(void) +{ + if( stackidx < 2 ) { + fputs("stack underflow\n",stderr); + return; + } + mpi_add( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] ); + stackidx--; +} + +static void +do_sub(void) +{ + if( stackidx < 2 ) { + fputs("stack underflow\n", stderr); + return; + } + mpi_sub( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] ); + stackidx--; +} + +static void +do_inc(void) +{ + if( stackidx < 1 ) { + fputs("stack underflow\n", stderr); + return; + } + mpi_add_ui( stack[stackidx-1], stack[stackidx-1], 1 ); +} + +static void +do_dec(void) +{ + if( stackidx < 1 ) { + fputs("stack underflow\n", stderr); + return; + } + /* mpi_sub_ui( stack[stackidx-1], stack[stackidx-1], 1 ); */ +} + +static void +do_mul(void) +{ + if( stackidx < 2 ) { + fputs("stack underflow\n", stderr); + return; + } + mpi_mul( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] ); + stackidx--; +} + +static void +do_div(void) +{ + if( stackidx < 2 ) { + fputs("stack underflow\n", stderr); + return; + } + mpi_fdiv_q( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] ); + stackidx--; +} + +static void +do_rem(void) +{ + if( stackidx < 2 ) { + fputs("stack underflow\n", stderr); + return; + } + mpi_fdiv_r( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] ); + stackidx--; +} + +static void +do_powm(void) +{ + MPI a; + if( stackidx < 3 ) { + fputs("stack underflow\n", stderr); + return; + } + a= mpi_alloc(10); + mpi_powm( a, stack[stackidx-3], stack[stackidx-2], stack[stackidx-1] ); + mpi_free(stack[stackidx-3]); + stack[stackidx-3] = a; + stackidx -= 2; +} + +static void +do_inv(void) +{ + MPI a = mpi_alloc(40); + if( stackidx < 2 ) { + fputs("stack underflow\n", stderr); + return; + } + mpi_inv_mod( a, stack[stackidx-2], stack[stackidx-1] ); + mpi_set(stack[stackidx-2],a); + mpi_free(a); + stackidx--; +} + +static void +do_gcd(void) +{ + MPI a = mpi_alloc(40); + if( stackidx < 2 ) { + fputs("stack underflow\n", stderr); + return; + } + mpi_gcd( a, stack[stackidx-2], stack[stackidx-1] ); + mpi_set(stack[stackidx-2],a); + mpi_free(a); + stackidx--; +} + + +int +main(int argc, char **argv) +{ + static ARGPARSE_OPTS opts[] = { + {0} }; + ARGPARSE_ARGS pargs = { &argc, &argv, 0 }; + int i, c; + int state = 0; + char strbuf[1000]; + int stridx=0; + + while( arg_parse( &pargs, opts) ) { + switch( pargs.r_opt ) { + default : pargs.err = 2; break; + } + } + if( argc ) + usage(1); + + + for(i=0; i < STACKSIZE; i++ ) + stack[i] = NULL; + stackidx =0; + + while( (c=getc(stdin)) != EOF ) { + if( !state ) { /* waiting */ + if( isdigit(c) || (c >='A' && c <= 'F') ) { + state = 1; + ungetc(c, stdin); + strbuf[0] = '0'; + strbuf[1] = 'x'; + stridx=2; + } + else if( isspace(c) ) + ; + else { + switch(c) { + case '+': + if( (c=getc(stdin)) == '+' ) + do_inc(); + else { + ungetc(c, stdin); + do_add(); + } + break; + case '-': + if( (c=getc(stdin)) == '-' ) + do_dec(); + else if( isdigit(c) || (c >='A' && c <= 'F') ) { + state = 1; + ungetc(c, stdin); + strbuf[0] = '-'; + strbuf[1] = '0'; + strbuf[2] = 'x'; + stridx=3; + } + else { + ungetc(c, stdin); + do_sub(); + } + break; + case '*': + do_mul(); + break; + case '/': + do_div(); + break; + case '%': + do_rem(); + break; + case '^': + do_powm(); + break; + case 'I': + do_inv(); + break; + case 'G': + do_gcd(); + break; + case 'i': /* dummy */ + if( !stackidx ) + fputs("stack underflow\n", stderr); + else { + mpi_free(stack[stackidx-1]); + stackidx--; + } + break; + case 'd': /* duplicate the tos */ + if( !stackidx ) + fputs("stack underflow\n", stderr); + else if( stackidx < STACKSIZE ) { + mpi_free(stack[stackidx]); + stack[stackidx] = mpi_copy( stack[stackidx-1] ); + stackidx++; + } + else + fputs("stack overflow\n", stderr); + break; + case 'c': + for(i=0; i < stackidx; i++ ) + mpi_free(stack[i]), stack[i] = NULL; + stackidx = 0; + break; + case 'p': /* print the tos */ + if( !stackidx ) + puts("stack is empty"); + else { + mpi_print(stdout, stack[stackidx-1], 1 ); + putchar('\n'); + } + break; + case 'f': /* print the stack */ + for( i = stackidx-1 ; i >= 0; i-- ) { + printf("[%2d]: ", i ); + mpi_print(stdout, stack[i], 1 ); + putchar('\n'); + } + break; + default: + fputs("invalid operator\n", stderr); + } + } + } + else if( state == 1 ) { /* in a number */ + if( !(isdigit(c) || (c >='A' && c <= 'F')) ) { /* store the number */ + state = 0; + ungetc(c, stdin); + if( stridx < 1000 ) + strbuf[stridx] = 0; + + if( stackidx < STACKSIZE ) { + if( !stack[stackidx] ) + stack[stackidx] = mpi_alloc(10); + if( mpi_fromstr(stack[stackidx], strbuf) ) + fputs("invalid number\n", stderr); + else + stackidx++; + } + else + fputs("stack overflow\n", stderr); + } + else { /* store digit */ + if( stridx < 999 ) + strbuf[stridx++] = c; + else if( stridx == 999 ) { + strbuf[stridx] = 0; + fputs("string too large - truncated\n", stderr); + stridx++; + } + } + } + + } + for(i=0; i < stackidx; i++ ) + mpi_free(stack[i]); + return 0; +} + + diff --git a/tools/primes.scm b/tools/primes.scm new file mode 100644 index 000000000..0772cdcf9 --- /dev/null +++ b/tools/primes.scm @@ -0,0 +1,31 @@ +(define (prime? n) + (define (smallest-divisor n) + (find-divisor n 2)) + (define (find-divisor n test) + (cond ((> (square test) n) n) + ((divides? test n) test) + (else (find-divisor n (+ test 1))))) + (define (divides? a b) + (= (remainder b a) 0)) + (define (square n) + (* n n)) + (= n (smallest-divisor n))) + +(define count 0) + + + +(define (display-prime n) + (display n) + (display ", ") + (cond ((> count 8) (display "\n") (let count 0)) + (else (define count (+ count 1))))) + + +(define (primes n limit) + (if (prime? n) + (display-prime n) ) + (if (< n limit) + (primes (+ n 1) limit)) ) + +(primes 3 5000) diff --git a/util/Makefile.am b/util/Makefile.am new file mode 100644 index 000000000..5fd3e59ca --- /dev/null +++ b/util/Makefile.am @@ -0,0 +1,13 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +noinst_LIBRARIES = util + + +util_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \ + ttyio.c argparse.c memory.c errors.c iobuf.c + + + + diff --git a/util/Makefile.in b/util/Makefile.in new file mode 100644 index 000000000..ca24380d6 --- /dev/null +++ b/util/Makefile.in @@ -0,0 +1,248 @@ +# Makefile.in generated automatically by automake 1.0 from Makefile.am + +# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +INCLUDES = -I$(top_srcdir)/include + +noinst_LIBRARIES = util + +util_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \ + ttyio.c argparse.c memory.c errors.c iobuf.c +mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs +CONFIG_HEADER = ../config.h +LIBRARIES = $(noinst_LIBRARIES) + +noinst_LIBFILES = libutil.a + +CC = @CC@ +LEX = @LEX@ +YACC = @YACC@ + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(LDFLAGS) -o $@ +util_LIBADD = +util_OBJECTS = logger.o fileutil.o miscutil.o strgutil.o ttyio.o \ +argparse.o memory.o errors.o iobuf.o +EXTRA_util_SOURCES = +LIBFILES = libutil.a +AR = ar +RANLIB = @RANLIB@ +DIST_COMMON = Makefile.am Makefile.in + + +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA) +DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \ + $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA) + +TAR = tar +DEP_FILES = $(srcdir)/.deps/argparse.P $(srcdir)/.deps/errors.P \ +$(srcdir)/.deps/fileutil.P $(srcdir)/.deps/iobuf.P \ +$(srcdir)/.deps/logger.P $(srcdir)/.deps/memory.P \ +$(srcdir)/.deps/miscutil.P $(srcdir)/.deps/strgutil.P \ +$(srcdir)/.deps/ttyio.P +SOURCES = $(util_SOURCES) +OBJECTS = $(util_OBJECTS) + +default: all + + +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in + cd $(top_srcdir) && automake $(subdir)/Makefile + +Makefile: $(top_builddir)/config.status Makefile.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + rm -f $(noinst_LIBFILES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) $< + +mostlyclean-compile: + rm -f *.o core + +clean-compile: + +distclean-compile: + rm -f *.tab.c + +maintainer-clean-compile: +$(util_OBJECTS): ../config.h + +libutil.a: $(util_OBJECTS) $(util_LIBADD) + rm -f libutil.a + $(AR) cru libutil.a $(util_OBJECTS) $(util_LIBADD) + $(RANLIB) libutil.a + +ID: $(HEADERS) $(SOURCES) + here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS) + +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) + here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + rm -f TAGS ID + +maintainer-clean-tags: + +subdir = util +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) +distdir: $(DEP_DISTFILES) + @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \ + test -f $(distdir)/$$file \ + || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $(srcdir)/$$file $(distdir)/$$file; \ + done + +# This fragment is probably only useful for maintainers. It relies on +# GNU make and gcc. It is only included in the generated Makefile.in +# if `automake' is not passed the `--include-deps' flag. + +MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) + +-include $(srcdir)/.deps/.P +$(srcdir)/.deps/.P: $(BUILT_SOURCES) + cd $(srcdir) && test -d .deps || mkdir .deps + echo > $@ + +-include $(DEP_FILES) +$(DEP_FILES): $(srcdir)/.deps/.P + +$(srcdir)/.deps/%.P: $(srcdir)/%.c + @echo "mkdeps $< > $@" + @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \ + $(MKDEP) $< | sed "$$re" > $@-tmp + @if test -n "$o"; then \ + sed 's/\.o:/$$o:/' $@-tmp > $@; \ + rm $@-tmp; \ + else \ + mv $@-tmp $@; \ + fi + +# End of maintainer-only section +info: + +dvi: + +check: all + +installcheck: + +install-exec: + +install-data: + +install: install-exec install-data all + @: + +uninstall: + +all: $(LIBFILES) Makefile + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install +installdirs: + + +mostlyclean-generic: + test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + rm -f Makefile $(DISTCLEANFILES) + rm -f config.cache config.log $(CONFIG_HEADER) stamp-h + +maintainer-clean-generic: + test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean + +distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \ + distclean-generic clean + rm -f config.status + +maintainer-clean: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info dvi check installcheck \ +install-exec install-data install uninstall all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + +.SUFFIXES: +.SUFFIXES: .c .o + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/util/argparse.c b/util/argparse.c new file mode 100644 index 000000000..3d51d014c --- /dev/null +++ b/util/argparse.c @@ -0,0 +1,653 @@ +/* [argparse.c wk 17.06.97] Argument Parser for option handling + * Copyright (c) 1997 by Werner Koch (dd9jn) + * This file is part of WkLib. + * + * WkLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * WkLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * Note: This is an independent version of the one in WkLib + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "util.h" + +#ifdef DOCUMENTATION +@Summary arg_parse + #include <wk/lib.h> + + typedef struct { + char *argc; /* pointer to argc (value subject to change) */ + char ***argv; /* pointer to argv (value subject to change) */ + unsigned flags; /* Global flags (DO NOT CHANGE) */ + int err; /* print error about last option */ + /* 1 = warning, 2 = abort */ + int r_opt; /* return option */ + int r_type; /* type of return value (0 = no argument found)*/ + union { + int ret_int; + long ret_long + ulong ret_ulong; + char *ret_str; + } r; /* Return values */ + struct { + int index; + const char *last; + } internal; /* DO NOT CHANGE */ + } ARGPARSE_ARGS; + + typedef struct { + int short_opt; + const char *long_opt; + unsigned flags; + } ARGPARSE_OPTS; + + int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts ); + +@Description + This is my replacement for getopt(). See the example for a typical usage. + Global flags are: + Bit 0 : Do not remove options form argv + Bit 1 : Do not stop at last option but return other args + with r_opt set to -1. + Bit 2 : Assume options and real args are mixed. + Bit 3 : Do not use -- to stop option processing. + Bit 4 : Do not skip the first arg. + Bit 5 : allow usage of long option with only one dash + all other bits must be set to zero, this value is modified by the function + so assume this is write only. + Local flags (for each option): + Bit 2-0 : 0 = does not take an argument + 1 = takes int argument + 2 = takes string argument + 3 = takes long argument + 4 = takes ulong argument + Bit 3 : argument is optional (r_type will the be set to 0) + Bit 4 : allow 0x etc. prefixed values. + If can stop the option processing by setting opts to NULL, the function will + then return 0. +@Return Value + Returns the args.r_opt or 0 if ready + r_opt may be -2 to indicate an unknown option. +@See Also + ArgExpand +@Notes + You do not need to process the options 'h', '--help' or '--version' + because this function includes standard help processing; but if you + specify '-h', '--help' or '--version' you have to do it yourself. + The option '--' stops argument processing; if bit 1 is set the function + continues to return normal arguments. + To process float args or unsigned args you must use a string args and do + the conversion yourself. +@Example + + ARGPARSE_OPTS opts[] = { + { 'v', "verbose", 0 }, + { 'd', "debug", 0 }, + { 'o', "output", 2 }, + { 'c', "cross-ref", 2|8 }, + { 'm', "my-option", 1|8 }, + { 500, "have-no-short-option-for-this-long-option", 0 }, + {0} }; + ARGPARSE_ARGS pargs = { &argc, &argv, 0 } + + while( ArgParse( &pargs, &opts) ) { + switch( pargs.r_opt ) { + case 'v': opt.verbose++; break; + case 'd': opt.debug++; break; + case 'o': opt.outfile = pargs.r.ret_str; break; + case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + case 500: opt.a_long_one++; break + default : pargs.err = 1; break; /* force warning output */ + } + } + if( argc > 1 ) + log_fatal( "Too many args"); + +#endif /*DOCUMENTATION*/ + + + +static void set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s); +static void show_help(ARGPARSE_OPTS *opts, unsigned flags); +static void show_version(void); + + +int +arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) +{ + int index; + int argc; + char **argv; + char *s, *s2; + int i; + + if( !(arg->flags & (1<<15)) ) { /* initialize this instance */ + arg->internal.index = 0; + arg->internal.last = NULL; + arg->internal.inarg = 0; + arg->internal.stopped= 0; + arg->err = 0; + arg->flags |= 1<<15; /* mark initialized */ + if( *arg->argc < 0 ) + log_bug("Invalid argument for ArgParse\n"); + } + argc = *arg->argc; + argv = *arg->argv; + index = arg->internal.index; + + if( arg->err ) { /* last option was erroneous */ + if( arg->r_opt == -3 ) + s = "Missing argument for option \"%.50s\"\n"; + else + s = "Invalid option \"%.50s\"\n"; + log_error(s, arg->internal.last? arg->internal.last:"[??]" ); + if( arg->err != 1 ) + exit(2); + arg->err = 0; + } + + if( !index && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */ + argc--; argv++; index++; + } + + next_one: + if( !argc ) { /* no more args */ + arg->r_opt = 0; + goto leave; /* ready */ + } + + s = *argv; + arg->internal.last = s; + + if( arg->internal.stopped && (arg->flags & (1<<1)) ) { + arg->r_opt = -1; /* not an option but a argument */ + arg->r_type = 2; + arg->r.ret_str = s; + argc--; argv++; index++; /* set to next one */ + } + else if( arg->internal.stopped ) { /* ready */ + arg->r_opt = 0; + goto leave; + } + else if( *s == '-' && s[1] == '-' ) { /* long option */ + arg->internal.inarg = 0; + if( !s[2] && !(arg->flags & (1<<3)) ) { /* stop option processing */ + arg->internal.stopped = 1; + argc--; argv++; index++; + goto next_one; + } + + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+2) ) + break; + + if( !opts[i].short_opt && !strcmp( "help", s+2) ) + show_help(opts, arg->flags); + else if( !opts[i].short_opt && !strcmp( "version", s+2) ) + show_version(); + else if( !opts[i].short_opt && !strcmp( "warranty", s+2) ) { + puts( strusage(10) ); + puts( strusage(31) ); + exit(0); + } + + arg->r_opt = opts[i].short_opt; + if( !opts[i].short_opt ) { + arg->r_opt = -2; /* unknown option */ + arg->r.ret_str = s+2; + } + else if( (opts[i].flags & 7) ) { + s2 = argv[1]; + if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/ + arg->r_type = 0; /* because it is optional */ + } + else if( !s2 ) { + arg->r_opt = -3; /* missing argument */ + } + else if( *s2 == '-' && (opts[i].flags & 8) ) { + /* the argument is optional and the next seems to be + * an option. We do not check this possible option + * but assume no argument */ + arg->r_type = 0; + } + else { + set_opt_arg(arg, opts[i].flags, s2); + argc--; argv++; index++; /* skip one */ + } + } + else { /* does not take an argument */ + arg->r_type = 0; + } + argc--; argv++; index++; /* set to next one */ + } + else if( (*s == '-' && s[1]) || arg->internal.inarg ) { /* short option */ + int dash_kludge = 0; + i = 0; + if( !arg->internal.inarg ) { + arg->internal.inarg++; + if( arg->flags & (1<<5) ) { + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+1)) { + dash_kludge=1; + break; + } + } + } + s += arg->internal.inarg; + + if( !dash_kludge ) { + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].short_opt == *s ) + break; + } + + if( !opts[i].short_opt && *s == 'h' ) + show_help(opts, arg->flags); + + arg->r_opt = opts[i].short_opt; + if( !opts[i].short_opt ) { + arg->r_opt = -2; /* unknown option */ + arg->internal.inarg++; /* point to the next arg */ + arg->r.ret_str = s; + } + else if( (opts[i].flags & 7) ) { + if( s[1] && !dash_kludge ) { + s2 = s+1; + set_opt_arg(arg, opts[i].flags, s2); + } + else { + s2 = argv[1]; + if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/ + arg->r_type = 0; /* because it is optional */ + } + else if( !s2 ) { + arg->r_opt = -3; /* missing argument */ + } + else if( *s2 == '-' && s2[1] && (opts[i].flags & 8) ) { + /* the argument is optional and the next seems to be + * an option. We do not check this possible option + * but assume no argument */ + arg->r_type = 0; + } + else { + set_opt_arg(arg, opts[i].flags, s2); + argc--; argv++; index++; /* skip one */ + } + } + s = "x"; /* so that !s[1] yields false */ + } + else { /* does not take an argument */ + arg->r_type = 0; + arg->internal.inarg++; /* point to the next arg */ + } + if( !s[1] || dash_kludge ) { /* no more concatenated short options */ + arg->internal.inarg = 0; + argc--; argv++; index++; + } + } + else if( arg->flags & (1<<2) ) { + arg->r_opt = -1; /* not an option but a argument */ + arg->r_type = 2; + arg->r.ret_str = s; + argc--; argv++; index++; /* set to next one */ + } + else { + arg->internal.stopped = 1; /* stop option processing */ + goto next_one; + } + + leave: + *arg->argc = argc; + *arg->argv = argv; + arg->internal.index = index; + return arg->r_opt; +} + + + +static void +set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s) +{ + int base = (flags & 16)? 0 : 10; + + switch( arg->r_type = (flags & 7) ) { + case 1: /* takes int argument */ + arg->r.ret_int = (int)strtol(s,NULL,base); + break; + default: + case 2: /* takes string argument */ + arg->r.ret_str = s; + break; + case 3: /* takes long argument */ + arg->r.ret_long= strtol(s,NULL,base); + break; + case 4: /* takes ulong argument */ + arg->r.ret_ulong= strtoul(s,NULL,base); + break; + } +} + +static void +show_help( ARGPARSE_OPTS *opts, unsigned flags ) +{ + const char *s; + + puts( strusage(10) ); + s = strusage(12); + if( *s == '\n' ) + s++; + puts(s); + if( opts[0].description ) { /* auto format the option description */ + int i,j, indent; + /* get max. length of long options */ + for(i=indent=0; opts[i].short_opt; i++ ) { + if( opts[i].long_opt ) + if( (j=strlen(opts[i].long_opt)) > indent && j < 35 ) + indent = j; + } + /* example: " -v, --verbose Viele Sachen ausgeben" */ + indent += 10; + puts("Options:"); + for(i=0; opts[i].short_opt; i++ ) { + if( opts[i].short_opt < 256 ) + printf(" -%c", opts[i].short_opt ); + else + fputs(" ", stdout); + j = 3; + if( opts[i].long_opt ) + j += printf("%c --%s ", opts[i].short_opt < 256?',':' ', + opts[i].long_opt ); + for(;j < indent; j++ ) + putchar(' '); + if( (s = opts[i].description) ) { + for(; *s; s++ ) { + if( *s == '\n' ) { + if( s[1] ) { + putchar('\n'); + for(j=0;j < indent; j++ ) + putchar(' '); + } + } + else + putchar(*s); + } + } + putchar('\n'); + } + if( flags & 32 ) + puts("\n(A single dash may be used instead of the double ones)"); + } + fflush(stdout); + exit(0); +} + +static void +show_version() +{ + const char *s; + printf("%s version %s (%s", strusage(13), strusage(14), strusage(45) ); + if( (s = strusage(24)) && *s ) { + #ifdef DEBUG + printf(", %s, dbg)\n", s); + #else + printf(", %s)\n", s); + #endif + } + else { + #ifdef DEBUG + printf(", dbg)\n"); + #else + printf(")\n"); + #endif + } + fflush(stdout); + exit(0); +} + + + +void +usage( int level ) +{ + static int sentinel=0; + + if( sentinel ) + return; + + sentinel++; + if( !level ) { + fputs( strusage(level), stderr ); putc( '\n', stderr ); + fputs( strusage(31), stderr); + #if DEBUG + fprintf(stderr, "%s (%s - Debug)\n", strusage(32), strusage(24) ); + #else + fprintf(stderr, "%s (%s)\n", strusage(32), strusage(24) ); + #endif + fflush(stderr); + } + else if( level == 1 ) { + fputs(strusage(level),stderr);putc('\n',stderr); + exit(2);} + else if( level == 2 ) { + puts(strusage(level)); exit(0);} + sentinel--; +} + + +const char * +default_strusage( int level ) +{ + const char *p; + switch( level ) { + case 0: p = strusage(10); break; + case 1: p = strusage(11); break; + case 2: p = strusage(12); break; + case 10: p = "WkLib" + #if DOS386 && __WATCOMC__ + " (DOS4G)" + #elif DOS386 + " (DOSX)" + #elif DOS16RM + " (DOS16RM)" + #elif M_I86VM + " (VCM)" + #elif UNIX || POSIX + " (Posix)" + #elif OS2 + " (OS/2)" + #elif WINNT && __CYGWIN32__ + " (CygWin)" + #elif WINNT + " (WinNT)" + #elif NETWARE + " (Netware)" + #elif VMS + " (VMS)" + #endif + "; Copyright (c) 1997 by Werner Koch (dd9jn)" ; break; + case 11: p = "usage: ?"; break; + case 16: + case 15: p = "[Untitled]"; break; + case 23: p = "[unknown]"; break; + case 24: p = ""; break; + case 12: p = + "This is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n\n" + "WkLib is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307," + " USA.\n" ; + break; + case 22: + #if MSDOS + #if USE_EMS + p = "MSDOS+EMS"; + #else + p = "MSDOS"; + #endif + #elif OS2 + p = "OS/2"; + #elif WINNT && __CYGWIN32__ + p = "CygWin"; + #elif WINNT + p = "WinNT"; + #elif DOS386 + p = "DOS386"; + #elif EMX + p = "EMX"; + #elif DOS16RM + p = "DOS16RM"; + #elif NETWARE + p = "Netware"; + #elif __linux__ + p = "Linux"; + #elif UNIX || M_UNIX || M_XENIX + p = "UNIX"; + #elif VMS + p = "VMS"; + #else + p = "UnknownOS"; + #endif + break; + case 31: p = + "This program comes with ABSOLUTELY NO WARRANTY.\n" + "This is free software, and you are welcome to redistribute it\n" + "under certain conditions. See the file COPYING for details.\n"; + break; + case 32: p = "[" + #if MSDOS + "MSDOS Version" + #elif DOS386 && __ZTC__ + "32-Bit MSDOS Version (Zortech's DOSX)" + #elif DOS386 + "32-Bit MSDOS Version" + #elif OS20 && EMX + "OS/2 2.x EMX Version" + #elif OS20 + "OS/2 2.x Version" + #elif OS2 + "OS/2 1.x Version" + #elif WINNT && __CYGWIN32__ + "Cygnus WinAPI Version" + #elif WINNT + "Windoze NT Version" + #elif EMX + "EMX Version" + #elif NETWARE + "NLM Version" + #elif DOS16RM + "DOS16RM Version" + #elif __linux__ + "Linux Version" + #elif VMS + "OpenVMS Version" + #elif POSIX + "POSIX Version" + #elif M_UNIX || M_XENIX + "*IX Version" + #endif + "]"; + break; + case 33: p = + #ifdef MULTI_THREADED + "mt" + #else + "" + #endif + ; break; + case 42: + case 43: + case 44: + case 45: p = ""; break; + default: p = "?"; + } + + return p; +} + + + +#ifdef TEST +static struct { + int verbose; + int debug; + char *outfile; + char *crf; + int myopt; + int echo; + int a_long_one; +}opt; + +int +main(int argc, char **argv) +{ + ARGPARSE_OPTS opts[] = { + { 'v', "verbose", 0 , "Laut sein"}, + { 'e', "echo" , 0 , "Zeile ausgeben, damit wir sehen, was wir einegegeben haben"}, + { 'd', "debug", 0 , "Debug\nfalls mal etasws\nSchief geht"}, + { 'o', "output", 2 }, + { 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" }, + { 'm', "my-option", 1|8 }, + { 500, "a-long-option", 0 }, + {0} }; + ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 }; + int i; + + while( ArgParse( &pargs, opts) ) { + switch( pargs.r_opt ) { + case -1 : printf( "arg='%s'\n", pargs.r.ret_str); break; + case 'v': opt.verbose++; break; + case 'e': opt.echo++; break; + case 'd': opt.debug++; break; + case 'o': opt.outfile = pargs.r.ret_str; break; + case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + case 500: opt.a_long_one++; break; + default : pargs.err = 1; break; /* force warning output */ + } + } + for(i=0; i < argc; i++ ) + printf("%3d -> (%s)\n", i, argv[i] ); + puts("Options:"); + if( opt.verbose ) + printf(" verbose=%d\n", opt.verbose ); + if( opt.debug ) + printf(" debug=%d\n", opt.debug ); + if( opt.outfile ) + printf(" outfile='%s'\n", opt.outfile ); + if( opt.crf ) + printf(" crffile='%s'\n", opt.crf ); + if( opt.myopt ) + printf(" myopt=%d\n", opt.myopt ); + if( opt.a_long_one ) + printf(" a-long-one=%d\n", opt.a_long_one ); + if( opt.echo ) + printf(" echo=%d\n", opt.echo ); + return 0; +} +#endif + +/**** bottom of file ****/ diff --git a/util/errors.c b/util/errors.c new file mode 100644 index 000000000..1e4579fc4 --- /dev/null +++ b/util/errors.c @@ -0,0 +1,69 @@ +/* errors.c - error strings + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +#include "errors.h" + +const char * +g10_errstr( int err ) +{ + static char buf[50]; + const char *p; + + #define X(n,s) case G10ERR_##n : p = s; break; + switch( err ) { + X(GENERAL, "General error") + X(UNKNOWN_PACKET, "Unknown packet type") + X(UNKNOWN_VERSION,"Unknown version") + X(PUBKEY_ALGO ,"Unknown pubkey algorithm") + X(DIGEST_ALGO ,"Unknown digest algorithm") + X(BAD_PUBKEY ,"Bad public key") + X(BAD_SECKEY ,"Bad secret key") + X(BAD_SIGN ,"Bad signature") + X(CHECKSUM , "Checksum error") + X(BAD_PASS , "Bad passphrase") + X(NO_PUBKEY ,"Public key not found") + X(CIPHER_ALGO ,"Unknown cipher algorithm") + X(KEYRING_OPEN ,"Can't open the keyring") + X(BAD_RING ,"Broken keyring") + X(NO_USER_ID ,"No such user id found") + X(NO_SECKEY ,"Secret key not available") + X(WRONG_SECKEY ,"Wrong secret key used") + X(UNSUPPORTED ,"Not supported") + X(BAD_KEY ,"Bad key") + X(READ_FILE ,"File read error") + X(WRITE_FILE ,"File write error") + X(COMPR_ALGO ,"Unknown compress algorithm") + X(OPEN_FILE ,"File open error") + X(CREATE_FILE ,"File create error") + X(PASSPHRASE ,"Invalid passphrase") + X(NI_PUBKEY ,"Unimplemented pubkey algorithm") + X(NI_CIPHER ,"Unimplemented cipher algorithm") + + default: p = buf; sprintf(buf, "Error code %d", err); break; + } + #undef X + return p; +} + diff --git a/util/fileutil.c b/util/fileutil.c new file mode 100644 index 000000000..e2ea9b20e --- /dev/null +++ b/util/fileutil.c @@ -0,0 +1,31 @@ +/* fileutil.c - file utilities + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include "util.h" +#include "memory.h" +#include "ttyio.h" + + diff --git a/util/iobuf.c b/util/iobuf.c new file mode 100644 index 000000000..12fc74ff6 --- /dev/null +++ b/util/iobuf.c @@ -0,0 +1,762 @@ +/* iobuf.c - file handling + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "memory.h" +#include "util.h" +#include "iobuf.h" + +typedef struct { + FILE *fp; /* open file handle */ + char fname[1]; /* name of the file */ +} file_filter_ctx_t ; + +typedef struct { + int usage; + size_t size; + size_t count; + int eof; +} block_filter_ctx_t; + +static int underflow(IOBUF a); + +/**************** + * Read data from a file into buf which has an allocated length of *LEN. + * return the number of read bytes in *LEN. OPAQUE is the FILE * of + * the stream. A is not used. + * control maybe: + * IOBUFCTRL_INIT: called just before the function is linked into the + * list of function. This can be used to prepare internal + * data structures of the function. + * IOBUFCTRL_FREE: called just before the function is removed from the + * list of functions and can be used to release internal + * data structures or close a file etc. + * IOBUFCTRL_UNDERFLOW: called by iobuf_underflow to fill the buffer + * with new stuff. *RET_LEN is the available size of the + * buffer, and should be set to the number of bytes + * which were put into the buffer. The function + * returns 0 to indicate success, -1 on EOF and + * G10ERR_xxxxx for other errors. + * + * IOBUFCTRL_FLUSH: called by iobuf_flush() to write out the collected stuff. + * *RET_LAN is the number of bytes in BUF. + * + */ +static int +file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) +{ + file_filter_ctx_t *a = opaque; + FILE *fp = a->fp; + size_t size = *ret_len; + size_t nbytes = 0; + int c, rc = 0; + char *p; + + if( control == IOBUFCTRL_UNDERFLOW ) { + assert( size ); /* need a buffer */ + for(; size; size-- ) { + if( (c=getc(fp)) == EOF ) { + if( ferror(fp) ) { + log_error("%s: read error: %s\n", + a->fname, strerror(errno)); + rc = G10ERR_READ_FILE; + } + else if( !nbytes ) + rc = -1; /* okay: we can return EOF now. */ + break; + } + buf[nbytes++] = c & 0xff; + } + *ret_len = nbytes; + } + else if( control == IOBUFCTRL_FLUSH ) { + for(p=buf; nbytes < size; nbytes++, p++ ) { + if( putc(*p, fp) == EOF ) { + log_error("%s: write error: %s\n", + a->fname, strerror(errno)); + rc = G10ERR_WRITE_FILE; + break; + } + } + *ret_len = nbytes; + } + else if( control == IOBUFCTRL_INIT ) { + } + else if( control == IOBUFCTRL_DESC ) { + *(char**)buf = "file_filter"; + } + else if( control == IOBUFCTRL_FREE ) { + if( fp != stdin && fp != stdout ) + fclose(fp); + fp = NULL; + m_free(a); /* we can free our context now */ + } + + return rc; +} + + +/**************** + * This is used to implement the block write mode. + * Block reading is done on a byte by byte basis in readbyte(), + * without a filter + */ +static int +block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) +{ + block_filter_ctx_t *a = opaque; + size_t size = *ret_len; + int c, rc = 0; + char *p; + + if( control == IOBUFCTRL_UNDERFLOW ) { + size_t n=0; + + p = buf; + assert( size ); /* need a buffer */ + if( a->eof ) /* don't read any further */ + rc = -1; + while( !rc && size ) { + if( !a->size ) { /* get the length bytes */ + c = iobuf_get(chain); + a->size = c << 8; + c = iobuf_get(chain); + a->size |= c; + if( c == -1 ) { + log_error("block_filter: error reading length info\n"); + rc = G10ERR_READ_FILE; + } + if( !a->size ) { + a->eof = 1; + if( !n ) + rc = -1; + break; + } + } + + for(; !rc && size && a->size; size--, a->size-- ) { + if( (c=iobuf_get(chain)) == -1 ) { + log_error("block_filter %p: read error (size=%lu,a->size=%lu)\n", + a, (ulong)size, (ulong)a->size); + rc = G10ERR_READ_FILE; + } + else { + *p++ = c; + n++; + } + } + } + *ret_len = n; + } + else if( control == IOBUFCTRL_FLUSH ) { + size_t avail, n; + + for(p=buf; !rc && size; ) { + n = size; + avail = a->size - a->count; + if( !avail ) { + if( n > a->size ) { + iobuf_put( chain, (a->size >> 8) & 0xff ); + iobuf_put( chain, a->size & 0xff ); + avail = a->size; + a->count = 0; + } + else { + iobuf_put( chain, (n >> 8) & 0xff ); + iobuf_put( chain, n & 0xff ); + avail = n; + a->count = a->size - n; + } + } + if( n > avail ) + n = avail; + if( iobuf_write(chain, p, n ) ) + rc = G10ERR_WRITE_FILE; + a->count += n; + p += n; + size -= n; + } + } + else if( control == IOBUFCTRL_INIT ) { + if( DBG_IOBUF ) + log_debug("init block_filter %p\n", a ); + if( a->usage == 1 ) + a->count = a->size = 0; + else + a->count = a->size; /* force first length bytes */ + a->eof = 0; + } + else if( control == IOBUFCTRL_DESC ) { + *(char**)buf = "block_filter"; + } + else if( control == IOBUFCTRL_FREE ) { + if( a->usage == 2 ) { /* write the end markers */ + iobuf_writebyte(chain, 0); + iobuf_writebyte(chain, 0); + } + else if( a->size ) { + log_error("block_filter: pending bytes!\n"); + } + if( DBG_IOBUF ) + log_debug("free block_filter %p\n", a ); + m_free(a); /* we can free our context now */ + } + + return rc; +} + + + +/**************** + * Allocate a new io buffer, with no function assigned. + * Usage is the desired usage: 1 for input, 2 for output, 3 for temp buffer + * BUFSIZE is a suggested buffer size. + */ +IOBUF +iobuf_alloc(int usage, size_t bufsize) +{ + IOBUF a; + static int number=0; + + a = m_alloc_clear(sizeof *a); + a->usage = usage; + a->d.buf = m_alloc( bufsize ); + a->d.size = bufsize; + a->no = ++number; + a->subno = 0; + return a; +} + + +int +iobuf_close( IOBUF a ) +{ + IOBUF a2; + size_t dummy_len; + int rc=0; + + for( ; a; a = a2 ) { + a2 = a->chain; + if( a->usage == 2 && (rc=iobuf_flush(a)) ) + log_error("iobuf_flush failed on close: %s\n", g10_errstr(rc)); + + if( DBG_IOBUF ) + log_debug("iobuf-%d.%d: close '%s'\n", a->no, a->subno, a->desc ); + if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, + a->chain, NULL, &dummy_len)) ) + log_error("IOBUFCTRL_FREE failed on close: %s\n", g10_errstr(rc) ); + m_free(a->recorder.buf); + m_free(a->d.buf); + m_free(a); + } + return rc; +} + +int +iobuf_cancel( IOBUF a ) +{ + /* FIXME: do an unlink if usage is 2 */ + return iobuf_close(a); +} + + +/**************** + * create a temporary iobuf, which can be used to collect stuff + * in an iobuf and later be written by iobuf_write_temp() to another + * iobuf. + */ +IOBUF +iobuf_temp() +{ + IOBUF a; + + a = iobuf_alloc(3, 8192 ); + + return a; +} + + +/**************** + * Create a head iobuf for reading from a file + * returns: NULL if an error occures and sets errno + */ +IOBUF +iobuf_open( const char *fname ) +{ + IOBUF a; + FILE *fp; + file_filter_ctx_t *fcx; + size_t len; + + if( !fname ) { + fp = stdin; /* fixme: set binary mode for msdoze */ + fname = "[stdin]"; + } + else if( !(fp = fopen(fname, "rb")) ) + return NULL; + a = iobuf_alloc(1, 8192 ); + fcx = m_alloc( sizeof *fcx + strlen(fname) ); + fcx->fp = fp; + strcpy(fcx->fname, fname ); + a->filter = file_filter; + a->filter_ov = fcx; + file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); + file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len ); + if( DBG_IOBUF ) + log_debug("iobuf-%d.%d: open '%s'\n", a->no, a->subno, fname ); + + return a; +} + +/**************** + * create a iobuf for writing to a file; the file will be created. + */ +IOBUF +iobuf_create( const char *fname ) +{ + IOBUF a; + FILE *fp; + file_filter_ctx_t *fcx; + size_t len; + + if( !fname ) { + fp = stdout; + fname = "[stdout]"; + } + else if( !(fp = fopen(fname, "wb")) ) + return NULL; + a = iobuf_alloc(2, 8192 ); + fcx = m_alloc( sizeof *fcx + strlen(fname) ); + fcx->fp = fp; + strcpy(fcx->fname, fname ); + a->filter = file_filter; + a->filter_ov = fcx; + file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); + file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len ); + if( DBG_IOBUF ) + log_debug("iobuf-%d.%d: create '%s'\n", a->no, a->subno, a->desc ); + + return a; +} + +/**************** + * Register an i/o filter. + */ +int +iobuf_push_filter( IOBUF a, + int (*f)(void *opaque, int control, + IOBUF chain, byte *buf, size_t *len), void *ov ) +{ + IOBUF b; + size_t dummy_len=0; + int rc=0; + + if( a->usage == 2 && (rc=iobuf_flush(a)) ) + return rc; + /* make a copy of the current stream, so that + * A is the new stream and B the original one. + * The contents of the buffers are transferred to the + * new stream. + */ + b = m_alloc(sizeof *b); + memcpy(b, a, sizeof *b ); + /* remove the filter stuff from the new stream */ + a->filter = NULL; + a->filter_ov = NULL; + if( a->usage == 2 ) { /* allocate a fresh buffer for the original stream */ + b->d.buf = m_alloc( a->d.size ); + b->d.len = 0; + b->d.start = 0; + } + else { /* allocate a fresh buffer for the new stream */ + a->d.buf = m_alloc( a->d.size ); + a->d.len = 0; + a->d.start = 0; + } + /* disable nlimit for the new stream */ + a->nlimit = a->nbytes = 0; + /* disable recorder for the original stream */ + b->recorder.buf = NULL; + /* make a link from the new stream to the original stream */ + a->chain = b; + + /* setup the function on the new stream */ + a->filter = f; + a->filter_ov = ov; + + a->subno = b->subno + 1; + f( ov, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &dummy_len ); + + if( DBG_IOBUF ) { + log_debug("iobuf-%d.%d: push '%s'\n", a->no, a->subno, a->desc ); + for(b=a; b; b = b->chain ) + log_debug("\tchain: %d.%d '%s'\n", b->no, b->subno, b->desc ); + } + + /* now we can initialize the new function if we have one */ + if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_INIT, a->chain, + NULL, &dummy_len)) ) + log_error("IOBUFCTRL_INIT failed: %s\n", g10_errstr(rc) ); + return rc; +} + +/**************** + * Remove an i/o filter. + */ +int +iobuf_pop_filter( IOBUF a, int (*f)(void *opaque, int control, + IOBUF chain, byte *buf, size_t *len), void *ov ) +{ + IOBUF b; + size_t dummy_len=0; + int rc=0; + + if( DBG_IOBUF ) + log_debug("iobuf-%d.%d: pop '%s'\n", a->no, a->subno, a->desc ); + if( !a->filter ) { /* this is simple */ + b = a->chain; + assert(b); + m_free(a->d.buf); + memcpy(a,b, sizeof *a); + m_free(b); + return 0; + } + for(b=a ; b; b = b->chain ) + if( b->filter == f && (!ov || b->filter_ov == ov) ) + break; + if( !b ) + log_bug("iobuf_pop_filter(): filter function not found\n"); + + /* flush this stream if it is an output stream */ + if( a->usage == 2 && (rc=iobuf_flush(b)) ) { + log_error("iobuf_flush failed in pop_filter: %s\n", g10_errstr(rc)); + return rc; + } + /* and tell the filter to free it self */ + if( (rc = b->filter(b->filter_ov, IOBUFCTRL_FREE, b->chain, + NULL, &dummy_len)) ) { + log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) ); + return rc; + } + + /* and look how to remove it */ + if( a == b && !b->chain ) + log_bug("can't remove the last filter from the chain\n"); + else if( a == b ) { /* remove the first iobuf from the chain */ + /* everything from b is copied to a. This is save because + * a flush has been done on the to be removed entry + */ + b = a->chain; + m_free(a->d.buf); + memcpy(a,b, sizeof *a); + m_free(b); + } + else if( !b->chain ) { /* remove the last iobuf from the chain */ + log_bug("Ohh jeee, trying to a head filter\n"); + } + else { /* remove an intermediate iobuf from the chain */ + log_bug("Ohh jeee, trying to remove an intermediate filter\n"); + } + + return rc; +} + + + +/**************** + * read underflow: read more bytes into the buffer and return + * the first byte or -1 on EOF. + */ +static int +underflow(IOBUF a) +{ + size_t len; + int rc; + + /*log_debug("iobuf-%d.%d: underflow: start=%lu len=%lu\n", + a->no, a->subno, (ulong)a->d.start, (ulong)a->d.len );*/ + assert( a->d.start == a->d.len ); + if( a->usage == 3 ) + return -1; /* EOF because a temp buffer can't do an underflow */ + if( a->filter_eof ) { + if( DBG_IOBUF ) + log_debug("iobuf-%d.%d: filter eof\n", a->no, a->subno ); + return -1; + } + + if( a->filter ) { + len = a->d.size; + rc = a->filter( a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, + a->d.buf, &len ); + if( a->usage == 1 && rc == -1 ) { /* EOF: we can remove the filter */ + size_t dummy_len; + + /* and tell the filter to free it self */ + if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain, + NULL, &dummy_len)) ) + log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) ); + a->filter = NULL; + a->desc = NULL; + a->filter_ov = NULL; + a->filter_eof = 1; + } + + if( !len ) + return -1; + a->d.len = len; + a->d.start = 0; + return a->d.buf[a->d.start++]; + } + else + return -1; /* no filter; return EOF */ +} + + +void +iobuf_clear_eof(IOBUF a) +{ + assert(a->usage == 1); + + if( a->filter ) + log_info("iobuf-%d.%d: clear_eof '%s' with enabled filter\n", a->no, a->subno, a->desc ); + if( !a->filter_eof ) + log_info("iobuf-%d.%d: clear_eof '%s' with no EOF pending\n", a->no, a->subno, a->desc ); + iobuf_pop_filter(a, NULL, NULL); +} + + +int +iobuf_flush(IOBUF a) +{ + size_t len; + int rc; + + /*log_debug("iobuf-%d.%d: flush\n", a->no, a->subno );*/ + if( a->usage == 3 ) + log_bug("temp buffer too short\n"); + else if( a->usage != 2 ) + log_bug("flush on non-output iobuf\n"); + else if( !a->filter ) + log_bug("iobuf_flush: no filter\n"); + len = a->d.len; + rc = a->filter( a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len ); + if( !rc && len != a->d.len ) { + log_info("iobuf_flush did not write all!\n"); + rc = G10ERR_WRITE_FILE; + } + a->d.len = 0; + + return rc; +} + + +/**************** + * Read a byte from the iobuf; returns -1 on EOF + */ +int +iobuf_readbyte(IOBUF a) +{ + int c; + + if( a->nlimit && a->nbytes >= a->nlimit ) + return -1; /* forced EOF */ + + if( a->d.start < a->d.len ) { + c = a->d.buf[a->d.start++]; + } + else if( (c=underflow(a)) == -1 ) + return -1; /* EOF */ + + a->nbytes++; + + if( a->recorder.buf ) { + if( a->recorder.len >= a->recorder.size ) { + a->recorder.size += 500; + a->recorder.buf = m_realloc( a->recorder.buf, a->recorder.size ); + } + ((byte*)a->recorder.buf)[a->recorder.len++] = c; + } + return c; +} + + +int +iobuf_writebyte(IOBUF a, unsigned c) +{ + if( a->d.len == a->d.size ) + if( iobuf_flush(a) ) + return -1; + + assert( a->d.len < a->d.size ); + a->d.buf[a->d.len++] = c; + return 0; +} + + +int +iobuf_write(IOBUF a, byte *buf, unsigned buflen ) +{ + for( ; buflen; buflen--, buf++ ) + if( iobuf_writebyte(a, *buf) ) + return -1; + return 0; +} + + + +/**************** + * copy the contents of TEMP to A. + */ +int +iobuf_write_temp( IOBUF a, IOBUF temp ) +{ + return iobuf_write(a, temp->d.buf, temp->d.len ); +} + +/**************** + * copy the contents of the temp io stream to BUFFER. + */ +size_t +iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen ) +{ + size_t n = a->d.len; + + if( n > buflen ) + n = buflen; + memcpy( buffer, a->d.buf, n ); + return n; +} + + +/**************** + * Set a limit, how much bytes may be read from the input stream A. + * Setting the limit to 0 disables this feature. + */ +void +iobuf_set_limit( IOBUF a, unsigned long nlimit ) +{ + a->nlimit = nlimit; + a->nbytes = 0; +} + + + +void +iobuf_start_recorder( IOBUF a ) +{ + m_free(a->recorder.buf); + a->recorder.size = 500; + a->recorder.buf = m_alloc(a->recorder.size); + a->recorder.len = 0; +} + +void +iobuf_push_recorder( IOBUF a, int c ) +{ + if( a->recorder.buf ) { + if( a->recorder.len >= a->recorder.size ) { + a->recorder.size += 500; + a->recorder.buf = m_realloc( a->recorder.buf, a->recorder.size ); + } + ((byte*)a->recorder.buf)[a->recorder.len++] = c; + } +} + + +char * +iobuf_stop_recorder( IOBUF a, size_t *n ) +{ + char *p; + if( !a->recorder.buf ) + log_bug("iobuf_recorder not started\n"); + p = a->recorder.buf; + if( n ) + *n = a->recorder.len; + a->recorder.buf = NULL; + return p; +} + + +/**************** + * Return the length of an open file + */ +u32 +iobuf_get_filelength( IOBUF a ) +{ + struct stat st; + + for( ; a; a = a->chain ) + if( !a->chain && a->filter == file_filter ) { + file_filter_ctx_t *b = a->filter_ov; + FILE *fp = b->fp; + + if( !fstat(fileno(fp), &st) ) + return st.st_size; + log_error("fstat() failed: %s\n", strerror(errno) ); + break; + } + + return 0; +} + +/**************** + * Start the block write mode, see rfc1991.new for details. + * A value of 0 for N stops this mode (flushes and writes + * the end marker) + */ +void +iobuf_set_block_mode( IOBUF a, size_t n ) +{ + block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx ); + + assert( a->usage == 1 || a->usage == 2 ); + ctx->usage = a->usage; + if( !n ) { + iobuf_pop_filter(a, block_filter, NULL ); + } + else { + ctx->size = n; /* only needed for usage 2 */ + iobuf_push_filter(a, block_filter, ctx ); + } +} + + +/**************** + * checks wether the stream is in block mode + */ +int +iobuf_in_block_mode( IOBUF a ) +{ + for(; a; a = a->chain ) + if( a->filter == block_filter ) + return 1; /* yes */ + return 0; /* no */ +} + + + diff --git a/util/logger.c b/util/logger.c new file mode 100644 index 000000000..803420cd8 --- /dev/null +++ b/util/logger.c @@ -0,0 +1,139 @@ +/* logger.c - log functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +#include "util.h" + +/**************** + * General interface for printing a line + * level 0 := print to /dev/null + * 1 := print to stdout + * 2 := print as info to stderr + * 3 := ditto but as error + */ +void +printstr( int level, const char *fmt, ... ) +{ + va_list arg_ptr ; + + if( !level ) + return; + + if( !fmt ) { + putc('\n', level? stderr: stdout); + return; + } + + va_start( arg_ptr, fmt ) ; + if( level < 2 ) { + vfprintf(stdout,fmt,arg_ptr) ; + } + else { + fprintf(stderr, level==2? "%s: ": "%s: error: ", strusage(13) ) ; + vfprintf(stderr,fmt,arg_ptr) ; + } + va_end(arg_ptr); +} + + +void +log_info( const char *fmt, ... ) +{ + va_list arg_ptr ; + + fprintf(stderr, "info: " ) ; + va_start( arg_ptr, fmt ) ; + vfprintf(stderr,fmt,arg_ptr) ; + va_end(arg_ptr); +} + +void +log_error( const char *fmt, ... ) +{ + va_list arg_ptr ; + + fprintf(stderr, "error: " ) ; + va_start( arg_ptr, fmt ) ; + vfprintf(stderr,fmt,arg_ptr) ; + va_end(arg_ptr); +} + +void +log_fatal( const char *fmt, ... ) +{ + va_list arg_ptr ; + + fprintf(stderr, "Fatal: " ) ; + va_start( arg_ptr, fmt ) ; + vfprintf(stderr,fmt,arg_ptr) ; + va_end(arg_ptr); + exit(2); +} + +void +log_bug( const char *fmt, ... ) +{ + va_list arg_ptr ; + + fprintf(stderr, "\nInternal Error: " ) ; + va_start( arg_ptr, fmt ) ; + vfprintf(stderr,fmt,arg_ptr) ; + va_end(arg_ptr); + fflush(stderr); + abort(); +} + +void +log_debug( const char *fmt, ... ) +{ + va_list arg_ptr ; + + fprintf(stderr, "DBG: " ) ; + va_start( arg_ptr, fmt ) ; + vfprintf(stderr,fmt,arg_ptr) ; + va_end(arg_ptr); +} + + + +void +log_hexdump( const char *text, char *buf, size_t len ) +{ + int i; + + fprintf(stderr, "DBG: %s", text ); + for(i=0; i < len; i++ ) + fprintf(stderr, " %02X", ((byte*)buf)[i] ); + fputc('\n', stderr); +} + + +void +log_mpidump( const char *text, MPI a ) +{ + fprintf(stderr, "DBG: %s", text ); + mpi_print(stderr, a, 1 ); + fputc('\n', stderr); +} + diff --git a/util/memory.c b/util/memory.c new file mode 100644 index 000000000..6ad57f9b0 --- /dev/null +++ b/util/memory.c @@ -0,0 +1,460 @@ +/* memory.c - memory allocation + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * We use our own memory allocation functions instead of plain malloc(), + * so that we can provide some special enhancements: + * a) functions to provide memory from a secure memory. + * Don't know how to handle it yet, but it may be possible to + * use memory which can't be swapped out. + * b) By looking at the requested allocation size we + * can reuse memory very quickly (e.g. MPI storage) + * c) A controlbyte gives us the opportunity to use only one + * free() function and do some overflow checking. + * d) memory checking and reporting if compiled with M_DEBUG + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "types.h" +#include "memory.h" +#include "util.h" + + +#define MAGIC_NOR_BYTE 0x55 +#define MAGIC_SEC_BYTE 0xcc +#define MAGIC_END_BYTE 0xaa + +const void membug( const char *fmt, ... ); + +#ifdef M_DEBUG + #undef m_alloc + #undef m_alloc_clear + #undef m_alloc_secure + #undef m_alloc_secure_clear + #undef m_realloc + #undef m_free + #undef m_check + #define FNAME(a) m_debug_ ##a + #define FNAMEPRT , const char *info + #define FNAMEARG , info + #define store_len(p,n,m) do { add_entry(p,n,m, \ + info, __FUNCTION__); } while(0) +#else + #define FNAME(a) m_ ##a + #define FNAMEPRT + #define FNAMEARG + #define store_len(p,n,m) do { ((byte*))p[0] = n; \ + ((byte*))p[2] = n >> 8 ; \ + ((byte*))p[3] = n >> 16 ; \ + ((byte*))p[4] = m? MAGIC_SEC_BYTE \ + : MAGIC_NOR_BYTE; \ + } while(0) +#endif + + +#ifdef M_DEBUG /* stuff used for memory debuging */ + +struct info_entry { + struct info_entry *next; + unsigned count; /* call count */ + const char *info; /* the reference to the info string */ +}; + +struct memtbl_entry { + const void *user_p; /* for reference: the pointer given to the user */ + size_t user_n; /* length requested by the user */ + struct memtbl_entry *next; /* to build a list of unused entries */ + const struct info_entry *info; /* points into the table with */ + /* the info strings */ + unsigned inuse:1; /* this entry is in use */ + unsigned count:31; +}; + + +#define INFO_BUCKETS 53 +#define info_hash(p) ( *(u32*)((p)) % INFO_BUCKETS ) +static struct info_entry *info_strings[INFO_BUCKETS]; /* hash table */ + +static struct memtbl_entry *memtbl; /* the table with the memory infos */ +static unsigned memtbl_size; /* number of allocated entries */ +static unsigned memtbl_len; /* number of used entries */ +static struct memtbl_entry *memtbl_unused;/* to keep track of unused entries */ + +static void dump_table(void); +static void check_allmem( const char *info ); + +/**************** + * Put the new P into the debug table and return a pointer to the table entry. + * mode is true for security. BY is the name of the function which called us. + */ +static void +add_entry( byte *p, unsigned n, int mode, const char *info, const char *by ) +{ + unsigned index; + struct memtbl_entry *e; + struct info_entry *ie; + + if( memtbl_len < memtbl_size ) + index = memtbl_len++; + else { + struct memtbl_entry *e; + /* look for an used entry in the table. We take the first one, + * so that freed entries remain as long as possible in the table + * (free appends a new one) + */ + if( (e = memtbl_unused) ) { + index = e - memtbl; + memtbl_unused = e->next; + e->next = NULL; + } + else { /* no free entries in the table: extend the table */ + if( !memtbl_size ) { /* first time */ + memtbl_size = 100; + if( !(memtbl = calloc( memtbl_size, sizeof *memtbl )) ) + membug("memory debug table malloc failed\n"); + index = 0; + memtbl_len = 1; + if( DBG_MEMSTAT ) + atexit( dump_table ); + } + else { /* realloc */ + unsigned n = memtbl_size / 4; /* enlarge by 25% */ + if(!(memtbl = realloc(memtbl, (memtbl_size+n)*sizeof *memtbl))) + membug("memory debug table realloc failed\n"); + memset(memtbl+memtbl_size, 0, n*sizeof *memtbl ); + memtbl_size += n; + index = memtbl_len++; + } + } + } + e = memtbl+index; + if( e->inuse ) + membug("Ooops: entry %u is flagged as in use\n", index); + e->user_p = p + 4; + e->user_n = n; + e->count++; + if( e->next ) + membug("Ooops: entry is in free entry list\n"); + /* do we already have this info string */ + for( ie = info_strings[info_hash(info)]; ie; ie = ie->next ) + if( ie->info == info ) + break; + if( !ie ) { /* no: make a new entry */ + if( !(ie = malloc( sizeof *ie )) ) + membug("can't allocate info entry\n"); + ie->next = info_strings[info_hash(info)]; + info_strings[info_hash(info)] = ie; + ie->info = info; + ie->count = 0; + } + ie->count++; + e->info = ie; + e->inuse = 1; + + /* put the index at the start of the memory */ + p[0] = index; + p[1] = index >> 8 ; + p[2] = index >> 16 ; + p[3] = mode? MAGIC_SEC_BYTE : MAGIC_NOR_BYTE ; + if( DBG_MEMORY ) + log_debug( "%s allocates %u bytes using %s\n", info, e->user_n, by ); +} + + + +/**************** + * Check that the memory block is correct. The magic byte has already been + * checked. Checks which are done here: + * - see wether the index points into our memory table + * - see wether P is the same as the one stored in the table + * - see wether we have already freed this block. + */ +struct memtbl_entry * +check_mem( const byte *p, const char *info ) +{ + unsigned n; + struct memtbl_entry *e; + + n = p[0]; + n |= p[1] << 8; + n |= p[2] << 16; + + if( n >= memtbl_len ) + membug("memory at %p corrupted: index=%u table_len=%u (%s)\n", + p+4, n, memtbl_len, info ); + e = memtbl+n; + + if( e->user_p != p+4 ) + membug("memory at %p corrupted: reference mismatch (%s)\n", p+4, info ); + if( !e->inuse ) + membug("memory at %p corrupted: marked as free (%s)\n", p+4, info ); + + if( !(p[3] == MAGIC_NOR_BYTE || p[3] == MAGIC_SEC_BYTE) ) + membug("memory at %p corrupted: underflow=%02x (%s)\n", p+4, p[3], info ); + if( p[4+e->user_n] != MAGIC_END_BYTE ) + membug("memory at %p corrupted: overflow=%02x (%s)\n", p+4, p[4+e->user_n], info ); + if( e->info->count > 20000 ) + membug("memory at %p corrupted: count too high (%s)\n", p+4, info ); + return e; +} + + +/**************** + * free the entry and the memory (replaces free) + */ +static void +free_entry( byte *p, const char *info ) +{ + struct memtbl_entry *e, *e2; + + check_allmem("add_entry"); + + e = check_mem(p, info); + if( DBG_MEMORY ) + log_debug( "%s frees %u bytes alloced by %s\n", + info, e->user_n, e->info->info ); + if( !e->inuse ) { + if( e->user_p == p + 4 ) + membug("freeing an already freed pointer at %p\n", p+4 ); + else + membug("freeing pointer %p which is flagged as freed\n", p+4 ); + } + + e->inuse = 0; + e->next = NULL; + if( !memtbl_unused ) + memtbl_unused = e; + else { + for(e2=memtbl_unused; e2->next; e2 = e2->next ) + ; + e2->next = e; + } + memset(p,'f', e->user_n+5); + free(p); +} + +static void +dump_entry(struct memtbl_entry *e ) +{ + unsigned n = e - memtbl; + + fprintf(stderr, "mem %4u%c %5u %p %5u %s (%u)\n", + n, e->inuse?'a':'u', e->count, e->user_p, e->user_n, + e->info->info, e->info->count ); + + +} + +static void +dump_table(void) +{ + unsigned n; + struct memtbl_entry *e; + ulong sum = 0, chunks =0; + + for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) { + dump_entry(e); + if(e->inuse) { + sum += e->user_n; + chunks++; + } + } + fprintf(stderr, " memory used: %8lu bytes in %ld chunks\n", + sum, chunks ); +} + +static void +check_allmem( const char *info ) +{ + unsigned n; + struct memtbl_entry *e; + + for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) + if( e->inuse ) + check_mem(e->user_p-4, info); +} + +#endif /* M_DEBUG */ + +const void +membug( const char *fmt, ... ) +{ + va_list arg_ptr ; + + fprintf(stderr, "\nMemory Error: " ) ; + va_start( arg_ptr, fmt ) ; + vfprintf(stderr,fmt,arg_ptr) ; + va_end(arg_ptr); + fflush(stderr); + #ifdef M_DEBUG + if( DBG_MEMSTAT ) + dump_table(); + #endif + abort(); +} + + +static void +out_of_core(size_t n) +{ + log_fatal("out of memory while allocating %u bytes\n", (unsigned)n ); +} + +/**************** + * Allocate memory of size n. + * This function gives up if we do not have enough memory + */ +void * +FNAME(alloc)( size_t n FNAMEPRT ) +{ + char *p; + + if( !(p = malloc( n + 5 )) ) + out_of_core(n); + store_len(p,n,0); + p[4+n] = MAGIC_END_BYTE; /* need to add the length somewhere */ + return p+4; +} + +/**************** + * Allocate memory of size n from the secure memory pool. + * This function gives up if we do not have enough memory + */ +void * +FNAME(alloc_secure)( size_t n FNAMEPRT ) +{ + char *p; + + if( !(p = malloc( n + 5 )) ) /* fixme: should alloc from the secure heap*/ + out_of_core(n); + store_len(p,n,1); + p[4+n] = MAGIC_END_BYTE; + return p+4; +} + +void * +FNAME(alloc_clear)( size_t n FNAMEPRT ) +{ + void *p; + p = FNAME(alloc)( n FNAMEARG ); + memset(p, 0, n ); + return p; +} + +void * +FNAME(alloc_secure_clear)( size_t n FNAMEPRT) +{ + void *p; + p = FNAME(alloc_secure)( n FNAMEARG ); + memset(p, 0, n ); + return p; +} + + +/**************** + * realloc and clear the new space + */ +void * +FNAME(realloc)( void *a, size_t n FNAMEPRT ) +{ /* FIXME: should be optimized :-) */ + unsigned char *p = a; + void *b; + size_t len = m_size(a); + + if( len >= n ) /* we don't shrink for now */ + return a; + if( p[-1] == MAGIC_SEC_BYTE ) + b = FNAME(alloc_secure_clear)(n FNAMEARG); + else + b = FNAME(alloc_clear)(n FNAMEARG); + FNAME(check)(NULL FNAMEARG); + memcpy(b, a, len ); + FNAME(free)(p FNAMEARG); + return b; +} + + + +/**************** + * Free a pointer + */ +void +FNAME(free)( void *a FNAMEPRT ) +{ + byte *p = a; + + if( !p ) + return; + #ifdef M_DEBUG + free_entry(p-4, info); + #else + m_check(p); + free(p-4); + #endif +} + + +void +FNAME(check)( const void *a FNAMEPRT ) +{ + const byte *p = a; + + #ifdef M_DEBUG + if( p ) + check_mem(p-4, info); + else + check_allmem(info); + #else + if( !p ) + return; + if( !(p[-1] == MAGIC_NOR_BYTE || p[-1] == MAGIC_SEC_BYTE) ) + membug("memory at %p corrupted (underflow=%02x)\n", p, p[-1] ); + else if( p[m_size(p)] != MAGIC_END_BYTE ) + membug("memory at %p corrupted (overflow=%02x)\n", p, p[-1] ); + #endif +} + + +size_t +m_size( const void *a ) +{ + const byte *p = a; + size_t n; + + #ifdef M_DEBUG + n = check_mem(p-4, "m_size")->user_n; + #else + n = ((byte*)p[-4]; + n |= ((byte*)p[-3] << 8; + n |= ((byte*)p[-2] << 16; + #endif + return n; +} + + +int +m_is_secure( const void *p ) +{ + return p && ((byte*)p)[-1] == MAGIC_SEC_BYTE; +} + diff --git a/util/miscutil.c b/util/miscutil.c new file mode 100644 index 000000000..9fecf4488 --- /dev/null +++ b/util/miscutil.c @@ -0,0 +1,33 @@ +/* miscutil.c - miscellaneous utilities + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <time.h> +#include "types.h" +#include "util.h" + +u32 +make_timestamp() +{ + return time(NULL); +} + + diff --git a/util/strgutil.c b/util/strgutil.c new file mode 100644 index 000000000..b517ed5b6 --- /dev/null +++ b/util/strgutil.c @@ -0,0 +1,63 @@ +/* strgutil.c - miscellaneous utilities + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdlib.h> +#include <ctype.h> +#include "types.h" +#include "util.h" +#include "memory.h" + + +void +free_strlist( STRLIST sl ) +{ + STRLIST sl2; + + for(; sl; sl = sl2 ) { + sl2 = sl->next; + m_free(sl); + } +} + +/**************** + * look for the substring SUB in buffer and return a pointer to that + * substring in BUF or NULL if not found. + * Comparison is case-in-sensitive. + */ +char * +memistr( char *buf, size_t buflen, const char *sub ) +{ + const byte *t, *s ; + size_t n; + + for( t=buf, n=buflen, s=sub ; n ; t++, n-- ) + if( toupper(*t) == toupper(*s) ) { + for( buf=(char*)t++, buflen = n--, s++; + n && toupper(*t) == toupper(*s); t++, s++, n-- ) + ; + if( !*s ) + return buf; + t = buf; n = buflen; s = sub ; + } + + return NULL ; +} + diff --git a/util/ttyio.c b/util/ttyio.c new file mode 100644 index 000000000..39ad5a666 --- /dev/null +++ b/util/ttyio.c @@ -0,0 +1,114 @@ +/* ttyio.c - tty i/O functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * G10 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <errno.h> +#include <ctype.h> +#include "util.h" +#include "memory.h" +#include "ttyio.h" + +static int last_prompt_len; + +static FILE * +open_tty(void) +{ + FILE *tty = fopen("/dev/tty", "r"); + if( !tty ) + log_fatal("cannot open /dev/tty: %s\n", strerror(errno) ); + return tty; +} + +static void +close_tty( FILE *tty ) +{ + fclose(tty); +} + + + +void +tty_printf( const char *fmt, ... ) +{ + va_list arg_ptr; + + va_start( arg_ptr, fmt ) ; + last_prompt_len += vfprintf(stderr,fmt,arg_ptr) ; + va_end(arg_ptr); + fflush(stderr); +} + + +char * +tty_get( const char *prompt ) +{ + char *buf; + int c, n, i; + FILE *fp; + + last_prompt_len = 0; + tty_printf( prompt ); + buf = m_alloc(n=50); + i = 0; + fp = open_tty(); + while( (c=getc(fp)) != EOF && c != '\n' ) { + last_prompt_len++; + if( c == '\t' ) + c = ' '; + else if( iscntrl(c) ) + continue; + if( !(i < n-1) ) { + n += 50; + buf = m_realloc( buf, n ); + } + buf[i++] = c; + } + close_tty(fp); + buf[i] = 0; + return buf; +} + +char * +tty_get_hidden( const char *prompt ) +{ + return tty_get( prompt ); /* fixme */ +} + + +void +tty_kill_prompt() +{ + int i; +#if 0 + for(i=0; i < last_prompt_len; i ++ ) + fputc('\b', stderr); + for(i=0; i < last_prompt_len; i ++ ) + fputc(' ', stderr); + for(i=0; i < last_prompt_len; i ++ ) + fputc('\b', stderr); +#endif + last_prompt_len = 0; + fflush(stderr); +} + |