1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

initially checkin

This commit is contained in:
Werner Koch 1997-11-18 14:06:00 +00:00
parent ada086d0ce
commit 5393dd53c5
105 changed files with 18726 additions and 0 deletions

0
AUTHORS Normal file
View File

340
COPYING Normal file
View File

@ -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.

0
ChangeLog Normal file
View File

0
INSTALL Normal file
View File

12
Makefile.am Normal file
View File

@ -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

261
Makefile.in Normal file
View File

@ -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:

0
NEWS Normal file
View File

0
README Normal file
View File

32
acconfig.h Normal file
View File

@ -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*/

28
cipher/Makefile.am Normal file
View File

@ -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

264
cipher/Makefile.in Normal file
View File

@ -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:

522
cipher/blowfish.c Normal file
View File

@ -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;
}
}

51
cipher/blowfish.h Normal file
View File

@ -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*/

61
cipher/elgamal.c Normal file
View File

@ -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 )
{
}

45
cipher/elgamal.h Normal file
View File

@ -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*/

309
cipher/gost.c Normal file
View File

@ -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 );
}
}

46
cipher/gost.h Normal file
View File

@ -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*/

352
cipher/idea.c Normal file
View File

@ -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;
}
}

51
cipher/idea.h Normal file
View File

@ -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*/

420
cipher/md5.c Normal file
View File

@ -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 */

44
cipher/md5.h Normal file
View File

@ -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*/

152
cipher/primegen.c Normal file
View File

@ -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;
}

67
cipher/random.c Normal file
View File

@ -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];
}

51
cipher/rmd.h Normal file
View File

@ -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*/

375
cipher/rmd160.c Normal file
View File

@ -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 */
}

63
cipher/rmd160test.c Normal file
View File

@ -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;
}

191
cipher/rsa.c Normal file
View File

@ -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 );
}

53
cipher/rsa.h Normal file
View File

@ -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*/

114
cipher/smallprime.c Normal file
View File

@ -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
};

60
config.h.in Normal file
View File

@ -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*/

54
configure.in Normal file
View File

@ -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 ])

33
g10/Makefile.am Normal file
View File

@ -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

285
g10/Makefile.in Normal file
View File

@ -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:

386
g10/build-packet.c Normal file
View File

@ -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;
}

96
g10/checksig.c Normal file
View File

@ -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;
}

114
g10/compressed.c Normal file
View File

@ -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
}

470
g10/encode.c Normal file
View File

@ -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;
}

122
g10/encr-data.c Normal file
View File

@ -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;
}

35
g10/filter.h Normal file
View File

@ -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*/

198
g10/free-packet.c Normal file
View File

@ -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;
}

219
g10/g10.c Normal file
View File

@ -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;
}

475
g10/getkey.c Normal file
View File

@ -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;
}

45
g10/keydb.h Normal file
View File

@ -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*/

253
g10/keygen.c Normal file
View File

@ -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);
}

35
g10/main.h Normal file
View File

@ -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*/

275
g10/mainproc.c Normal file
View File

@ -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;
}

70
g10/mdfilter.c Normal file
View File

@ -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;
}

68
g10/options.h Normal file
View File

@ -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*/

79
g10/overwrite.c Normal file
View File

@ -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;
}

214
g10/packet.h Normal file
View File

@ -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*/

662
g10/parse-packet.c Normal file
View File

@ -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;
}

126
g10/passphrase.c Normal file
View File

@ -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;
}

114
g10/plaintext.c Normal file
View File

@ -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;
}

130
g10/pubkey-enc.c Normal file
View File

@ -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;
}

157
g10/seckey-cert.c Normal file
View File

@ -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;
}

101
g10/seskey.c Normal file
View File

@ -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;
}

213
g10/sig-check.c Normal file
View File

@ -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;
}

87
include/cipher.h Normal file
View File

@ -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*/

52
include/errors.h Normal file
View File

@ -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*/

120
include/iobuf.h Normal file
View File

@ -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*/

64
include/memory.h Normal file
View File

@ -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*/

147
include/mpi.h Normal file
View File

@ -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*/

29
include/ttyio.h Normal file
View File

@ -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*/

76
include/types.h Normal file
View File

@ -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*/

100
include/util.h Normal file
View File

@ -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*/

27
mpi/Makefile.am Normal file
View File

@ -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

271
mpi/Makefile.in Normal file
View File

@ -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:

1398
mpi/longlong.h Normal file

File diff suppressed because it is too large Load Diff

221
mpi/mpi-add.c Normal file
View File

@ -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;
}
}

133
mpi/mpi-bit.c Normal file
View File

@ -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);
}

72
mpi/mpi-cmp.c Normal file
View File

@ -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;
}

282
mpi/mpi-div.c Normal file
View File

@ -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 );
}

54
mpi/mpi-gcd.c Normal file
View File

@ -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);
}

198
mpi/mpi-internal.h Normal file
View File

@ -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*/

127
mpi/mpi-inv.c Normal file
View File

@ -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;
}

178
mpi/mpi-mul.c Normal file
View File

@ -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 );
}

247
mpi/mpi-pow.c Normal file
View File

@ -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 );
}

88
mpi/mpi-scan.c Normal file
View File

@ -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 */
}

392
mpi/mpicoder.c Normal file
View File

@ -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;
}

109
mpi/mpih-add.c Normal file
View File

@ -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;
}

53
mpi/mpih-cmp.c Normal file
View File

@ -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;
}

528
mpi/mpih-div.c Normal file
View File

@ -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;
}
}

557
mpi/mpih-mul.c Normal file
View File

@ -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;
}

94
mpi/mpih-shift.c Normal file
View File

@ -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;
}

106
mpi/mpih-sub.c Normal file
View File

@ -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;
}

326
mpi/mpiutil.c Normal file
View File

@ -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;
}

250
scripts/install-sh Executable file
View File

@ -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

40
scripts/mkinstalldirs Executable file
View File

@ -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

1
stamp-h.in Normal file
View File

@ -0,0 +1 @@
timestamp

12
tools/Makefile.am Normal file
View File

@ -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

252
tools/Makefile.in Normal file
View File

@ -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:

85
tools/bftest.c Normal file
View File

@ -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;
}

341
tools/mpicalc.c Normal file
View File

@ -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;
}

31
tools/primes.scm Normal file
View File

@ -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)

13
util/Makefile.am Normal file
View File

@ -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

248
util/Makefile.in Normal file
View File

@ -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:

653
util/argparse.c Normal file
View File

@ -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 ****/

69
util/errors.c Normal file
View File

@ -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;
}

31
util/fileutil.c Normal file
View File

@ -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"

762
util/iobuf.c Normal file
View File

@ -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 */
}

Some files were not shown because too many files have changed in this diff Show More