diff -uNr a/mpi/COPYING b/mpi/COPYING
--- a/mpi/COPYING false
+++ b/mpi/COPYING 9225acdfee37d53f45669eac0abd4f4e8eba5e9dbf39f49e9f182530a038a159934f8645e2bdc00783b4af40743643c1b3256653b5d3a4dea375ace1613b72fc
@@ -0,0 +1,676 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 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
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
+
diff -uNr a/mpi/errors.c b/mpi/errors.c
--- a/mpi/errors.c false
+++ b/mpi/errors.c 2637e827d61ac5be58c3cc88799eaf49daed6c957ed6c6647b6d8d787e4f7fd731cdd16db53cb1fa15e35230e918cd62da33b4dd410cc073ca4092bc973f5ad1
@@ -0,0 +1,113 @@
+/* errors.c - error strings
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+#include "errors.h"
+
+#ifndef HAVE_STRERROR
+char *
+strerror( int n )
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ static char buf[15];
+
+ if( n >= 0 && n < sys_nerr )
+ return sys_errlist[n];
+ strcpy( buf, "Unknown error" );
+ return buf;
+}
+#endif /* !HAVE_STRERROR */
+
+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 ) {
+ case -1: p = "eof"; break;
+ case 0: p = "okay"; break;
+ X(GENERAL, N_("general error"))
+ X(UNKNOWN_PACKET, N_("unknown packet type"))
+ X(UNKNOWN_VERSION,N_("unknown version"))
+ X(PUBKEY_ALGO ,N_("unknown pubkey algorithm"))
+ X(DIGEST_ALGO ,N_("unknown digest algorithm"))
+ X(BAD_PUBKEY ,N_("bad public key"))
+ X(BAD_SECKEY ,N_("bad secret key"))
+ X(BAD_SIGN ,N_("bad signature"))
+ X(CHECKSUM , N_("checksum error"))
+ X(BAD_PASS , N_("bad passphrase"))
+ X(NO_PUBKEY ,N_("public key not found"))
+ X(CIPHER_ALGO ,N_("unknown cipher algorithm"))
+ X(KEYRING_OPEN ,N_("can't open the keyring"))
+ X(INVALID_PACKET ,N_("invalid packet"))
+ X(INVALID_ARMOR ,N_("invalid armor"))
+ X(NO_USER_ID ,N_("no such user id"))
+ X(NO_SECKEY ,N_("secret key not available"))
+ X(WRONG_SECKEY ,N_("wrong secret key used"))
+ X(UNSUPPORTED ,N_("not supported"))
+ X(BAD_KEY ,N_("bad key"))
+ X(READ_FILE ,N_("file read error"))
+ X(WRITE_FILE ,N_("file write error"))
+ X(COMPR_ALGO ,N_("unknown compress algorithm"))
+ X(OPEN_FILE ,N_("file open error"))
+ X(CREATE_FILE ,N_("file create error"))
+ X(PASSPHRASE ,N_("invalid passphrase"))
+ X(NI_PUBKEY ,N_("unimplemented pubkey algorithm"))
+ X(NI_CIPHER ,N_("unimplemented cipher algorithm"))
+ X(SIG_CLASS ,N_("unknown signature class"))
+ X(TRUSTDB ,N_("trust database error"))
+ X(BAD_MPI ,N_("bad MPI"))
+ X(RESOURCE_LIMIT ,N_("resource limit"))
+ X(INV_KEYRING ,N_("invalid keyring"))
+ X(BAD_CERT ,N_("bad certificate"))
+ X(INV_USER_ID ,N_("malformed user id"))
+ X(CLOSE_FILE ,N_("file close error"))
+ X(RENAME_FILE ,N_("file rename error"))
+ X(DELETE_FILE ,N_("file delete error"))
+ X(UNEXPECTED ,N_("unexpected data"))
+ X(TIME_CONFLICT ,N_("timestamp conflict"))
+ X(WR_PUBKEY_ALGO ,N_("unusable pubkey algorithm"))
+ X(FILE_EXISTS ,N_("file exists"))
+ X(WEAK_KEY ,N_("weak key"))
+ X(INV_ARG ,N_("invalid argument"))
+ X(BAD_URI ,N_("bad URI"))
+ X(INVALID_URI ,N_("unsupported URI"))
+ X(NETWORK ,N_("network error"))
+ X(SELFTEST_FAILED,"selftest failed")
+ X(NOT_ENCRYPTED ,N_("not encrypted"))
+ X(NOT_PROCESSED ,N_("not processed"))
+ /* the key cannot be used for a specific usage */
+ X(UNU_PUBKEY ,N_("unusable public key"))
+ X(UNU_SECKEY ,N_("unusable secret key"))
+ X(KEYSERVER ,N_("keyserver error"))
+ X(CANCELED ,N_("canceled"))
+ X(NO_CARD ,N_("no card"))
+ X(NO_DATA ,N_("no data"))
+ default: p = buf; sprintf(buf, "g10err=%d", err); break;
+ }
+#undef X
+ return _(p);
+}
diff -uNr a/mpi/include/compat.h b/mpi/include/compat.h
--- a/mpi/include/compat.h false
+++ b/mpi/include/compat.h cbb804cbf1d96718eebc82abded7fb63514ba10efd2eb136a606d85bd1896dbeaa0d631cd87bf01c8c1e014350f5664309ec9136a0d4c6edf63c039227450926
@@ -0,0 +1,25 @@
+#ifndef _COMPAT_H_
+#define _COMPAT_H_
+
+/* Note this isn't identical to a C locale isspace() without \f and
+ \v, but works for the purposes used here. */
+#define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
+
+int hextobyte( const char *s );
+int ascii_toupper (int c);
+int ascii_tolower (int c);
+int ascii_strcasecmp( const char *a, const char *b );
+int ascii_strncasecmp( const char *a, const char *b, size_t n);
+
+#ifndef HAVE_STRSEP
+char *strsep (char **stringp, const char *delim);
+#endif
+
+#if __GNUC__ >= 4
+char *xstrconcat (const char *s1, ...) __attribute__ ((sentinel(0)));
+#else
+char *xstrconcat (const char *s1, ...);
+#endif
+
+
+#endif /* !_COMPAT_H_ */
diff -uNr a/mpi/include/config.h b/mpi/include/config.h
--- a/mpi/include/config.h false
+++ b/mpi/include/config.h f16ecf4fd4cffb8cb4c97bee3a486e8feaaa6ce8c2d70fdf6ab80687847ae8700b2dc199476459401505048d1642b4d94fd2e4152d911e8b6d54065da09efe66
@@ -0,0 +1,89 @@
+/* config.h.
+ ORIGINALLY Generated from config.h.in by configure.
+ Cleaned up by hand. The price of this is that the knobs must
+ now be turned by hand.
+*/
+
+#ifndef GNUPG_CONFIG_H_INCLUDED
+#define GNUPG_CONFIG_H_INCLUDED
+
+/* Define to 1 if you have the `atexit' function. */
+#define HAVE_ATEXIT 1
+
+/* Defined if the mlock() call does not work */
+/* #undef HAVE_BROKEN_MLOCK */
+
+/* Defined if a `byte' is typedef'd */
+/* #undef HAVE_BYTE_TYPEDEF */
+
+/* defined if we run on some of the PCDOS like systems (DOS, Windoze. OS/2)
+ with special properties like no file modes */
+/* #undef HAVE_DOSISH_SYSTEM */
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the header file. */
+// #undef HAVE_LOCALE_H
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Defined if the system supports an mlock() call */
+#define HAVE_MLOCK 1
+
+/* Define to 1 if you have the `mmap' function. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `plock' function. */
+/* #undef HAVE_PLOCK */
+
+/* Define to 1 if you have the `raise' function. */
+#define HAVE_RAISE 1
+
+/* Define to 1 if you have the `stpcpy' function. */
+#define HAVE_STPCPY 1
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strlwr' function. */
+/* #undef HAVE_STRLWR */
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define to 1 if you have the `sysconf' function. */
+#define HAVE_SYSCONF 1
+
+/* Defined if a `u16' is typedef'd */
+/* #undef HAVE_U16_TYPEDEF */
+
+/* Defined if a `u32' is typedef'd */
+/* #undef HAVE_U32_TYPEDEF */
+
+/* Defined if a `ulong' is typedef'd */
+#define HAVE_ULONG_TYPEDEF 1
+
+/* Defined if a `ushort' is typedef'd */
+#define HAVE_USHORT_TYPEDEF 1
+
+#endif /*GNUPG_CONFIG_H_INCLUDED*/
diff -uNr a/mpi/include/errors.h b/mpi/include/errors.h
--- a/mpi/include/errors.h false
+++ b/mpi/include/errors.h 6c4fab042db987c280ea86471c8549a167903cb11073d0b74a426dc78ce9e65a1b66fb2815722acb069df807506181548960e60c33ee27c64246672a8457f752
@@ -0,0 +1,89 @@
+/* errors.h - erro code
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+#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_INVALID_ARMOR 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
+#define G10ERR_SIG_CLASS 29
+#define G10ERR_BAD_MPI 30
+#define G10ERR_RESOURCE_LIMIT 31
+#define G10ERR_INV_KEYRING 32
+#define G10ERR_TRUSTDB 33 /* a problem with the trustdb */
+#define G10ERR_BAD_CERT 34 /* bad certicate */
+#define G10ERR_INV_USER_ID 35
+#define G10ERR_CLOSE_FILE 36
+#define G10ERR_RENAME_FILE 37
+#define G10ERR_DELETE_FILE 38
+#define G10ERR_UNEXPECTED 39
+#define G10ERR_TIME_CONFLICT 40
+#define G10ERR_WR_PUBKEY_ALGO 41 /* unusabe pubkey algo */
+#define G10ERR_FILE_EXISTS 42
+#define G10ERR_WEAK_KEY 43 /* NOTE: hardcoded into the cipher modules */
+#define G10ERR_WRONG_KEYLEN 44 /* NOTE: hardcoded into the cipher modules */
+#define G10ERR_INV_ARG 45
+#define G10ERR_BAD_URI 46 /* syntax error in URI */
+#define G10ERR_INVALID_URI 47 /* e.g. unsupported scheme */
+#define G10ERR_NETWORK 48 /* general network error */
+#define G10ERR_UNKNOWN_HOST 49
+#define G10ERR_SELFTEST_FAILED 50
+#define G10ERR_NOT_ENCRYPTED 51
+#define G10ERR_NOT_PROCESSED 52
+#define G10ERR_UNU_PUBKEY 53
+#define G10ERR_UNU_SECKEY 54
+#define G10ERR_KEYSERVER 55
+#define G10ERR_CANCELED 56
+#define G10ERR_NO_CARD 57
+#define G10ERR_NO_DATA 58
+
+#ifndef HAVE_STRERROR
+char *strerror (int n);
+#endif
+
+#ifdef _WIN32
+const char * w32_strerror (int w32_errno);
+#endif
+
+#endif /*G10_ERRORS_H*/
diff -uNr a/mpi/include/iobuf.h b/mpi/include/iobuf.h
--- a/mpi/include/iobuf.h false
+++ b/mpi/include/iobuf.h 42269e10b09731558fe6d6e4f8d52f3c3ce10ad1c67496e22f7ec0e19c6d6586f1491921486e90a468905a68d6414d7b7f68914582206ccc2ce2e3ed1e2d3f3d
@@ -0,0 +1,161 @@
+/* iobuf.h - I/O buffer
+ * Copyright (C) 1998, 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#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_CANCEL 6
+#define IOBUFCTRL_USER 16
+
+typedef struct iobuf_struct *IOBUF;
+typedef struct iobuf_struct *iobuf_t;
+
+/* fixme: we should hide most of this stuff */
+struct iobuf_struct {
+ int use; /* 1 input , 2 output, 3 temp */
+ off_t nlimit;
+ off_t nbytes; /* used together with nlimit */
+ off_t ntotal; /* total bytes read (position of stream) */
+ int nofast; /* used by the iobuf_get() */
+ void *directfp;
+ 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;
+ int filter_eof;
+ int error;
+ int (*filter)( void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *len);
+ void *filter_ov; /* value for opaque */
+ int filter_ov_owner;
+ char *real_fname;
+ IOBUF chain; /* next iobuf used for i/o if any (passed to filter) */
+ int no, subno;
+ const char *desc;
+ void *opaque; /* can be used to hold any information */
+ /* this value is copied to all instances */
+ 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;
+ } unget;
+};
+
+#ifndef EXTERN_UNLESS_MAIN_MODULE
+#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
+#define EXTERN_UNLESS_MAIN_MODULE extern
+#else
+#define EXTERN_UNLESS_MAIN_MODULE
+#endif
+#endif
+EXTERN_UNLESS_MAIN_MODULE int iobuf_debug_mode;
+
+void iobuf_enable_special_filenames ( int yes );
+int iobuf_is_pipe_filename (const char *fname);
+IOBUF iobuf_alloc(int use, size_t bufsize);
+IOBUF iobuf_temp(void);
+IOBUF iobuf_temp_with_content( const char *buffer, size_t length );
+IOBUF iobuf_open( const char *fname );
+IOBUF iobuf_fdopen( int fd, const char *mode );
+IOBUF iobuf_sockopen( int fd, const char *mode );
+IOBUF iobuf_create( const char *fname );
+IOBUF iobuf_append( const char *fname );
+IOBUF iobuf_openrw( const char *fname );
+int iobuf_ioctl ( IOBUF a, int cmd, int intval, void *ptrval );
+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_push_filter2( IOBUF a,
+ int (*f)(void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *len),
+ void *ov, int rel_ov );
+int iobuf_flush(IOBUF a);
+void iobuf_clear_eof(IOBUF a);
+#define iobuf_set_error(a) do { (a)->error = 1; } while(0)
+#define iobuf_error(a) ((a)->error)
+
+void iobuf_set_limit( IOBUF a, off_t nlimit );
+
+off_t iobuf_tell( IOBUF a );
+int iobuf_seek( IOBUF a, off_t newpos );
+
+int iobuf_readbyte(IOBUF a);
+int iobuf_read(IOBUF a, byte *buf, unsigned buflen );
+unsigned iobuf_read_line( IOBUF a, byte **addr_of_buffer,
+ unsigned *length_of_buffer, unsigned *max_length );
+int iobuf_peek(IOBUF a, byte *buf, unsigned buflen );
+int iobuf_writebyte(IOBUF a, unsigned c);
+int iobuf_write(IOBUF a, byte *buf, unsigned buflen );
+int iobuf_writestr(IOBUF a, const char *buf );
+
+void iobuf_flush_temp( IOBUF temp );
+int iobuf_write_temp( IOBUF a, IOBUF temp );
+size_t iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen );
+void iobuf_unget_and_close_temp( IOBUF a, IOBUF temp );
+
+int iobuf_get_fd (IOBUF a);
+off_t iobuf_get_filelength (IOBUF a, int *overflow);
+#define IOBUF_FILELENGTH_LIMIT 0xffffffff
+const char *iobuf_get_real_fname( IOBUF a );
+const char *iobuf_get_fname( IOBUF a );
+
+void iobuf_set_partial_block_mode( IOBUF a, size_t len );
+
+int iobuf_translate_file_handle ( int fd, int for_write );
+
+/* 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)->nofast || (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_buffer(a) ( (a)->d.buf )
+#define iobuf_get_temp_length(a) ( (a)->d.len )
+#define iobuf_is_temp(a) ( (a)->use == 3 )
+
+void iobuf_skip_rest (IOBUF a, unsigned long n, int partial);
+
+#endif /*G10_IOBUF_H*/
diff -uNr a/mpi/include/longlong.h b/mpi/include/longlong.h
--- a/mpi/include/longlong.h false
+++ b/mpi/include/longlong.h 042ba62021e6a33fa5f28447d8d268d4fd9a66d49bd10b904aa5f5c9fb6a30345f5cfea787fba1145b328f56e77c39e4d7c3d6df94ccd4b7696b9fe2c8aa7055
@@ -0,0 +1,224 @@
+/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
+ Note: I added some stuff for use with gnupg
+
+Copyright (C) 1991, 1992, 1993, 1994, 1996, 1998,
+ 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+This file is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or (at your
+option) any later version.
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this file; if not, see . */
+
+
+/* You have to define the following before including this file:
+
+ UWtype -- An unsigned type, default type for operations (typically a "word")
+ UHWtype -- An unsigned type, at least half the size of UWtype.
+ UDWtype -- An unsigned type, at least twice as large a UWtype
+ W_TYPE_SIZE -- size in bits of UWtype
+
+ SItype, USItype -- Signed and unsigned 32 bit types.
+ DItype, UDItype -- Signed and unsigned 64 bit types.
+
+ On a 32 bit machine UWtype should typically be USItype;
+ on a 64 bit machine, UWtype should typically be UDItype.
+*/
+
+#define __BITS4 (W_TYPE_SIZE / 4)
+#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
+#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
+
+/* This is used to make sure no undesirable sharing between different libraries
+ that use this file takes place. */
+#ifndef __MPN
+#define __MPN(x) __##x
+#endif
+
+/***************************************
+ *********** Generic Versions ********
+ ***************************************/
+#if !defined (umul_ppmm) && defined (__umulsidi3)
+#define umul_ppmm(ph, pl, m0, m1) \
+ { \
+ UDWtype __ll = __umulsidi3 (m0, m1); \
+ ph = (UWtype) (__ll >> W_TYPE_SIZE); \
+ pl = (UWtype) __ll; \
+ }
+#endif
+
+#if !defined (__umulsidi3)
+#define __umulsidi3(u, v) \
+ ({UWtype __hi, __lo; \
+ umul_ppmm (__hi, __lo, u, v); \
+ ((UDWtype) __hi << W_TYPE_SIZE) | __lo; })
+#endif
+
+/* If this machine has no inline assembler, use C macros. */
+
+#if !defined (add_ssaaaa)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ do { \
+ UWtype __x; \
+ __x = (al) + (bl); \
+ (sh) = (ah) + (bh) + (__x < (al)); \
+ (sl) = __x; \
+ } while (0)
+#endif
+
+#if !defined (sub_ddmmss)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ do { \
+ UWtype __x; \
+ __x = (al) - (bl); \
+ (sh) = (ah) - (bh) - (__x > (al)); \
+ (sl) = __x; \
+ } while (0)
+#endif
+
+#if !defined (umul_ppmm)
+#define umul_ppmm(w1, w0, u, v) \
+ do { \
+ UWtype __x0, __x1, __x2, __x3; \
+ UHWtype __ul, __vl, __uh, __vh; \
+ UWtype __u = (u), __v = (v); \
+ \
+ __ul = __ll_lowpart (__u); \
+ __uh = __ll_highpart (__u); \
+ __vl = __ll_lowpart (__v); \
+ __vh = __ll_highpart (__v); \
+ \
+ __x0 = (UWtype) __ul * __vl; \
+ __x1 = (UWtype) __ul * __vh; \
+ __x2 = (UWtype) __uh * __vl; \
+ __x3 = (UWtype) __uh * __vh; \
+ \
+ __x1 += __ll_highpart (__x0);/* this can't give carry */ \
+ __x1 += __x2; /* but this indeed can */ \
+ if (__x1 < __x2) /* did we get it? */ \
+ __x3 += __ll_B; /* yes, add it in the proper pos. */ \
+ \
+ (w1) = __x3 + __ll_highpart (__x1); \
+ (w0) = (__ll_lowpart (__x1) << W_TYPE_SIZE/2) + __ll_lowpart (__x0);\
+ } while (0)
+#endif
+
+#if !defined (umul_ppmm)
+#define smul_ppmm(w1, w0, u, v) \
+ do { \
+ UWtype __w1; \
+ UWtype __m0 = (u), __m1 = (v); \
+ umul_ppmm (__w1, w0, __m0, __m1); \
+ (w1) = __w1 - (-(__m0 >> (W_TYPE_SIZE - 1)) & __m1) \
+ - (-(__m1 >> (W_TYPE_SIZE - 1)) & __m0); \
+ } while (0)
+#endif
+
+/* Define this unconditionally, so it can be used for debugging. */
+#define __udiv_qrnnd_c(q, r, n1, n0, d) \
+ do { \
+ UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \
+ __d1 = __ll_highpart (d); \
+ __d0 = __ll_lowpart (d); \
+ \
+ __r1 = (n1) % __d1; \
+ __q1 = (n1) / __d1; \
+ __m = (UWtype) __q1 * __d0; \
+ __r1 = __r1 * __ll_B | __ll_highpart (n0); \
+ if (__r1 < __m) \
+ { \
+ __q1--, __r1 += (d); \
+ if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
+ if (__r1 < __m) \
+ __q1--, __r1 += (d); \
+ } \
+ __r1 -= __m; \
+ \
+ __r0 = __r1 % __d1; \
+ __q0 = __r1 / __d1; \
+ __m = (UWtype) __q0 * __d0; \
+ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \
+ if (__r0 < __m) \
+ { \
+ __q0--, __r0 += (d); \
+ if (__r0 >= (d)) \
+ if (__r0 < __m) \
+ __q0--, __r0 += (d); \
+ } \
+ __r0 -= __m; \
+ \
+ (q) = (UWtype) __q1 * __ll_B | __q0; \
+ (r) = __r0; \
+ } while (0)
+
+/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through
+ __udiv_w_sdiv (defined in libgcc or elsewhere). */
+#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd)
+#define udiv_qrnnd(q, r, nh, nl, d) \
+ do { \
+ UWtype __r; \
+ (q) = __MPN(udiv_w_sdiv) (&__r, nh, nl, d); \
+ (r) = __r; \
+ } while (0)
+#endif
+
+/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */
+#if !defined (udiv_qrnnd)
+#define UDIV_NEEDS_NORMALIZATION 1
+#define udiv_qrnnd __udiv_qrnnd_c
+#endif
+
+#if !defined (count_leading_zeros)
+extern
+#ifdef __STDC__
+const
+#endif
+unsigned char __clz_tab[];
+#define MPI_INTERNAL_NEED_CLZ_TAB 1
+#define count_leading_zeros(count, x) \
+ do { \
+ UWtype __xr = (x); \
+ UWtype __a; \
+ \
+ if (W_TYPE_SIZE <= 32) \
+ { \
+ __a = __xr < ((UWtype) 1 << 2*__BITS4) \
+ ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \
+ : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 : 3*__BITS4);\
+ } \
+ else \
+ { \
+ for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \
+ if (((__xr >> __a) & 0xff) != 0) \
+ break; \
+ } \
+ \
+ (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \
+ } while (0)
+/* This version gives a well-defined value for zero. */
+#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE
+#endif
+
+#if !defined (count_trailing_zeros)
+/* Define count_trailing_zeros using count_leading_zeros. The latter might be
+ defined in asm, but if it is not, the C version above is good enough. */
+#define count_trailing_zeros(count, x) \
+ do { \
+ UWtype __ctz_x = (x); \
+ UWtype __ctz_c; \
+ count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \
+ (count) = W_TYPE_SIZE - 1 - __ctz_c; \
+ } while (0)
+#endif
+
+#ifndef UDIV_NEEDS_NORMALIZATION
+#define UDIV_NEEDS_NORMALIZATION 0
+#endif
diff -uNr a/mpi/include/memory.h b/mpi/include/memory.h
--- a/mpi/include/memory.h false
+++ b/mpi/include/memory.h b48416427e71fe46868283490813e4d0a22da9f4b17eff706673a9b05380ae2d85ec9b183db47eaa8aa197b7c7629eb873e63e5f8a66208bf230a794b6967fab
@@ -0,0 +1,105 @@
+/* memory.h - memory allocation
+ * Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#ifndef G10_MEMORY_H
+#define G10_MEMORY_H
+
+#ifdef M_DEBUG
+#ifndef STR
+#define STR(v) #v
+#endif
+#ifndef __riscos__
+#define M_DBGINFO(a) __FUNCTION__ "["__FILE__ ":" STR(a) "]"
+#else /* __riscos__ */
+#define M_DBGINFO(a) "["__FILE__ ":" STR(a) "]"
+#endif /* __riscos__ */
+#define xmalloc(n) m_debug_alloc((n), M_DBGINFO( __LINE__ ) )
+#define xtrymalloc(n) m_debug_trymalloc ((n), M_DBGINFO( __LINE__ ))
+#define xmalloc_clear(n) m_debug_alloc_clear((n), M_DBGINFO(__LINE__) )
+#define xmalloc_secure(n) m_debug_alloc_secure(n), M_DBGINFO(__LINE__) )
+#define xmalloc_secure_clear(n) m_debug_alloc_secure_clear((n), M_DBGINFO(__LINE__) )
+#define xrealloc(n,m) m_debug_realloc((n),(m), M_DBGINFO(__LINE__) )
+#define xfree(n) m_debug_free((n), M_DBGINFO(__LINE__) )
+#define m_check(n) m_debug_check((n), M_DBGINFO(__LINE__) )
+/*#define m_copy(a) m_debug_copy((a), M_DBGINFO(__LINE__) )*/
+#define xstrdup(a) m_debug_strdup((a), M_DBGINFO(__LINE__) )
+#define xtrystrdup(a) m_debug_trystrdup((a), M_DBGINFO(__LINE__) )
+
+void *m_debug_alloc( size_t n, const char *info );
+void *m_debug_trymalloc (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 );
+/*void *m_debug_copy( const void *a, const char *info );*/
+char *m_debug_strdup( const char *a, const char *info );
+char *m_debug_trystrdup (const char *a, const char *info);
+
+#else
+void *xmalloc( size_t n );
+void *xtrymalloc (size_t n);
+void *xmalloc_clear( size_t n );
+void *xmalloc_secure( size_t n );
+void *xmalloc_secure_clear( size_t n );
+void *xrealloc( void *a, size_t n );
+void xfree( void *p );
+void m_check( const void *a );
+/*void *m_copy( const void *a );*/
+char *xstrdup( const char * a);
+char *xtrystrdup (const char *a);
+#endif
+
+size_t m_size( const void *a );
+void m_print_stats(const char *prefix);
+
+/* The follwing functions should be preferred over xmalloc_clear. */
+void *xcalloc (size_t n, size_t m);
+void *xcalloc_secure (size_t n, size_t m);
+
+
+/*-- secmem.c --*/
+int secmem_init( size_t npool );
+void secmem_term( void );
+void *secmem_malloc( size_t size );
+void *secmexrealloc( void *a, size_t newsize );
+void secmem_free( void *a );
+int m_is_secure( const void *p );
+void secmem_dump_stats(void);
+void secmem_set_flags( unsigned flags );
+unsigned secmem_get_flags(void);
+
+
+#define DBG_MEMORY memory_debug_mode
+#define DBG_MEMSTAT memory_stat_debug_mode
+
+#ifndef EXTERN_UNLESS_MAIN_MODULE
+#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
+#define EXTERN_UNLESS_MAIN_MODULE extern
+#else
+#define EXTERN_UNLESS_MAIN_MODULE
+#endif
+#endif
+EXTERN_UNLESS_MAIN_MODULE int memory_debug_mode;
+EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
+
+
+
+#endif /*G10_MEMORY_H*/
diff -uNr a/mpi/include/mpi-asm-defs.h b/mpi/include/mpi-asm-defs.h
--- a/mpi/include/mpi-asm-defs.h false
+++ b/mpi/include/mpi-asm-defs.h fb2afc7686790fa12e3143e79c4728dac3e43c4056c647650d216b7ec7350f7651f6c44c4393858e8bab02719b7674ad7f29e1fcb10511de0a5ae4a2c12af5a6
@@ -0,0 +1,10 @@
+/* This file defines some basic constants for the MPI machinery. We
+ * need to define the types on a per-CPU basis, so it is done with
+ * this file here. */
+#define BYTES_PER_MPI_LIMB (SIZEOF_UNSIGNED_LONG)
+
+
+
+
+
+
diff -uNr a/mpi/include/mpi.h b/mpi/include/mpi.h
--- a/mpi/include/mpi.h false
+++ b/mpi/include/mpi.h e539ef777487b66317cd23b7d19f883a9bab67a9cb984dfb5d1a5df4575a66cb44b7ec199ac0829b1270edfa68f182d646ce944c14f5c401654e1e0f68271baf
@@ -0,0 +1,169 @@
+/* mpi.h - Multi Precision Integers
+ * Copyright (C) 1994, 1996, 1998, 1999,
+ * 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#ifndef G10_MPI_H
+#define G10_MPI_H
+
+#include
+#include
+#include "iobuf.h"
+#include "types.h"
+#include "memory.h"
+
+#ifndef EXTERN_UNLESS_MAIN_MODULE
+#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
+#define EXTERN_UNLESS_MAIN_MODULE extern
+#else
+#define EXTERN_UNLESS_MAIN_MODULE
+#endif
+#endif
+
+#define DBG_MPI mpi_debug_mode
+EXTERN_UNLESS_MAIN_MODULE int mpi_debug_mode;
+
+
+struct gcry_mpi;
+typedef struct gcry_mpi *MPI;
+
+
+/*-- 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_alloc_like(n) mpi_debug_alloc_like((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 );
+MPI mpi_debug_alloc_like( MPI a, 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 );
+MPI mpi_alloc_like( MPI a );
+void mpi_free( MPI a );
+void mpi_resize( MPI a, unsigned nlimbs );
+MPI mpi_copy( MPI a );
+#endif
+#define mpi_is_opaque(a) ((a) && (mpi_get_flags (a)&4))
+MPI mpi_set_opaque( MPI a, void *p, unsigned int len );
+void *mpi_get_opaque( MPI a, unsigned int *len );
+#define mpi_is_secure(a) ((a) && (mpi_get_flags (a)&1))
+void mpi_set_secure( MPI a );
+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);
+int mpi_get_nlimbs (MPI a);
+int mpi_is_neg (MPI a);
+unsigned int mpi_nlimb_hint_from_nbytes (unsigned int nbytes);
+unsigned int mpi_nlimb_hint_from_nbits (unsigned int nbits);
+unsigned int mpi_get_flags (MPI a);
+
+/*-- mpicoder.c --*/
+int mpi_write( IOBUF out, MPI a );
+#ifdef M_DEBUG
+#define mpi_read(a,b,c) mpi_debug_read((a),(b),(c), M_DBGINFO( __LINE__ ) )
+MPI mpi_debug_read(IOBUF inp, unsigned *nread, int secure, const char *info);
+#else
+MPI mpi_read(IOBUF inp, unsigned *nread, int secure);
+#endif
+MPI mpi_read_from_buffer(byte *buffer, unsigned *ret_nread, int secure);
+int mpi_fromstr(MPI val, const char *str);
+int mpi_print( FILE *fp, MPI a, int mode );
+void g10_log_mpidump( const char *text, MPI a );
+u32 mpi_get_keyid( MPI a, u32 *keyid );
+byte *mpi_get_buffer( MPI a, unsigned *nbytes, int *sign );
+byte *mpi_get_secure_buffer( MPI a, unsigned *nbytes, int *sign );
+void mpi_set_buffer( MPI a, const byte *buffer, unsigned nbytes, int sign );
+
+#define log_mpidump g10_log_mpidump
+
+/*-- mpi-add.c --*/
+void mpi_add_ui(MPI w, MPI u, ulong v );
+void mpi_add(MPI w, MPI u, MPI v);
+void mpi_addm(MPI w, MPI u, MPI v, MPI m);
+void mpi_sub_ui(MPI w, MPI u, ulong v );
+void mpi_sub( MPI w, MPI u, MPI v);
+void mpi_subm( MPI w, MPI u, MPI v, MPI m);
+
+/*-- 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);
+void mpi_mulm( MPI w, MPI u, MPI v, MPI m);
+
+/*-- 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);
+void mpi_tdiv_q_2exp( MPI w, MPI u, unsigned count );
+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 exponent, MPI mod);
+
+/*-- mpi-mpow.c --*/
+void mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, 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 idx );
+void mpi_putbyte( MPI a, unsigned idx, int value );
+unsigned mpi_trailing_zeros( MPI a );
+
+/*-- mpi-bit.c --*/
+void mpi_normalize( MPI a );
+unsigned mpi_get_nbits( MPI a );
+int mpi_test_bit( MPI a, unsigned n );
+void mpi_set_bit( MPI a, unsigned n );
+void mpi_set_highbit( MPI a, unsigned n );
+void mpi_clear_highbit( MPI a, unsigned n );
+void mpi_clear_bit( MPI a, unsigned n );
+void mpi_rshift( MPI x, MPI a, unsigned n );
+
+/*-- mpi-inv.c --*/
+void mpi_invm( MPI x, MPI u, MPI v );
+
+#endif /*G10_MPI_H*/
diff -uNr a/mpi/include/mpi-inline.h b/mpi/include/mpi-inline.h
--- a/mpi/include/mpi-inline.h false
+++ b/mpi/include/mpi-inline.h df6064b02a11c90fb20945dad1ecc4753a231f894d6cf60e133d6196d924442e0fa08c1d38421a97511f4007a9545c6a980960a20817e6eaecf4ce36e920f151
@@ -0,0 +1,126 @@
+/* mpi-inline.h - Internal to the Multi Precision Integers
+ * Copyright (C) 1994, 1996, 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#ifndef G10_MPI_INLINE_H
+#define G10_MPI_INLINE_H
+
+#ifndef G10_MPI_INLINE_DECL
+#define G10_MPI_INLINE_DECL extern __inline__
+#endif
+
+G10_MPI_INLINE_DECL 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 */
+}
+
+
+
+G10_MPI_INLINE_DECL 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;
+}
+
+
+G10_MPI_INLINE_DECL 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;
+}
+
+
+
+G10_MPI_INLINE_DECL 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;
+}
+
+#endif /*G10_MPI_INLINE_H*/
diff -uNr a/mpi/include/mpi-internal.h b/mpi/include/mpi-internal.h
--- a/mpi/include/mpi-internal.h false
+++ b/mpi/include/mpi-internal.h 98c4253d69c7531f96dc7631d3d26c5733d5104a3ddbd9eafd622f8aacd8619e71abb55d0c951b148e9d33887dab0edf2cbd9c9b38ca908bc8e04ed930943fde
@@ -0,0 +1,290 @@
+/* mpi-internal.h - Internal to the Multi Precision Integers
+ * Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#ifndef G10_MPI_INTERNAL_H
+#define G10_MPI_INTERNAL_H
+
+#include "mpi.h"
+#include "mpi-asm-defs.h"
+
+#if BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_INT
+ typedef unsigned int mpi_limb_t;
+ typedef signed int mpi_limb_signed_t;
+#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_LONG
+ typedef unsigned long int mpi_limb_t;
+ typedef signed long int mpi_limb_signed_t;
+#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_LONG_LONG
+ typedef unsigned long long int mpi_limb_t;
+ typedef signed long long int mpi_limb_signed_t;
+#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_SHORT
+ typedef unsigned short int mpi_limb_t;
+ typedef signed short int mpi_limb_signed_t;
+#else
+#error BYTES_PER_MPI_LIMB does not match any C type
+#endif
+#define BITS_PER_MPI_LIMB (8*BYTES_PER_MPI_LIMB)
+
+
+struct gcry_mpi {
+ int alloced; /* array size (# of allocated limbs) */
+ int nlimbs; /* number of valid limbs */
+ unsigned int nbits; /* the real number of valid bits (info only) */
+ int sign; /* indicates a negative number */
+ unsigned flags; /* bit 0: array must be allocated in secure memory space */
+ /* bit 1: not used */
+ /* bit 2: the limb is a pointer to some xmalloced data */
+ mpi_limb_t *d; /* array with the limbs */
+};
+
+
+
+/* If KARATSUBA_THRESHOLD is not already defined, define it to a
+ * value which is good on most machines. */
+
+/* tested 4, 16, 32 and 64, where 16 gave the best performance when
+ * checking a 768 and a 1024 bit ElGamal signature.
+ * (wk 22.12.97) */
+#ifndef KARATSUBA_THRESHOLD
+#define KARATSUBA_THRESHOLD 16
+#endif
+
+/* The code can't handle KARATSUBA_THRESHOLD smaller than 2. */
+#if KARATSUBA_THRESHOLD < 2
+#undef KARATSUBA_THRESHOLD
+#define KARATSUBA_THRESHOLD 2
+#endif
+
+
+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_INCR( d, s, n) \
+ do { \
+ mpi_size_t _i; \
+ for( _i = 0; _i < (n); _i++ ) \
+ (d)[_i] = (d)[_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,f) mpi_debug_alloc_limb_space((n),(f), 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, int sec, 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, int sec );
+ void mpi_free_limb_space( mpi_ptr_t a );
+#endif
+void mpi_assign_limb_space( MPI a, mpi_ptr_t ap, unsigned nlimbs );
+
+/*-- mpi-bit.c --*/
+void mpi_rshift_limbs( MPI a, unsigned int count );
+void mpi_lshift_limbs( MPI a, unsigned int count );
+
+
+/*-- 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 --*/
+
+struct karatsuba_ctx {
+ struct karatsuba_ctx *next;
+ mpi_ptr_t tspace;
+ mpi_size_t tspace_size;
+ mpi_ptr_t tp;
+ mpi_size_t tp_size;
+};
+
+void mpihelp_release_karatsuba_ctx( struct karatsuba_ctx *ctx );
+
+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);
+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);
+void mpih_sqr_n_basecase( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size );
+void mpih_sqr_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size,
+ mpi_ptr_t tspace);
+
+void mpihelp_mul_karatsuba_case( mpi_ptr_t prodp,
+ mpi_ptr_t up, mpi_size_t usize,
+ mpi_ptr_t vp, mpi_size_t vsize,
+ struct karatsuba_ctx *ctx );
+
+
+/*-- mpihelp-mul_1.c (or xxx/cpu/ *.S) --*/
+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);
+
+/*-- 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
+
+#ifdef __GNUC__
+#include "mpi-inline.h"
+#endif
+
+#endif /*G10_MPI_INTERNAL_H*/
diff -uNr a/mpi/include/ttyio.h b/mpi/include/ttyio.h
--- a/mpi/include/ttyio.h false
+++ b/mpi/include/ttyio.h 85d1de1e79681b0cece4caea7ca324374fb41317c449585e8cd4d23fae4ef10923285545645fac2921d3c53a0c897e33da32d895b9bd0b761f696d0d8e036479
@@ -0,0 +1,58 @@
+/* ttyio.h
+ * Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+#ifndef G10_TTYIO_H
+#define G10_TTYIO_H
+
+#ifdef HAVE_LIBREADLINE
+#include
+#include
+#endif
+
+const char *tty_get_ttyname (void);
+int tty_batchmode( int onoff );
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
+ void tty_printf (const char *fmt, ... ) __attribute__ ((format (printf,1,2)));
+ void tty_fprintf (FILE *fp, const char *fmt, ... )
+ __attribute__ ((format (printf,2,3)));
+#else
+ void tty_printf (const char *fmt, ... );
+ void tty_fprintf (FILE *fp, const char *fmt, ... );
+#endif
+void tty_print_string( const byte *p, size_t n );
+void tty_print_utf8_string( const byte *p, size_t n );
+void tty_print_utf8_string2( const byte *p, size_t n, size_t max_n );
+char *tty_get( const char *prompt );
+char *tty_get_hidden( const char *prompt );
+void tty_kill_prompt(void);
+int tty_get_answer_is_yes( const char *prompt );
+int tty_no_terminal(int onoff);
+
+#ifdef HAVE_LIBREADLINE
+void tty_enable_completion(rl_completion_func_t *completer);
+void tty_disable_completion(void);
+#else
+/* Use a macro to stub out these functions since a macro has no need
+ to typedef a "rl_completion_func_t" which would be undefined
+ without readline. */
+#define tty_enable_completion(x)
+#define tty_disable_completion()
+#endif
+void tty_cleanup_after_signal (void);
+
+#endif /*G10_TTYIO_H*/
diff -uNr a/mpi/include/types.h b/mpi/include/types.h
--- a/mpi/include/types.h false
+++ b/mpi/include/types.h d355f8bb711647e95451cf2d53f8c496013d9c797acc81560fae155c5850823c880d647347426a4562da568a6cde708fdccbd1e881568816156c0801c7e47fd7
@@ -0,0 +1,142 @@
+/* types.h - some common typedefs
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#ifndef G10_TYPES_H
+#define G10_TYPES_H
+
+#ifdef HAVE_INTTYPES_H
+/* For uint64_t */
+#include
+#endif
+
+/* The AC_CHECK_SIZEOF() in configure fails for some machines.
+ * we provide some fallback values here */
+#if !SIZEOF_UNSIGNED_SHORT
+#undef SIZEOF_UNSIGNED_SHORT
+#define SIZEOF_UNSIGNED_SHORT 2
+#endif
+#if !SIZEOF_UNSIGNED_INT
+#undef SIZEOF_UNSIGNED_INT
+#define SIZEOF_UNSIGNED_INT 4
+#endif
+#if !SIZEOF_UNSIGNED_LONG
+#undef SIZEOF_UNSIGNED_LONG
+#define SIZEOF_UNSIGNED_LONG 4
+#endif
+
+
+#include
+
+
+#ifndef HAVE_BYTE_TYPEDEF
+#undef byte /* maybe there is a macro with this name */
+#ifndef __riscos__
+typedef unsigned char byte;
+#else
+/* Norcroft treats char = unsigned char as legal assignment
+ but char* = unsigned char* as illegal assignment
+ and the same applies to the signed variants as well */
+typedef char byte;
+#endif
+#define HAVE_BYTE_TYPEDEF
+#endif
+
+#ifndef HAVE_USHORT_TYPEDEF
+#undef ushort /* maybe there is a macro with this name */
+typedef unsigned short ushort;
+#define HAVE_USHORT_TYPEDEF
+#endif
+
+#ifndef HAVE_ULONG_TYPEDEF
+#undef ulong /* maybe there is a macro with this name */
+typedef unsigned long ulong;
+#define HAVE_ULONG_TYPEDEF
+#endif
+
+#ifndef HAVE_U16_TYPEDEF
+#undef u16 /* maybe there is a macro with this name */
+#if SIZEOF_UNSIGNED_INT == 2
+typedef unsigned int u16;
+#elif SIZEOF_UNSIGNED_SHORT == 2
+typedef unsigned short u16;
+#else
+#error no typedef for u16
+#endif
+#define HAVE_U16_TYPEDEF
+#endif
+
+#ifndef HAVE_U32_TYPEDEF
+#undef u32 /* maybe there is a macro with this name */
+#if SIZEOF_UNSIGNED_INT == 4
+typedef unsigned int u32;
+#elif SIZEOF_UNSIGNED_LONG == 4
+typedef unsigned long u32;
+#else
+#error no typedef for u32
+#endif
+#define HAVE_U32_TYPEDEF
+#endif
+
+/****************
+ * Warning: Some systems segfault when this u64 typedef and
+ * the dummy code in cipher/md.c is not available. Examples are
+ * Solaris and IRIX.
+ */
+#ifndef HAVE_U64_TYPEDEF
+#undef u64 /* maybe there is a macro with this name */
+#if SIZEOF_UINT64_T == 8
+typedef uint64_t u64;
+#define U64_C(c) (UINT64_C(c))
+#define HAVE_U64_TYPEDEF
+#elif SIZEOF_UNSIGNED_INT == 8
+typedef unsigned int u64;
+#define U64_C(c) (c ## U)
+#define HAVE_U64_TYPEDEF
+#elif SIZEOF_UNSIGNED_LONG == 8
+typedef unsigned long u64;
+#define U64_C(c) (c ## UL)
+#define HAVE_U64_TYPEDEF
+#elif SIZEOF_UNSIGNED_LONG_LONG == 8
+typedef unsigned long long u64;
+#define U64_C(c) (c ## ULL)
+#define HAVE_U64_TYPEDEF
+#endif
+#endif
+
+typedef union {
+ int a;
+ short b;
+ char c[1];
+ long d;
+#ifdef HAVE_U64_TYPEDEF
+ u64 e;
+#endif
+ float f;
+ double g;
+} PROPERLY_ALIGNED_TYPE;
+
+struct string_list {
+ struct string_list *next;
+ unsigned int flags;
+ char d[1];
+};
+typedef struct string_list *STRLIST;
+typedef struct string_list *strlist_t;
+
+#endif /*G10_TYPES_H*/
diff -uNr a/mpi/include/util.h b/mpi/include/util.h
--- a/mpi/include/util.h false
+++ b/mpi/include/util.h 5b4adedb0dda25d37413fd81037ef2d94722cee3b58b5a5314da3816308540588319a280819e272845d154b6f2fdbdcece3a73c15b2802f33bc6bfe484f0b4a5
@@ -0,0 +1,334 @@
+/* util.h
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ * 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+#ifndef G10_UTIL_H
+#define G10_UTIL_H
+
+#if defined (_WIN32) || defined (__CYGWIN32__)
+#include
+#endif
+
+#include "types.h"
+#include "errors.h"
+#include "types.h"
+#include "mpi.h"
+#include "compat.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 idx;
+ int inarg;
+ int stopped;
+ const char *last;
+ void *aliases;
+ const void *cur_alias;
+ } 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 log_set_logfile( const char *name, int fd );
+FILE *log_stream(void);
+void g10_log_print_prefix(const char *text);
+void log_set_name( const char *name );
+const char *log_get_name(void);
+void log_set_pid( int pid );
+int log_get_errorcount( int clear );
+void log_inc_errorcount(void);
+int log_set_strict(int val);
+void g10_log_hexdump( const char *text, const char *buf, size_t len );
+
+#if defined (__riscos__) \
+ || (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ))
+ void g10_log_bug( const char *fmt, ... )
+ __attribute__ ((noreturn, format (printf,1,2)));
+ void g10_log_bug0( const char *, int, const char * ) __attribute__ ((noreturn));
+ void g10_log_fatal( const char *fmt, ... )
+ __attribute__ ((noreturn, format (printf,1,2)));
+ void g10_log_error( const char *fmt, ... ) __attribute__ ((format (printf,1,2)));
+ void g10_log_info( const char *fmt, ... ) __attribute__ ((format (printf,1,2)));
+ void g10_log_warning( const char *fmt, ... ) __attribute__ ((format (printf,1,2)));
+ void g10_log_debug( const char *fmt, ... ) __attribute__ ((format (printf,1,2)));
+#ifndef __riscos__
+#define BUG() g10_log_bug0( __FILE__ , __LINE__, __FUNCTION__ )
+#else
+#define BUG() g10_log_bug0( __FILE__ , __LINE__, __func__ )
+#endif
+#else
+ void g10_log_bug( const char *fmt, ... );
+ void g10_log_bug0( const char *, int );
+ void g10_log_fatal( const char *fmt, ... );
+ void g10_log_error( const char *fmt, ... );
+ void g10_log_info( const char *fmt, ... );
+ void g10_log_warning( const char *fmt, ... );
+ void g10_log_debug( const char *fmt, ... );
+#define BUG() g10_log_bug0( __FILE__ , __LINE__ )
+#endif
+
+#define log_hexdump g10_log_hexdump
+#define log_bug g10_log_bug
+#define log_bug0 g10_log_bug0
+#define log_fatal g10_log_fatal
+#define log_error g10_log_error
+#define log_info g10_log_info
+#define log_warning g10_log_warning
+#define log_debug g10_log_debug
+
+
+/*-- errors.c --*/
+const char * g10_errstr( int no );
+
+/*-- argparse.c --*/
+int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
+int optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
+ ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
+void usage( int level );
+const char *default_strusage( int level );
+
+
+/*-- (main program) --*/
+const char *strusage( int level );
+
+
+/*-- dotlock.c --*/
+struct dotlock_handle;
+typedef struct dotlock_handle *DOTLOCK;
+
+void disable_dotlock(void);
+DOTLOCK create_dotlock( const char *file_to_lock );
+void destroy_dotlock ( DOTLOCK h );
+int make_dotlock( DOTLOCK h, long timeout );
+int release_dotlock( DOTLOCK h );
+void remove_lockfiles (void);
+
+/*-- fileutil.c --*/
+char * make_basename(const char *filepath, const char *inputpath);
+char * make_dirname(const char *filepath);
+char *make_filename( const char *first_part, ... );
+int compare_filenames( const char *a, const char *b );
+int same_file_p (const char *name1, const char *name2);
+const char *print_fname_stdin( const char *s );
+const char *print_fname_stdout( const char *s );
+int is_file_compressed(const char *s, int *r_status);
+
+/*-- miscutil.c --*/
+u32 make_timestamp(void);
+u32 scan_isodatestr( const char *string );
+u32 isotime2seconds (const char *string);
+const char *strtimevalue( u32 stamp );
+const char *strtimestamp( u32 stamp ); /* GMT */
+const char *isotimestamp( u32 stamp ); /* GMT with hh:mm:ss */
+const char *asctimestamp( u32 stamp ); /* localized */
+void print_string( FILE *fp, const byte *p, size_t n, int delim );
+void print_string2( FILE *fp, const byte *p, size_t n, int delim, int delim2 );
+void print_utf8_string( FILE *fp, const byte *p, size_t n );
+void print_utf8_string2( FILE *fp, const byte *p, size_t n, int delim);
+char *make_printable_string( const byte *p, size_t n, int delim );
+int answer_is_yes_no_default( const char *s, int def_answer );
+int answer_is_yes( const char *s );
+int answer_is_yes_no_quit( const char *s );
+int answer_is_okay_cancel (const char *s, int def_answer);
+int match_multistr(const char *multistr,const char *match);
+
+/*-- strgutil.c --*/
+void free_strlist( STRLIST sl );
+#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0)
+STRLIST add_to_strlist( STRLIST *list, const char *string );
+STRLIST add_to_strlist2( STRLIST *list, const char *string, int is_utf8 );
+STRLIST append_to_strlist( STRLIST *list, const char *string );
+STRLIST append_to_strlist2( STRLIST *list, const char *string, int is_utf8 );
+STRLIST strlist_prev( STRLIST head, STRLIST node );
+STRLIST strlist_last( STRLIST node );
+char *pop_strlist( STRLIST *list );
+const char *memistr( const char *buf, size_t buflen, const char *sub );
+const char *ascii_memistr( const char *buf, size_t buflen, const char *sub );
+char *mem2str( char *, const void *, size_t);
+char *trim_spaces( char *string );
+unsigned int trim_trailing_chars( byte *line, unsigned int len,
+ const char *trimchars);
+unsigned int trim_trailing_ws( byte *line, unsigned len );
+unsigned int check_trailing_chars( const byte *line, unsigned int len,
+ const char *trimchars );
+unsigned int check_trailing_ws( const byte *line, unsigned int len );
+int string_count_chr( const char *string, int c );
+int set_native_charset( const char *newset );
+const char* get_native_charset(void);
+char *native_to_utf8( const char *string );
+char *utf8_to_native( const char *string, size_t length, int delim);
+char *string_to_utf8 (const char *string);
+
+int ascii_isupper (int c);
+int ascii_islower (int c);
+int ascii_memcasecmp( const char *a, const char *b, size_t n);
+
+#ifndef HAVE_STPCPY
+char *stpcpy(char *a,const char *b);
+#endif
+#ifndef HAVE_STRLWR
+char *strlwr(char *a);
+#endif
+#ifndef HAVE_STRCASECMP
+int strcasecmp( const char *, const char *b);
+#endif
+#ifndef HAVE_STRNCASECMP
+int strncasecmp (const char *, const char *b, size_t n);
+#endif
+#ifndef HAVE_STRTOUL
+#define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c)))
+#endif
+#ifndef HAVE_MEMMOVE
+#define memmove(d, s, n) bcopy((s), (d), (n))
+#endif
+
+/*-- membuf.c --*/
+/* The definition of the structure is private, we only need it here,
+ so it can be allocated on the stack. */
+struct private_membuf_s {
+ size_t len;
+ size_t size;
+ char *buf;
+ int out_of_core;
+};
+
+typedef struct private_membuf_s membuf_t;
+
+void init_membuf (membuf_t *mb, int initiallen);
+void put_membuf (membuf_t *mb, const void *buf, size_t len);
+void *get_membuf (membuf_t *mb, size_t *len);
+
+
+
+#if defined (_WIN32)
+/*-- w32reg.c --*/
+char *read_w32_registry_string( const char *root,
+ const char *dir, const char *name );
+int write_w32_registry_string(const char *root, const char *dir,
+ const char *name, const char *value);
+
+#endif /*_WIN32*/
+
+/*-- strgutil.c --*/
+char *xasprintf (const char *fmt, ...);
+char *xtryasprintf (const char *fmt, ...);
+
+
+/*-- pka.c --*/
+char *get_pka_info (const char *address, unsigned char *fpr);
+
+/*-- cert.c --*/
+int get_cert(const char *name,size_t max_size,IOBUF *iobuf,
+ unsigned char **fpr,size_t *fpr_len,char **url);
+
+/*-- convert.c --*/
+int hex2bin (const char *string, void *buffer, size_t length);
+int hexcolon2bin (const char *string, void *buffer, size_t length);
+char *bin2hex (const void *buffer, size_t length, char *stringbuf);
+char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
+const char *hex2str (const char *hexstring,
+ char *buffer, size_t bufsize, size_t *buflen);
+char *hex2str_alloc (const char *hexstring, size_t *r_count);
+
+
+/**** other missing stuff ****/
+#ifndef HAVE_ATEXIT /* For SunOS */
+#define atexit(a) (on_exit((a),0))
+#endif
+
+#ifndef HAVE_RAISE
+#define raise(a) kill(getpid(), (a))
+#endif
+
+/*-- Replacement functions from funcname.c --*/
+
+
+
+/******** 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)
+
+#define wipememory2(_ptr,_set,_len) do { volatile char *_vptr=(volatile char *)(_ptr); size_t _vlen=(_len); while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } } while(0)
+#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
+
+/*-- macros to replace ctype ones and avoid locale problems --*/
+#define spacep(p) (*(p) == ' ' || *(p) == '\t')
+#define digitp(p) (*(p) >= '0' && *(p) <= '9')
+#define hexdigitp(a) (digitp (a) \
+ || (*(a) >= 'A' && *(a) <= 'F') \
+ || (*(a) >= 'a' && *(a) <= 'f'))
+/* the atoi macros assume that the buffer has only valid digits */
+#define atoi_1(p) (*(p) - '0' )
+#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
+#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
+#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
+ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+
+/******* RISC OS stuff ***********/
+#ifdef __riscos__
+int riscos_load_module(const char *name, const char * const path[], int fatal);
+int riscos_get_filetype_from_string(const char *string, int len);
+int riscos_get_filetype(const char *filename);
+void riscos_set_filetype_by_number(const char *filename, int type);
+void riscos_set_filetype_by_mimetype(const char *filename, const char *mimetype);
+pid_t riscos_getpid(void);
+int riscos_kill(pid_t pid, int sig);
+int riscos_access(const char *path, int amode);
+int riscos_getchar(void);
+char *riscos_make_basename(const char *filepath, const char *inputpath);
+int riscos_check_regexp(const char *exp, const char *string, int debug);
+int riscos_fdopenfile(const char *filename, const int allow_write);
+void riscos_close_fds(void);
+int riscos_renamefile(const char *old, const char *new);
+char *riscos_gstrans(const char *old);
+void riscos_not_implemented(const char *feature);
+#ifdef DEBUG
+void riscos_dump_fdlist(void);
+void riscos_list_openfiles(void);
+#endif
+#ifndef __RISCOS__C__
+#define getpid riscos_getpid
+#define kill(a,b) riscos_kill((a),(b))
+#define access(a,b) riscos_access((a),(b))
+#endif /* !__RISCOS__C__ */
+#endif /* __riscos__ */
+
+#endif /*G10_UTIL_H*/
diff -uNr a/mpi/iobuf.c b/mpi/iobuf.c
--- a/mpi/iobuf.c false
+++ b/mpi/iobuf.c c5dddd9d52900ba3d847422f9dba2799be2954ad9cca3b9aa6fb1654dd89ee00575c52d15bd65e98d3054d4646943372ca8ad591f610ea7761d21fe4c3ae6187
@@ -0,0 +1,2326 @@
+/* iobuf.c - file handling
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2008,
+ * 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_DOSISH_SYSTEM
+#include
+#endif
+#ifdef __riscos__
+#include
+#include
+#endif /* __riscos__ */
+
+#include "memory.h"
+#include "util.h"
+#include "iobuf.h"
+
+/* The size of the internal buffers.
+ NOTE: If you change this value you MUST also adjust the regression
+ test "armored_key_8192" in armor.test! */
+#define IOBUF_BUFFER_SIZE 8192
+
+
+#undef FILE_FILTER_USES_STDIO
+
+#ifdef HAVE_DOSISH_SYSTEM
+#define USE_SETMODE 1
+#endif
+
+#ifdef FILE_FILTER_USES_STDIO
+#define my_fileno(a) fileno ((a))
+#define my_fopen_ro(a,b) fopen ((a),(b))
+#define my_fopen(a,b) fopen ((a),(b))
+typedef FILE *FILEP_OR_FD;
+#define INVALID_FP NULL
+#define FILEP_OR_FD_FOR_STDIN (stdin)
+#define FILEP_OR_FD_FOR_STDOUT (stdout)
+typedef struct {
+ FILE *fp; /* open file handle */
+ int keep_open;
+ int no_cache;
+ int print_only_name; /* flags indicating that fname is not a real file*/
+ char fname[1]; /* name of the file */
+ } file_filter_ctx_t ;
+#else
+#define my_fileno(a) (a)
+#define my_fopen_ro(a,b) fd_cache_open ((a),(b))
+#define my_fopen(a,b) direct_open ((a),(b))
+#ifdef HAVE_DOSISH_SYSTEM
+typedef HANDLE FILEP_OR_FD;
+#define INVALID_FP ((HANDLE)-1)
+#define FILEP_OR_FD_FOR_STDIN (GetStdHandle (STD_INPUT_HANDLE))
+#define FILEP_OR_FD_FOR_STDOUT (GetStdHandle (STD_OUTPUT_HANDLE))
+#undef USE_SETMODE
+#else
+typedef int FILEP_OR_FD;
+#define INVALID_FP (-1)
+#define FILEP_OR_FD_FOR_STDIN (0)
+#define FILEP_OR_FD_FOR_STDOUT (1)
+#endif
+typedef struct {
+ FILEP_OR_FD fp; /* open file handle */
+ int keep_open;
+ int no_cache;
+ int eof_seen;
+ int print_only_name; /* flags indicating that fname is not a real file*/
+ char fname[1]; /* name of the file */
+ } file_filter_ctx_t ;
+
+ struct close_cache_s {
+ struct close_cache_s *next;
+ FILEP_OR_FD fp;
+ char fname[1];
+ };
+ typedef struct close_cache_s *CLOSE_CACHE;
+ static CLOSE_CACHE close_cache;
+#endif
+
+#ifdef _WIN32
+typedef struct {
+ int sock;
+ int keep_open;
+ int no_cache;
+ int eof_seen;
+ int print_only_name; /* flags indicating that fname is not a real file*/
+ char fname[1]; /* name of the file */
+} sock_filter_ctx_t ;
+#endif /*_WIN32*/
+
+/* The first partial length header block must be of size 512
+ * to make it easier (and efficienter) we use a min. block size of 512
+ * for all chunks (but the last one) */
+#define OP_MIN_PARTIAL_CHUNK 512
+#define OP_MIN_PARTIAL_CHUNK_2POW 9
+
+typedef struct {
+ int use;
+ size_t size;
+ size_t count;
+ int partial; /* 1 = partial header, 2 in last partial packet */
+ char *buffer; /* used for partial header */
+ size_t buflen; /* used size of buffer */
+ int first_c; /* of partial header (which is > 0)*/
+ int eof;
+} block_filter_ctx_t;
+
+static int special_names_enabled;
+
+static int underflow(IOBUF a);
+static int translate_file_handle ( int fd, int for_write );
+
+
+
+#ifndef FILE_FILTER_USES_STDIO
+
+/* This is a replacement for strcmp. Under W32 it does not
+ distinguish between backslash and slash. */
+static int
+fd_cache_strcmp (const char *a, const char *b)
+{
+#ifdef HAVE_DOSISH_SYSTEM
+ for (; *a && *b; a++, b++)
+ {
+ if (*a != *b && !((*a == '/' && *b == '\\')
+ || (*a == '\\' && *b == '/')) )
+ break;
+ }
+ return *(const unsigned char *)a - *(const unsigned char *)b;
+#else
+ return strcmp (a, b);
+#endif
+}
+
+/*
+ * Invalidate (i.e. close) a cached iobuf or all iobufs if NULL is
+ * used for FNAME.
+ */
+static int
+fd_cache_invalidate (const char *fname)
+{
+ CLOSE_CACHE cc;
+ int err=0;
+
+ if (!fname) {
+ if( DBG_IOBUF )
+ log_debug ("fd_cache_invalidate (all)\n");
+
+ for (cc=close_cache; cc; cc = cc->next ) {
+ if ( cc->fp != INVALID_FP ) {
+#ifdef HAVE_DOSISH_SYSTEM
+ CloseHandle (cc->fp);
+#else
+ close(cc->fp);
+#endif
+ cc->fp = INVALID_FP;
+ }
+ }
+ return err;
+ }
+
+ if( DBG_IOBUF )
+ log_debug ("fd_cache_invalidate (%s)\n", fname);
+
+ for (cc=close_cache; cc; cc = cc->next ) {
+ if ( cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname) ) {
+ if( DBG_IOBUF )
+ log_debug (" did (%s)\n", cc->fname);
+#ifdef HAVE_DOSISH_SYSTEM
+ if(CloseHandle (cc->fp)==0)
+ err=-1;
+#else
+ err=close(cc->fp);
+#endif
+ cc->fp = INVALID_FP;
+ }
+ }
+
+ return err;
+}
+
+static int
+fd_cache_synchronize(const char *fname)
+{
+ int err=0;
+
+#ifndef HAVE_DOSISH_SYSTEM
+ CLOSE_CACHE cc;
+
+ if( DBG_IOBUF )
+ log_debug ("fd_cache_synchronize (%s)\n", fname);
+
+ for (cc=close_cache; cc; cc = cc->next )
+ {
+ if ( cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname) )
+ {
+ if( DBG_IOBUF )
+ log_debug (" did (%s)\n", cc->fname);
+
+ err=fsync(cc->fp);
+ }
+ }
+#endif
+
+ return err;
+}
+
+static FILEP_OR_FD
+direct_open (const char *fname, const char *mode)
+{
+#ifdef HAVE_DOSISH_SYSTEM
+ unsigned long da, cd, sm;
+ HANDLE hfile;
+
+ /* Note, that we do not handle all mode combinations */
+
+ /* According to the ReactOS source it seems that open() of the
+ * standard MSW32 crt does open the file in share mode which is
+ * something new for MS applications ;-)
+ */
+ if ( strchr (mode, '+') ) {
+ fd_cache_invalidate (fname);
+ da = GENERIC_READ|GENERIC_WRITE;
+ cd = OPEN_EXISTING;
+ sm = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ }
+ else if ( strchr (mode, 'w') ) {
+ fd_cache_invalidate (fname);
+ da = GENERIC_WRITE;
+ cd = CREATE_ALWAYS;
+ sm = FILE_SHARE_WRITE;
+ }
+ else {
+ da = GENERIC_READ;
+ cd = OPEN_EXISTING;
+ sm = FILE_SHARE_READ;
+ }
+
+ hfile = CreateFile (fname, da, sm, NULL, cd, FILE_ATTRIBUTE_NORMAL, NULL);
+ return hfile;
+#else
+ int oflag;
+ int cflag = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+
+ /* Note, that we do not handle all mode combinations */
+ if ( strchr (mode, '+') ) {
+ fd_cache_invalidate (fname);
+ oflag = O_RDWR;
+ }
+ else if ( strchr (mode, 'w') ) {
+ fd_cache_invalidate (fname);
+ oflag = O_WRONLY | O_CREAT | O_TRUNC;
+ }
+ else {
+ oflag = O_RDONLY;
+ }
+#ifdef O_BINARY
+ if (strchr (mode, 'b'))
+ oflag |= O_BINARY;
+#endif
+#ifndef __riscos__
+ return open (fname, oflag, cflag );
+#else
+ {
+ struct stat buf;
+ int rc = stat( fname, &buf );
+
+ /* Don't allow iobufs on directories */
+ if( !rc && S_ISDIR(buf.st_mode) && !S_ISREG(buf.st_mode) )
+ return __set_errno( EISDIR );
+ else
+ return open( fname, oflag, cflag );
+ }
+#endif
+#endif
+}
+
+
+/*
+ * Instead of closing an FD we keep it open and cache it for later reuse
+ * Note that this caching strategy only works if the process does not chdir.
+ */
+static void
+fd_cache_close (const char *fname, FILEP_OR_FD fp)
+{
+ CLOSE_CACHE cc;
+
+ assert (fp);
+ if ( !fname || !*fname ) {
+#ifdef HAVE_DOSISH_SYSTEM
+ CloseHandle (fp);
+#else
+ close(fp);
+#endif
+ if( DBG_IOBUF )
+ log_debug ("fd_cache_close (%d) real\n", (int)fp);
+ return;
+ }
+ /* try to reuse a slot */
+ for (cc=close_cache; cc; cc = cc->next ) {
+ if ( cc->fp == INVALID_FP && !fd_cache_strcmp (cc->fname, fname) ) {
+ cc->fp = fp;
+ if( DBG_IOBUF )
+ log_debug ("fd_cache_close (%s) used existing slot\n", fname);
+ return;
+ }
+ }
+ /* add a new one */
+ if( DBG_IOBUF )
+ log_debug ("fd_cache_close (%s) new slot created\n", fname);
+ cc = xmalloc_clear (sizeof *cc + strlen (fname));
+ strcpy (cc->fname, fname);
+ cc->fp = fp;
+ cc->next = close_cache;
+ close_cache = cc;
+}
+
+/*
+ * Do an direct_open on FNAME but first try to reuse one from the fd_cache
+ */
+static FILEP_OR_FD
+fd_cache_open (const char *fname, const char *mode)
+{
+ CLOSE_CACHE cc;
+
+ assert (fname);
+ for (cc=close_cache; cc; cc = cc->next ) {
+ if ( cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname) ) {
+ FILEP_OR_FD fp = cc->fp;
+ cc->fp = INVALID_FP;
+ if( DBG_IOBUF )
+ log_debug ("fd_cache_open (%s) using cached fp\n", fname);
+#ifdef HAVE_DOSISH_SYSTEM
+ if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff ) {
+ log_error ("rewind file failed on handle %p: %s\n",
+ fp, w32_strerror (errno));
+ fp = INVALID_FP;
+ }
+#else
+ if ( lseek (fp, 0, SEEK_SET) == (off_t)-1 ) {
+ log_error("can't rewind fd %d: %s\n", fp, strerror(errno) );
+ fp = INVALID_FP;
+ }
+#endif
+ return fp;
+ }
+ }
+ if( DBG_IOBUF )
+ log_debug ("fd_cache_open (%s) not cached\n", fname);
+ return direct_open (fname, mode);
+}
+
+
+#endif /*FILE_FILTER_USES_STDIO*/
+
+
+/****************
+ * 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 may be:
+ * 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.
+ *
+ * IOBUFCTRL_CANCEL: send to all filters on behalf of iobuf_cancel. The
+ * filter may take appropriate action on this message.
+ */
+static int
+file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
+{
+ file_filter_ctx_t *a = opaque;
+ FILEP_OR_FD f = a->fp;
+ size_t size = *ret_len;
+ size_t nbytes = 0;
+ int rc = 0;
+
+#ifdef FILE_FILTER_USES_STDIO
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ assert( size ); /* need a buffer */
+ if ( feof(f)) { /* On terminals you could easiely read as many EOFs as you call */
+ rc = -1; /* fread() or fgetc() repeatly. Every call will block until you press */
+ *ret_len = 0; /* CTRL-D. So we catch this case before we call fread() again. */
+ }
+ else {
+ clearerr( f );
+ nbytes = fread( buf, 1, size, f );
+ if( feof(f) && !nbytes ) {
+ rc = -1; /* okay: we can return EOF now. */
+ }
+ else if( ferror(f) && errno != EPIPE ) {
+ log_error("%s: read error: %s\n",
+ a->fname, strerror(errno));
+ rc = G10ERR_READ_FILE;
+ }
+ *ret_len = nbytes;
+ }
+ }
+ else if( control == IOBUFCTRL_FLUSH ) {
+ if( size ) {
+ clearerr( f );
+ nbytes = fwrite( buf, 1, size, f );
+ if( ferror(f) ) {
+ log_error("%s: write error: %s\n", a->fname, strerror(errno));
+ rc = G10ERR_WRITE_FILE;
+ }
+ }
+ *ret_len = nbytes;
+ }
+ else if( control == IOBUFCTRL_INIT ) {
+ a->keep_open = a->no_cache = 0;
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "file_filter";
+ }
+ else if( control == IOBUFCTRL_FREE ) {
+ if( f != stdin && f != stdout ) {
+ if( DBG_IOBUF )
+ log_debug("%s: close fd %d\n", a->fname, fileno(f) );
+ if (!a->keep_open)
+ fclose(f);
+ }
+ f = NULL;
+ xfree(a); /* we can free our context now */
+ }
+#else /* !stdio implementation */
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ assert( size ); /* need a buffer */
+ if ( a->eof_seen) {
+ rc = -1;
+ *ret_len = 0;
+ }
+ else {
+#ifdef HAVE_DOSISH_SYSTEM
+ unsigned long nread;
+
+ nbytes = 0;
+ if ( !ReadFile ( f, buf, size, &nread, NULL ) ) {
+ if ((int)GetLastError () != ERROR_BROKEN_PIPE) {
+ log_error ("%s: read error: %s\n", a->fname,
+ w32_strerror (0));
+ rc = G10ERR_READ_FILE;
+ }
+ }
+ else if ( !nread ) {
+ a->eof_seen = 1;
+ rc = -1;
+ }
+ else {
+ nbytes = nread;
+ }
+
+#else
+
+ int n;
+
+ nbytes = 0;
+ do {
+ n = read ( f, buf, size );
+ } while (n == -1 && errno == EINTR );
+ if ( n == -1 ) { /* error */
+ if (errno != EPIPE) {
+ log_error("%s: read error: %s\n",
+ a->fname, strerror(errno));
+ rc = G10ERR_READ_FILE;
+ }
+ }
+ else if ( !n ) { /* eof */
+ a->eof_seen = 1;
+ rc = -1;
+ }
+ else {
+ nbytes = n;
+ }
+#endif
+ *ret_len = nbytes;
+ }
+ }
+ else if( control == IOBUFCTRL_FLUSH ) {
+ if( size ) {
+#ifdef HAVE_DOSISH_SYSTEM
+ byte *p = buf;
+ unsigned long n;
+
+ nbytes = size;
+ do {
+ if (size && !WriteFile (f, p, nbytes, &n, NULL)) {
+ log_error ("%s: write error: %s\n", a->fname,
+ w32_strerror (0));
+ rc = G10ERR_WRITE_FILE;
+ break;
+ }
+ p += n;
+ nbytes -= n;
+ } while ( nbytes );
+ nbytes = p - buf;
+#else
+ byte *p = buf;
+ int n;
+
+ nbytes = size;
+ do {
+ do {
+ n = write ( f, p, nbytes );
+ } while ( n == -1 && errno == EINTR );
+ if ( n > 0 ) {
+ p += n;
+ nbytes -= n;
+ }
+ } while ( n != -1 && nbytes );
+ if( n == -1 ) {
+ log_error("%s: write error: %s\n", a->fname, strerror(errno));
+ rc = G10ERR_WRITE_FILE;
+ }
+ nbytes = p - buf;
+#endif
+ }
+ *ret_len = nbytes;
+ }
+ else if ( control == IOBUFCTRL_INIT ) {
+ a->eof_seen = 0;
+ a->keep_open = 0;
+ a->no_cache = 0;
+ }
+ else if ( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "file_filter(fd)";
+ }
+ else if ( control == IOBUFCTRL_FREE ) {
+#ifdef HAVE_DOSISH_SYSTEM
+ if ( f != FILEP_OR_FD_FOR_STDIN && f != FILEP_OR_FD_FOR_STDOUT ) {
+ if( DBG_IOBUF )
+ log_debug("%s: close handle %p\n", a->fname, f );
+ if (!a->keep_open)
+ fd_cache_close (a->no_cache?NULL:a->fname, f);
+ }
+#else
+ if ( (int)f != 0 && (int)f != 1 ) {
+ if( DBG_IOBUF )
+ log_debug("%s: close fd %d\n", a->fname, f );
+ if (!a->keep_open)
+ fd_cache_close (a->no_cache?NULL:a->fname, f);
+ }
+ f = INVALID_FP;
+#endif
+ xfree (a); /* we can free our context now */
+ }
+#endif /* !stdio implementation */
+ return rc;
+}
+
+#ifdef _WIN32
+/* Becuase sockets are an special object under Lose32 we have to
+ * use a special filter */
+static int
+sock_filter (void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
+{
+ sock_filter_ctx_t *a = opaque;
+ size_t size = *ret_len;
+ size_t nbytes = 0;
+ int rc = 0;
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ assert( size ); /* need a buffer */
+ if ( a->eof_seen) {
+ rc = -1;
+ *ret_len = 0;
+ }
+ else {
+ int nread;
+
+ nread = recv ( a->sock, buf, size, 0 );
+ if ( nread == SOCKET_ERROR ) {
+ int ec = (int)WSAGetLastError ();
+ log_error("socket read error: ec=%d\n", ec);
+ rc = G10ERR_READ_FILE;
+ }
+ else if ( !nread ) {
+ a->eof_seen = 1;
+ rc = -1;
+ }
+ else {
+ nbytes = nread;
+ }
+ *ret_len = nbytes;
+ }
+ }
+ else if( control == IOBUFCTRL_FLUSH ) {
+ if( size ) {
+ byte *p = buf;
+ int n;
+
+ nbytes = size;
+ do {
+ n = send (a->sock, p, nbytes, 0);
+ if ( n == SOCKET_ERROR ) {
+ int ec = (int)WSAGetLastError ();
+ log_error("socket write error: ec=%d\n", ec);
+ rc = G10ERR_WRITE_FILE;
+ break;
+ }
+ p += n;
+ nbytes -= n;
+ } while ( nbytes );
+ nbytes = p - buf;
+ }
+ *ret_len = nbytes;
+ }
+ else if ( control == IOBUFCTRL_INIT ) {
+ a->eof_seen = 0;
+ a->keep_open = 0;
+ a->no_cache = 0;
+ }
+ else if ( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "sock_filter";
+ }
+ else if ( control == IOBUFCTRL_FREE ) {
+ if (!a->keep_open)
+ closesocket (a->sock);
+ xfree (a); /* we can free our context now */
+ }
+ return rc;
+}
+#endif /*_WIN32*/
+
+/****************
+ * 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, needed, 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 */
+ if( a->partial == 2 ) {
+ a->eof = 1;
+ if( !n )
+ rc = -1;
+ break;
+ }
+ else if( a->partial ) {
+ /* These OpenPGP introduced huffman like encoded length
+ * bytes are really a mess :-( */
+ if( a->first_c ) {
+ c = a->first_c;
+ a->first_c = 0;
+ }
+ else if( (c = iobuf_get(chain)) == -1 ) {
+ log_error("block_filter: 1st length byte missing\n");
+ rc = G10ERR_READ_FILE;
+ break;
+ }
+ if( c < 192 ) {
+ a->size = c;
+ a->partial = 2;
+ if( !a->size ) {
+ a->eof = 1;
+ if( !n )
+ rc = -1;
+ break;
+ }
+ }
+ else if( c < 224 ) {
+ a->size = (c - 192) * 256;
+ if( (c = iobuf_get(chain)) == -1 ) {
+ log_error("block_filter: 2nd length byte missing\n");
+ rc = G10ERR_READ_FILE;
+ break;
+ }
+ a->size += c + 192;
+ a->partial = 2;
+ if( !a->size ) {
+ a->eof = 1;
+ if( !n )
+ rc = -1;
+ break;
+ }
+ }
+ else if( c == 255 ) {
+ a->size = iobuf_get(chain) << 24;
+ a->size |= iobuf_get(chain) << 16;
+ a->size |= iobuf_get(chain) << 8;
+ if( (c = iobuf_get(chain)) == -1 ) {
+ log_error("block_filter: invalid 4 byte length\n");
+ rc = G10ERR_READ_FILE;
+ break;
+ }
+ a->size |= c;
+ a->partial = 2;
+ if( !a->size ) {
+ a->eof = 1;
+ if( !n )
+ rc = -1;
+ break;
+ }
+ }
+ else { /* next partial body length */
+ a->size = 1 << (c & 0x1f);
+ }
+ /* log_debug("partial: ctx=%p c=%02x size=%u\n", a, c, a->size);*/
+ }
+ else
+ BUG();
+ }
+
+ while( !rc && size && a->size ) {
+ needed = size < a->size ? size : a->size;
+ c = iobuf_read( chain, p, needed );
+ if( c < needed ) {
+ if( c == -1 ) c = 0;
+ log_error("block_filter %p: read error (size=%lu,a->size=%lu)\n",
+ a, (ulong)size+c, (ulong)a->size+c);
+ rc = G10ERR_READ_FILE;
+ }
+ else {
+ size -= c;
+ a->size -= c;
+ p += c;
+ n += c;
+ }
+ }
+ }
+ *ret_len = n;
+ }
+ else if( control == IOBUFCTRL_FLUSH ) {
+ if( a->partial ) { /* the complicated openpgp scheme */
+ size_t blen, n, nbytes = size + a->buflen;
+
+ assert( a->buflen <= OP_MIN_PARTIAL_CHUNK );
+ if( nbytes < OP_MIN_PARTIAL_CHUNK ) {
+ /* not enough to write a partial block out; so we store it*/
+ if( !a->buffer )
+ a->buffer = xmalloc( OP_MIN_PARTIAL_CHUNK );
+ memcpy( a->buffer + a->buflen, buf, size );
+ a->buflen += size;
+ }
+ else { /* okay, we can write out something */
+ /* do this in a loop to use the most efficient block lengths */
+ p = buf;
+ do {
+ /* find the best matching block length - this is limited
+ * by the size of the internal buffering */
+ for( blen=OP_MIN_PARTIAL_CHUNK*2,
+ c=OP_MIN_PARTIAL_CHUNK_2POW+1; blen <= nbytes;
+ blen *=2, c++ )
+ ;
+ blen /= 2; c--;
+ /* write the partial length header */
+ assert( c <= 0x1f ); /*;-)*/
+ c |= 0xe0;
+ iobuf_put( chain, c );
+ if( (n=a->buflen) ) { /* write stuff from the buffer */
+ assert( n == OP_MIN_PARTIAL_CHUNK);
+ if( iobuf_write(chain, a->buffer, n ) )
+ rc = G10ERR_WRITE_FILE;
+ a->buflen = 0;
+ nbytes -= n;
+ }
+ if( (n = nbytes) > blen )
+ n = blen;
+ if( n && iobuf_write(chain, p, n ) )
+ rc = G10ERR_WRITE_FILE;
+ p += n;
+ nbytes -= n;
+ } while( !rc && nbytes >= OP_MIN_PARTIAL_CHUNK );
+ /* store the rest in the buffer */
+ if( !rc && nbytes ) {
+ assert( !a->buflen );
+ assert( nbytes < OP_MIN_PARTIAL_CHUNK );
+ if( !a->buffer )
+ a->buffer = xmalloc( OP_MIN_PARTIAL_CHUNK );
+ memcpy( a->buffer, p, nbytes );
+ a->buflen = nbytes;
+ }
+ }
+ }
+ else
+ BUG();
+ }
+ else if( control == IOBUFCTRL_INIT ) {
+ if( DBG_IOBUF )
+ log_debug("init block_filter %p\n", a );
+ if( a->partial )
+ a->count = 0;
+ else if( a->use == 1 )
+ a->count = a->size = 0;
+ else
+ a->count = a->size; /* force first length bytes */
+ a->eof = 0;
+ a->buffer = NULL;
+ a->buflen = 0;
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "block_filter";
+ }
+ else if( control == IOBUFCTRL_FREE ) {
+ if( a->use == 2 ) { /* write the end markers */
+ if( a->partial ) {
+ u32 len;
+ /* write out the remaining bytes without a partial header
+ * the length of this header may be 0 - but if it is
+ * the first block we are not allowed to use a partial header
+ * and frankly we can't do so, because this length must be
+ * a power of 2. This is _really_ complicated because we
+ * have to check the possible length of a packet prior
+ * to it's creation: a chain of filters becomes complicated
+ * and we need a lot of code to handle compressed packets etc.
+ * :-(((((((
+ */
+ /* construct header */
+ len = a->buflen;
+ /*log_debug("partial: remaining length=%u\n", len );*/
+ if( len < 192 )
+ rc = iobuf_put(chain, len );
+ else if( len < 8384 ) {
+ if( !(rc=iobuf_put( chain, ((len-192) / 256) + 192)) )
+ rc = iobuf_put( chain, ((len-192) % 256));
+ }
+ else { /* use a 4 byte header */
+ if( !(rc=iobuf_put( chain, 0xff )) )
+ if( !(rc=iobuf_put( chain, (len >> 24)&0xff )) )
+ if( !(rc=iobuf_put( chain, (len >> 16)&0xff )) )
+ if( !(rc=iobuf_put( chain, (len >> 8)&0xff )))
+ rc=iobuf_put( chain, len & 0xff );
+ }
+ if( !rc && len )
+ rc = iobuf_write(chain, a->buffer, len );
+ if( rc ) {
+ log_error("block_filter: write error: %s\n",strerror(errno));
+ rc = G10ERR_WRITE_FILE;
+ }
+ xfree( a->buffer ); a->buffer = NULL; a->buflen = 0;
+ }
+ else
+ BUG();
+ }
+ else if( a->size ) {
+ log_error("block_filter: pending bytes!\n");
+ }
+ if( DBG_IOBUF )
+ log_debug("free block_filter %p\n", a );
+ xfree(a); /* we can free our context now */
+ }
+
+ return rc;
+}
+
+
+static void
+print_chain( IOBUF a )
+{
+ if( !DBG_IOBUF )
+ return;
+ for(; a; a = a->chain ) {
+ size_t dummy_len = 0;
+ const char *desc = "[none]";
+
+ if( a->filter )
+ a->filter( a->filter_ov, IOBUFCTRL_DESC, NULL,
+ (byte*)&desc, &dummy_len );
+
+ log_debug("iobuf chain: %d.%d `%s' filter_eof=%d start=%d len=%d\n",
+ a->no, a->subno, desc?desc:"?", a->filter_eof,
+ (int)a->d.start, (int)a->d.len );
+ }
+}
+
+int
+iobuf_print_chain( IOBUF a )
+{
+ print_chain(a);
+ return 0;
+}
+
+/****************
+ * Allocate a new io buffer, with no function assigned.
+ * Use is the desired usage: 1 for input, 2 for output, 3 for temp buffer
+ * BUFSIZE is a suggested buffer size.
+ */
+IOBUF
+iobuf_alloc(int use, size_t bufsize)
+{
+ IOBUF a;
+ static int number=0;
+
+ a = xmalloc_clear(sizeof *a);
+ a->use = use;
+ a->d.buf = xmalloc( bufsize );
+ a->d.size = bufsize;
+ a->no = ++number;
+ a->subno = 0;
+ a->opaque = NULL;
+ a->real_fname = NULL;
+ return a;
+}
+
+int
+iobuf_close ( IOBUF a )
+{
+ IOBUF a2;
+ size_t dummy_len=0;
+ int rc=0;
+
+ if( a && a->directfp ) {
+ fclose( a->directfp );
+ xfree( a->real_fname );
+ if( DBG_IOBUF )
+ log_debug("iobuf_close -> %p\n", a->directfp );
+ return 0;
+ }
+
+ for( ; a && !rc ; a = a2 ) {
+ a2 = a->chain;
+ if( a->use == 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?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) );
+ xfree(a->real_fname);
+ if (a->d.buf) {
+ memset (a->d.buf, 0, a->d.size); /* erase the buffer */
+ xfree(a->d.buf);
+ }
+ xfree(a);
+ }
+ return rc;
+}
+
+int
+iobuf_cancel( IOBUF a )
+{
+ const char *s;
+ IOBUF a2;
+ int rc;
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ char *remove_name = NULL;
+#endif
+
+ if( a && a->use == 2 ) {
+ s = iobuf_get_real_fname(a);
+ if( s && *s ) {
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ remove_name = xstrdup ( s );
+#else
+ remove(s);
+#endif
+ }
+ }
+
+ /* send a cancel message to all filters */
+ for( a2 = a; a2 ; a2 = a2->chain ) {
+ size_t dummy;
+ if( a2->filter )
+ a2->filter( a2->filter_ov, IOBUFCTRL_CANCEL, a2->chain,
+ NULL, &dummy );
+ }
+
+ rc = iobuf_close(a);
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ if ( remove_name ) {
+ /* Argg, MSDOS does not allow to remove open files. So
+ * we have to do it here */
+ remove ( remove_name );
+ xfree ( remove_name );
+ }
+#endif
+ return rc;
+}
+
+
+/****************
+ * 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, IOBUF_BUFFER_SIZE );
+
+ return a;
+}
+
+IOBUF
+iobuf_temp_with_content( const char *buffer, size_t length )
+{
+ IOBUF a;
+
+ a = iobuf_alloc(3, length );
+ memcpy( a->d.buf, buffer, length );
+ a->d.len = length;
+
+ return a;
+}
+
+void
+iobuf_enable_special_filenames ( int yes )
+{
+ special_names_enabled = yes;
+}
+
+/*
+ * see whether the filename has the for "-&nnnn", where n is a
+ * non-zero number.
+ * Returns this number or -1 if it is not the case.
+ */
+static int
+check_special_filename ( const char *fname )
+{
+ if ( special_names_enabled
+ && fname && *fname == '-' && fname[1] == '&' ) {
+ int i;
+
+ fname += 2;
+ for (i=0; digitp (fname+i); i++ )
+ ;
+ if ( !fname[i] )
+ return atoi (fname);
+ }
+ return -1;
+}
+
+/* This fucntion returns true if FNAME indicates a PIPE (stdout or
+ stderr) or a special file name if those are enabled. */
+int
+iobuf_is_pipe_filename (const char *fname)
+{
+ if (!fname || (*fname=='-' && !fname[1]) )
+ return 1;
+ return check_special_filename (fname) != -1;
+}
+
+/****************
+ * 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;
+ FILEP_OR_FD fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+ int print_only = 0;
+ int fd;
+
+ if( !fname || (*fname=='-' && !fname[1]) ) {
+ fp = FILEP_OR_FD_FOR_STDIN;
+#ifdef USE_SETMODE
+ setmode ( my_fileno(fp) , O_BINARY );
+#endif
+ fname = "[stdin]";
+ print_only = 1;
+ }
+ else if ( (fd = check_special_filename ( fname )) != -1 )
+ return iobuf_fdopen ( translate_file_handle (fd,0), "rb" );
+ else if( (fp = my_fopen_ro(fname, "rb")) == INVALID_FP )
+ return NULL;
+ a = iobuf_alloc(1, IOBUF_BUFFER_SIZE );
+ fcx = xmalloc( sizeof *fcx + strlen(fname) );
+ fcx->fp = fp;
+ fcx->print_only_name = print_only;
+ strcpy(fcx->fname, fname );
+ if( !print_only )
+ a->real_fname = xstrdup( 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' fd=%d\n",
+ a->no, a->subno, fname, (int)my_fileno(fcx->fp) );
+
+ return a;
+}
+
+/****************
+ * Create a head iobuf for reading from a file
+ * returns: NULL if an error occures and sets errno
+ */
+IOBUF
+iobuf_fdopen( int fd, const char *mode )
+{
+ IOBUF a;
+ FILEP_OR_FD fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+
+#ifdef FILE_FILTER_USES_STDIO
+ if( !(fp = fdopen(fd, mode)) )
+ return NULL;
+#else
+ fp = (FILEP_OR_FD)fd;
+#endif
+ a = iobuf_alloc( strchr( mode, 'w')? 2:1, IOBUF_BUFFER_SIZE );
+ fcx = xmalloc( sizeof *fcx + 20 );
+ fcx->fp = fp;
+ fcx->print_only_name = 1;
+ sprintf(fcx->fname, "[fd %d]", fd );
+ 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: fdopen `%s'\n", a->no, a->subno, fcx->fname );
+ iobuf_ioctl (a,3,1,NULL); /* disable fd caching */
+ return a;
+}
+
+
+IOBUF
+iobuf_sockopen ( int fd, const char *mode )
+{
+ IOBUF a;
+#ifdef _WIN32
+ sock_filter_ctx_t *scx;
+ size_t len;
+
+ a = iobuf_alloc( strchr( mode, 'w')? 2:1, IOBUF_BUFFER_SIZE );
+ scx = xmalloc( sizeof *scx + 25 );
+ scx->sock = fd;
+ scx->print_only_name = 1;
+ sprintf(scx->fname, "[sock %d]", fd );
+ a->filter = sock_filter;
+ a->filter_ov = scx;
+ sock_filter( scx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
+ sock_filter( scx, IOBUFCTRL_INIT, NULL, NULL, &len );
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: sockopen `%s'\n", a->no, a->subno, scx->fname);
+ iobuf_ioctl (a,3,1,NULL); /* disable fd caching */
+#else
+ a = iobuf_fdopen (fd, mode);
+#endif
+ return a;
+}
+
+/****************
+ * create an iobuf for writing to a file; the file will be created.
+ */
+IOBUF
+iobuf_create( const char *fname )
+{
+ IOBUF a;
+ FILEP_OR_FD fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+ int print_only = 0;
+ int fd;
+
+ if( !fname || (*fname=='-' && !fname[1]) ) {
+ fp = FILEP_OR_FD_FOR_STDOUT;
+#ifdef USE_SETMODE
+ setmode ( my_fileno(fp) , O_BINARY );
+#endif
+ fname = "[stdout]";
+ print_only = 1;
+ }
+ else if ( (fd = check_special_filename ( fname )) != -1 )
+ return iobuf_fdopen ( translate_file_handle (fd, 1), "wb" );
+ else if( (fp = my_fopen(fname, "wb")) == INVALID_FP )
+ return NULL;
+ a = iobuf_alloc(2, IOBUF_BUFFER_SIZE );
+ fcx = xmalloc( sizeof *fcx + strlen(fname) );
+ fcx->fp = fp;
+ fcx->print_only_name = print_only;
+ strcpy(fcx->fname, fname );
+ if( !print_only )
+ a->real_fname = xstrdup( 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?a->desc:"?" );
+
+ return a;
+}
+
+/****************
+ * append to an iobuf; if the file does not exist, create it.
+ * cannot be used for stdout.
+ * Note: This is not used.
+ */
+#if 0 /* not used */
+IOBUF
+iobuf_append( const char *fname )
+{
+ IOBUF a;
+ FILE *fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+
+ if( !fname )
+ return NULL;
+ else if( !(fp = my_fopen(fname, "ab")) )
+ return NULL;
+ a = iobuf_alloc(2, IOBUF_BUFFER_SIZE );
+ fcx = xmalloc( sizeof *fcx + strlen(fname) );
+ fcx->fp = fp;
+ strcpy(fcx->fname, fname );
+ a->real_fname = xstrdup( 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: append `%s'\n", a->no, a->subno,
+ a->desc?a->desc:"?" );
+
+ return a;
+}
+#endif
+
+IOBUF
+iobuf_openrw( const char *fname )
+{
+ IOBUF a;
+ FILEP_OR_FD fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+
+ if( !fname )
+ return NULL;
+ else if( (fp = my_fopen(fname, "r+b")) == INVALID_FP )
+ return NULL;
+ a = iobuf_alloc(2, IOBUF_BUFFER_SIZE );
+ fcx = xmalloc( sizeof *fcx + strlen(fname) );
+ fcx->fp = fp;
+ strcpy(fcx->fname, fname );
+ a->real_fname = xstrdup( 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: openrw `%s'\n", a->no, a->subno,
+ a->desc?a->desc:"?");
+
+ return a;
+}
+
+
+int
+iobuf_ioctl ( IOBUF a, int cmd, int intval, void *ptrval )
+{
+ if ( cmd == 1 ) { /* keep system filepointer/descriptor open */
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: ioctl `%s' keep=%d\n",
+ a? a->no:-1, a?a->subno:-1,
+ a&&a->desc?a->desc:"?", intval );
+ for( ; a; a = a->chain )
+ if( !a->chain && a->filter == file_filter ) {
+ file_filter_ctx_t *b = a->filter_ov;
+ b->keep_open = intval;
+ return 0;
+ }
+#ifdef _WIN32
+ else if( !a->chain && a->filter == sock_filter ) {
+ sock_filter_ctx_t *b = a->filter_ov;
+ b->keep_open = intval;
+ return 0;
+ }
+#endif
+ }
+ else if ( cmd == 2 ) { /* invalidate cache */
+ if( DBG_IOBUF )
+ log_debug("iobuf-*.*: ioctl `%s' invalidate\n",
+ ptrval? (char*)ptrval:"[all]");
+ if ( !a && !intval ) {
+#ifndef FILE_FILTER_USES_STDIO
+ return fd_cache_invalidate (ptrval);
+#endif
+ return 0;
+ }
+ }
+ else if ( cmd == 3 ) { /* disallow/allow caching */
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: ioctl `%s' no_cache=%d\n",
+ a? a->no:-1, a?a->subno:-1,
+ a&&a->desc?a->desc:"?", intval );
+ for( ; a; a = a->chain )
+ if( !a->chain && a->filter == file_filter ) {
+ file_filter_ctx_t *b = a->filter_ov;
+ b->no_cache = intval;
+ return 0;
+ }
+#ifdef _WIN32
+ else if( !a->chain && a->filter == sock_filter ) {
+ sock_filter_ctx_t *b = a->filter_ov;
+ b->no_cache = intval;
+ return 0;
+ }
+#endif
+ }
+ else if(cmd==4)
+ {
+ /* Do a fsync on the open fd and return any errors to the
+ caller of iobuf_ioctl */
+ if( DBG_IOBUF )
+ log_debug("iobuf-*.*: ioctl `%s' fsync\n",
+ ptrval? (char*)ptrval:"");
+
+ if(!a && !intval && ptrval)
+ {
+#ifndef FILE_FILTER_USES_STDIO
+ return fd_cache_synchronize (ptrval);
+#else
+ return 0;
+#endif
+ }
+ }
+
+ return -1;
+}
+
+
+/****************
+ * 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 )
+{
+ return iobuf_push_filter2( a, f, ov, 0 );
+}
+
+int
+iobuf_push_filter2( IOBUF a,
+ int (*f)(void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *len),
+ void *ov, int rel_ov )
+{
+ IOBUF b;
+ size_t dummy_len=0;
+ int rc=0;
+
+ if( a->directfp )
+ BUG();
+
+ if( a->use == 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 = xmalloc(sizeof *b);
+ memcpy(b, a, sizeof *b );
+ /* fixme: it is stupid to keep a copy of the name at every level
+ * but we need the name somewhere because the name known by file_filter
+ * may have been released when we need the name of the file */
+ b->real_fname = a->real_fname? xstrdup(a->real_fname):NULL;
+ /* remove the filter stuff from the new stream */
+ a->filter = NULL;
+ a->filter_ov = NULL;
+ a->filter_ov_owner = 0;
+ a->filter_eof = 0;
+ if( a->use == 3 )
+ a->use = 2; /* make a write stream from a temp stream */
+
+ if( a->use == 2 ) { /* allocate a fresh buffer for the original stream */
+ b->d.buf = xmalloc( a->d.size );
+ b->d.len = 0;
+ b->d.start = 0;
+ }
+ else { /* allocate a fresh buffer for the new stream */
+ a->d.buf = xmalloc( a->d.size );
+ a->d.len = 0;
+ a->d.start = 0;
+ }
+ /* disable nlimit for the new stream */
+ a->ntotal = b->ntotal + b->nbytes;
+ a->nlimit = a->nbytes = 0;
+ a->nofast &= ~1;
+ /* make a link from the new stream to the original stream */
+ a->chain = b;
+ a->opaque = b->opaque;
+
+ /* setup the function on the new stream */
+ a->filter = f;
+ a->filter_ov = ov;
+ a->filter_ov_owner = rel_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?a->desc:"?" );
+ print_chain( a );
+ }
+
+ /* 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.
+ */
+static int
+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( a->directfp )
+ BUG();
+
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: pop `%s'\n", a->no, a->subno,
+ a->desc?a->desc:"?" );
+ if( !a->filter ) { /* this is simple */
+ b = a->chain;
+ assert(b);
+ xfree(a->d.buf);
+ xfree(a->real_fname);
+ memcpy(a,b, sizeof *a);
+ xfree(b);
+ return 0;
+ }
+ for(b=a ; b; b = b->chain )
+ if( b->filter == f && (!ov || b->filter_ov == ov) )
+ break;
+ if( !b )
+ log_bug("pop_filter(): filter function not found\n");
+
+ /* flush this stream if it is an output stream */
+ if( a->use == 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( b->filter && (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;
+ }
+ if( b->filter_ov && b->filter_ov_owner ) {
+ xfree( b->filter_ov );
+ b->filter_ov = NULL;
+ }
+
+
+ /* and see 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;
+ xfree(a->d.buf);
+ xfree(a->real_fname);
+ memcpy(a,b, sizeof *a);
+ xfree(b);
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: popped filter\n", a->no, a->subno );
+ }
+ else if( !b->chain ) { /* remove the last iobuf from the chain */
+ log_bug("Ohh jeee, trying to remove 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;
+
+ assert( a->d.start == a->d.len );
+ if( a->use == 3 )
+ return -1; /* EOF because a temp buffer can't do an underflow */
+
+ if( a->filter_eof ) {
+ if( a->chain ) {
+ IOBUF b = a->chain;
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: pop `%s' in underflow\n",
+ a->no, a->subno, a->desc?a->desc:"?" );
+ xfree(a->d.buf);
+ xfree(a->real_fname);
+ memcpy(a, b, sizeof *a);
+ xfree(b);
+ print_chain(a);
+ }
+ else
+ a->filter_eof = 0; /* for the top level filter */
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: underflow: eof (due to filter eof)\n",
+ a->no, a->subno );
+ return -1; /* return one(!) EOF */
+ }
+ if( a->error ) {
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: error\n", a->no, a->subno );
+ return -1;
+ }
+
+ if( a->directfp ) {
+ FILE *fp = a->directfp;
+
+ len = fread( a->d.buf, 1, a->d.size, fp);
+ if( len < a->d.size ) {
+ if( ferror(fp) )
+ a->error = 1;
+ }
+ a->d.len = len;
+ a->d.start = 0;
+ return len? a->d.buf[a->d.start++] : -1;
+ }
+
+
+ if( a->filter ) {
+ len = a->d.size;
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: underflow: req=%lu\n",
+ a->no, a->subno, (ulong)len );
+ rc = a->filter( a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain,
+ a->d.buf, &len );
+ if( DBG_IOBUF ) {
+ log_debug("iobuf-%d.%d: underflow: got=%lu rc=%d\n",
+ a->no, a->subno, (ulong)len, rc );
+/* if( a->no == 1 ) */
+/* log_hexdump (" data:", a->d.buf, len); */
+ }
+ if( a->use == 1 && rc == -1 ) { /* EOF: we can remove the filter */
+ size_t dummy_len=0;
+
+ /* and tell the filter to free itself */
+ if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain,
+ NULL, &dummy_len)) )
+ log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
+ if( a->filter_ov && a->filter_ov_owner ) {
+ xfree( a->filter_ov );
+ a->filter_ov = NULL;
+ }
+ a->filter = NULL;
+ a->desc = NULL;
+ a->filter_ov = NULL;
+ a->filter_eof = 1;
+ if( !len && a->chain ) {
+ IOBUF b = a->chain;
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: pop in underflow (!len)\n",
+ a->no, a->subno);
+ xfree(a->d.buf);
+ xfree(a->real_fname);
+ memcpy(a,b, sizeof *a);
+ xfree(b);
+ print_chain(a);
+ }
+ }
+ else if( rc )
+ a->error = 1;
+
+ if( !len ) {
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: underflow: eof\n", a->no, a->subno );
+ return -1;
+ }
+ a->d.len = len;
+ a->d.start = 0;
+ return a->d.buf[a->d.start++];
+ }
+ else {
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: underflow: eof (no filter)\n",
+ a->no, a->subno );
+ return -1; /* no filter; return EOF */
+ }
+}
+
+
+int
+iobuf_flush(IOBUF a)
+{
+ size_t len;
+ int rc;
+
+ if( a->directfp )
+ return 0;
+
+ if( a->use == 3 ) { /* increase the temp buffer */
+ char *newbuf;
+ size_t newsize = a->d.size + IOBUF_BUFFER_SIZE;
+
+ if( DBG_IOBUF )
+ log_debug("increasing temp iobuf from %lu to %lu\n",
+ (ulong)a->d.size, (ulong)newsize );
+ newbuf = xmalloc( newsize );
+ memcpy( newbuf, a->d.buf, a->d.len );
+ xfree(a->d.buf);
+ a->d.buf = newbuf;
+ a->d.size = newsize;
+ return 0;
+ }
+ else if( a->use != 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;
+ }
+ else if( rc )
+ a->error = 1;
+ a->d.len = 0;
+
+ return rc;
+}
+
+
+/****************
+ * Read a byte from the iobuf; returns -1 on EOF
+ */
+int
+iobuf_readbyte(IOBUF a)
+{
+ int c;
+
+ /* nlimit does not work together with unget */
+ /* nbytes is also not valid! */
+ if( a->unget.buf ) {
+ if( a->unget.start < a->unget.len )
+ return a->unget.buf[a->unget.start++];
+ xfree(a->unget.buf);
+ a->unget.buf = NULL;
+ a->nofast &= ~2;
+ }
+
+ 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++;
+ return c;
+}
+
+
+int
+iobuf_read(IOBUF a, byte *buf, unsigned buflen )
+{
+ int c, n;
+
+ if( a->unget.buf || a->nlimit ) {
+ /* handle special cases */
+ for(n=0 ; n < buflen; n++ ) {
+ if( (c = iobuf_readbyte(a)) == -1 ) {
+ if( !n )
+ return -1; /* eof */
+ break;
+ }
+ else
+ if( buf ) *buf = c;
+ if( buf ) buf++;
+ }
+ return n;
+ }
+
+ n = 0;
+ do {
+ if( n < buflen && a->d.start < a->d.len ) {
+ unsigned size = a->d.len - a->d.start;
+ if( size > buflen - n )
+ size = buflen - n;
+ if( buf )
+ memcpy( buf, a->d.buf + a->d.start, size );
+ n += size;
+ a->d.start += size;
+ if( buf )
+ buf += size;
+ }
+ if( n < buflen ) {
+ if( (c=underflow(a)) == -1 ) {
+ a->nbytes += n;
+ return n? n : -1/*EOF*/;
+ }
+ if( buf )
+ *buf++ = c;
+ n++;
+ }
+ } while( n < buflen );
+ a->nbytes += n;
+ return n;
+}
+
+
+/****************
+ * Have a look at the iobuf.
+ * NOTE: This only works in special cases.
+ */
+int
+iobuf_peek(IOBUF a, byte *buf, unsigned buflen )
+{
+ int n=0;
+
+ if( a->filter_eof )
+ return -1;
+
+ if( !(a->d.start < a->d.len) ) {
+ if( underflow(a) == -1 )
+ return -1;
+ /* and unget this character */
+ assert(a->d.start == 1);
+ a->d.start = 0;
+ }
+
+ for(n=0 ; n < buflen && (a->d.start+n) < a->d.len ; n++, buf++ )
+ *buf = a->d.buf[n];
+ return n;
+}
+
+
+
+
+int
+iobuf_writebyte(IOBUF a, unsigned c)
+{
+
+ if( a->directfp )
+ BUG();
+
+ 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 )
+{
+
+ if( a->directfp )
+ BUG();
+
+ do {
+ if( buflen && a->d.len < a->d.size ) {
+ unsigned size = a->d.size - a->d.len;
+ if( size > buflen ) size = buflen;
+ memcpy( a->d.buf + a->d.len, buf, size );
+ buflen -= size;
+ buf += size;
+ a->d.len += size;
+ }
+ if( buflen ) {
+ if( iobuf_flush(a) )
+ return -1;
+ }
+ } while( buflen );
+ return 0;
+}
+
+
+int
+iobuf_writestr(IOBUF a, const char *buf )
+{
+ for( ; *buf; 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 )
+{
+ while( temp->chain )
+ pop_filter( temp, temp->filter, NULL );
+ 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;
+}
+
+
+/****************
+ * Call this function to terminate processing of the temp stream
+ * without closing it. This removes all filters from the stream
+ * makes sure that iobuf_get_temp_{buffer,length}() returns correct
+ * values.
+ */
+void
+iobuf_flush_temp( IOBUF temp )
+{
+ while( temp->chain )
+ pop_filter( temp, temp->filter, NULL );
+}
+
+
+/****************
+ * Set a limit on how many bytes may be read from the input stream A.
+ * Setting the limit to 0 disables this feature.
+ */
+void
+iobuf_set_limit( IOBUF a, off_t nlimit )
+{
+ if( nlimit )
+ a->nofast |= 1;
+ else
+ a->nofast &= ~1;
+ a->nlimit = nlimit;
+ a->ntotal += a->nbytes;
+ a->nbytes = 0;
+}
+
+
+
+/* Return the length of an open file A. IF OVERFLOW is not NULL it
+ will be set to true if the file is larger than what off_t can cope
+ with. The function return 0 on error or on overflow condition. */
+off_t
+iobuf_get_filelength (IOBUF a, int *overflow )
+{
+ struct stat st;
+
+ if (overflow)
+ *overflow = 0;
+
+ if( a->directfp ) {
+ FILE *fp = a->directfp;
+
+ if( !fstat(fileno(fp), &st) )
+ return st.st_size;
+ log_error("fstat() failed: %s\n", strerror(errno) );
+ return 0;
+ }
+
+ /* Hmmm: file_filter may have already been removed */
+ for( ; a; a = a->chain )
+ if( !a->chain && a->filter == file_filter ) {
+ file_filter_ctx_t *b = a->filter_ov;
+ FILEP_OR_FD fp = b->fp;
+
+#if defined(HAVE_DOSISH_SYSTEM) && !defined(FILE_FILTER_USES_STDIO)
+ ulong size;
+ static int (* __stdcall get_file_size_ex)
+ (void *handle, LARGE_INTEGER *size);
+ static int get_file_size_ex_initialized;
+
+ if (!get_file_size_ex_initialized)
+ {
+ void *handle;
+
+ handle = dlopen ("kernel32.dll", RTLD_LAZY);
+ if (handle)
+ {
+ get_file_size_ex = dlsym (handle, "GetFileSizeEx");
+ if (!get_file_size_ex)
+ dlclose (handle);
+ }
+ get_file_size_ex_initialized = 1;
+ }
+
+ if (get_file_size_ex)
+ {
+ /* This is a newer system with GetFileSizeEx; we use
+ this then becuase it seem that GetFileSize won't
+ return a proper error in case a file is larger than
+ 4GB. */
+ LARGE_INTEGER size;
+
+ if (get_file_size_ex (fp, &size))
+ {
+ if (!size.u.HighPart)
+ return size.u.LowPart;
+ if (overflow)
+ *overflow = 1;
+ return 0;
+ }
+ }
+ else
+ {
+ if ((size=GetFileSize (fp, NULL)) != 0xffffffff)
+ return size;
+ }
+ log_error ("GetFileSize for handle %p failed: %s\n",
+ fp, w32_strerror (0));
+#else
+ if( !fstat(my_fileno(fp), &st) )
+ return st.st_size;
+ log_error("fstat() failed: %s\n", strerror(errno) );
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+
+/* Return the file descriptor of the underlying file or -1 if it is
+ not available. */
+int
+iobuf_get_fd (IOBUF a)
+{
+ if (a->directfp)
+ return fileno ( (FILE*)a->directfp );
+
+ for ( ; a; a = a->chain )
+ if (!a->chain && a->filter == file_filter)
+ {
+ file_filter_ctx_t *b = a->filter_ov;
+ FILEP_OR_FD fp = b->fp;
+
+ return my_fileno (fp);
+ }
+
+ return -1;
+}
+
+
+/****************
+ * Tell the file position, where the next read will take place
+ */
+off_t
+iobuf_tell( IOBUF a )
+{
+ return a->ntotal + a->nbytes;
+}
+
+
+#if !defined(HAVE_FSEEKO) && !defined(fseeko)
+
+#ifdef HAVE_LIMITS_H
+# include
+#endif
+#ifndef LONG_MAX
+# define LONG_MAX ((long) ((unsigned long) -1 >> 1))
+#endif
+#ifndef LONG_MIN
+# define LONG_MIN (-1 - LONG_MAX)
+#endif
+
+/****************
+ * A substitute for fseeko, for hosts that don't have it.
+ */
+static int
+fseeko( FILE *stream, off_t newpos, int whence )
+{
+ while( newpos != (long) newpos ) {
+ long pos = newpos < 0 ? LONG_MIN : LONG_MAX;
+ if( fseek( stream, pos, whence ) != 0 )
+ return -1;
+ newpos -= pos;
+ whence = SEEK_CUR;
+ }
+ return fseek( stream, (long)newpos, whence );
+}
+#endif
+
+/****************
+ * This is a very limited implementation. It simply discards all internal
+ * buffering and removes all filters but the first one.
+ */
+int
+iobuf_seek( IOBUF a, off_t newpos )
+{
+ file_filter_ctx_t *b = NULL;
+
+ if( a->directfp ) {
+ FILE *fp = a->directfp;
+ if( fseeko( fp, newpos, SEEK_SET ) ) {
+ log_error("can't seek: %s\n", strerror(errno) );
+ return -1;
+ }
+ clearerr(fp);
+ }
+ else {
+ for( ; a; a = a->chain ) {
+ if( !a->chain && a->filter == file_filter ) {
+ b = a->filter_ov;
+ break;
+ }
+ }
+ if( !a )
+ return -1;
+#ifdef FILE_FILTER_USES_STDIO
+ if( fseeko( b->fp, newpos, SEEK_SET ) ) {
+ log_error("can't fseek: %s\n", strerror(errno) );
+ return -1;
+ }
+#else
+#ifdef HAVE_DOSISH_SYSTEM
+ if (SetFilePointer (b->fp, newpos, NULL, FILE_BEGIN) == 0xffffffff ) {
+ log_error ("SetFilePointer failed on handle %p: %s\n",
+ b->fp, w32_strerror (0));
+ return -1;
+ }
+#else
+ if ( lseek (b->fp, newpos, SEEK_SET) == (off_t)-1 ) {
+ log_error("can't lseek: %s\n", strerror(errno) );
+ return -1;
+ }
+#endif
+#endif
+ }
+ a->d.len = 0; /* discard buffer */
+ a->d.start = 0;
+ a->nbytes = 0;
+ a->nlimit = 0;
+ a->nofast &= ~1;
+ a->ntotal = newpos;
+ a->error = 0;
+ /* remove filters, but the last */
+ if( a->chain )
+ log_debug("pop_filter called in iobuf_seek - please report\n");
+ while( a->chain )
+ pop_filter( a, a->filter, NULL );
+
+ return 0;
+}
+
+
+
+
+
+
+/****************
+ * Retrieve the real filename
+ */
+const char *
+iobuf_get_real_fname( IOBUF a )
+{
+ if( a->real_fname )
+ return a->real_fname;
+
+ /* the old solution */
+ for( ; a; a = a->chain )
+ if( !a->chain && a->filter == file_filter ) {
+ file_filter_ctx_t *b = a->filter_ov;
+ return b->print_only_name? NULL : b->fname;
+ }
+
+ return NULL;
+}
+
+
+/****************
+ * Retrieve the filename
+ */
+const char *
+iobuf_get_fname( IOBUF a )
+{
+ for( ; a; a = a->chain )
+ if( !a->chain && a->filter == file_filter ) {
+ file_filter_ctx_t *b = a->filter_ov;
+ return b->fname;
+ }
+
+ return NULL;
+}
+
+
+/****************
+ * enable partial block mode as described in the OpenPGP draft.
+ * LEN is the first length byte on read, but ignored on writes.
+ */
+void
+iobuf_set_partial_block_mode( IOBUF a, size_t len )
+{
+ block_filter_ctx_t *ctx = xmalloc_clear( sizeof *ctx );
+
+ assert( a->use == 1 || a->use == 2 );
+ ctx->use = a->use;
+ if( !len ) {
+ if( a->use == 1 )
+ log_debug("pop_filter called in set_partial_block_mode"
+ " - please report\n");
+ pop_filter(a, block_filter, NULL );
+ }
+ else {
+ ctx->partial = 1;
+ ctx->size = 0;
+ ctx->first_c = len;
+ iobuf_push_filter(a, block_filter, ctx );
+ }
+}
+
+
+/****************
+ * Same as fgets() but if the buffer is too short a larger one will
+ * be allocated up to some limit *max_length.
+ * A line is considered a byte stream ending in a LF.
+ * Returns the length of the line. EOF is indicated by a line of
+ * length zero. The last LF may be missing due to an EOF.
+ * is max_length is zero on return, the line has been truncated.
+ *
+ * Note: The buffer is allocated with enough space to append a CR,LF,EOL
+ */
+unsigned
+iobuf_read_line( IOBUF a, byte **addr_of_buffer,
+ unsigned *length_of_buffer, unsigned *max_length )
+{
+ int c;
+ char *buffer = *addr_of_buffer;
+ unsigned length = *length_of_buffer;
+ unsigned nbytes = 0;
+ unsigned maxlen = *max_length;
+ char *p;
+
+ if( !buffer ) { /* must allocate a new buffer */
+ length = 256;
+ buffer = xmalloc( length );
+ *addr_of_buffer = buffer;
+ *length_of_buffer = length;
+ }
+
+ length -= 3; /* reserve 3 bytes (cr,lf,eol) */
+ p = buffer;
+ while( (c=iobuf_get(a)) != -1 ) {
+ if( nbytes == length ) { /* increase the buffer */
+ if( length > maxlen ) { /* this is out limit */
+ /* skip the rest of the line */
+ while( c != '\n' && (c=iobuf_get(a)) != -1 )
+ ;
+ *p++ = '\n'; /* always append a LF (we have reserved space) */
+ nbytes++;
+ *max_length = 0; /* indicate truncation */
+ break;
+ }
+ length += 3; /* correct for the reserved byte */
+ length += length < 1024? 256 : 1024;
+ buffer = xrealloc( buffer, length );
+ *addr_of_buffer = buffer;
+ *length_of_buffer = length;
+ length -= 3; /* and reserve again */
+ p = buffer + nbytes;
+ }
+ *p++ = c;
+ nbytes++;
+ if( c == '\n' )
+ break;
+ }
+ *p = 0; /* make sure the line is a string */
+
+ return nbytes;
+}
+
+/* This is the non iobuf specific function */
+int
+iobuf_translate_file_handle ( int fd, int for_write )
+{
+#ifdef _WIN32
+ {
+ int x;
+
+ if ( fd <= 2 )
+ return fd; /* do not do this for error, stdin, stdout, stderr */
+
+ x = _open_osfhandle ( fd, for_write? 1:0 );
+ if (x==-1 )
+ log_error ("failed to translate osfhandle %p\n", (void*)fd );
+ else {
+ /*log_info ("_open_osfhandle %p yields %d%s\n",
+ (void*)fd, x, for_write? " for writing":"" );*/
+ fd = x;
+ }
+ }
+#endif
+ return fd;
+}
+
+static int
+translate_file_handle ( int fd, int for_write )
+{
+#ifdef _WIN32
+#ifdef FILE_FILTER_USES_STDIO
+ fd = iobuf_translate_file_handle (fd, for_write);
+#else
+ {
+ int x;
+
+ if ( fd == 0 )
+ x = (int)GetStdHandle (STD_INPUT_HANDLE);
+ else if (fd == 1)
+ x = (int)GetStdHandle (STD_OUTPUT_HANDLE);
+ else if (fd == 2)
+ x = (int)GetStdHandle (STD_ERROR_HANDLE);
+ else
+ x = fd;
+
+ if (x == -1)
+ log_debug ("GetStdHandle(%d) failed: %s\n",
+ fd, w32_strerror (0));
+
+ fd = x;
+ }
+#endif
+#endif
+ return fd;
+}
+
+
+void
+iobuf_skip_rest(IOBUF a, unsigned long n, int partial)
+{
+ if ( partial ) {
+ for (;;) {
+ if (a->nofast || a->d.start >= a->d.len) {
+ if (iobuf_readbyte (a) == -1) {
+ break;
+ }
+ } else {
+ unsigned long count = a->d.len - a->d.start;
+ a->nbytes += count;
+ a->d.start = a->d.len;
+ }
+ }
+ } else {
+ unsigned long remaining = n;
+ while (remaining > 0) {
+ if (a->nofast || a->d.start >= a->d.len) {
+ if (iobuf_readbyte (a) == -1) {
+ break;
+ }
+ --remaining;
+ } else {
+ unsigned long count = a->d.len - a->d.start;
+ if (count > remaining) {
+ count = remaining;
+ }
+ a->nbytes += count;
+ a->d.start += count;
+ remaining -= count;
+ }
+ }
+ }
+}
diff -uNr a/mpi/logger.c b/mpi/logger.c
--- a/mpi/logger.c false
+++ b/mpi/logger.c a4ca272e00eba069786cb1edfb3f7054c5b31630a22ae66c012878d4bcee96b11298141730589f0a0ddb04eeff1c2f4eef5a25d88447226f32eaa5346595ea96
@@ -0,0 +1,262 @@
+/* logger.c - log functions
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "util.h"
+
+static char pidstring[15];
+static char *pgm_name;
+static int errorcount;
+static int strict;
+static FILE *logfp;
+
+/****************
+ * Set the logfile to use (not yet implemneted) or, if logfile is NULL,
+ * the Fd where logoutputs should go.
+ */
+void
+log_set_logfile( const char *name, int fd )
+{
+ if( name )
+ BUG();
+
+ if( logfp && logfp != stderr && logfp != stdout )
+ fclose( logfp );
+ if( fd == 1 )
+ logfp = stdout;
+ else if( fd == 2 )
+ logfp = stderr;
+ else
+ logfp = fdopen( fd, "a" );
+ if( !logfp ) {
+ logfp = stderr;
+ log_fatal("can't open fd %d for logging: %s\n", fd, strerror(errno));
+ }
+}
+
+FILE *
+log_stream()
+{
+ if( !logfp )
+ logfp = stderr;
+ return logfp;
+}
+
+
+void
+log_set_name( const char *name )
+{
+ xfree(pgm_name);
+ if( name )
+ pgm_name = xstrdup(name);
+ else
+ pgm_name = NULL;
+}
+
+const char *
+log_get_name(void)
+{
+ return pgm_name? pgm_name : "";
+}
+
+
+void
+log_set_pid( int pid )
+{
+ if( pid )
+ sprintf(pidstring,"[%u]", (unsigned)pid );
+ else
+ *pidstring = 0;
+}
+
+int
+log_get_errorcount( int clear)
+{
+ int n = errorcount;
+ if( clear )
+ errorcount = 0;
+ return n;
+}
+
+void
+log_inc_errorcount()
+{
+ errorcount++;
+}
+
+int
+log_set_strict(int val)
+{
+ int old=strict;
+ strict=val;
+ return old;
+}
+
+void
+g10_log_print_prefix(const char *text)
+{
+ if( !logfp )
+ logfp = stderr;
+ if( pgm_name )
+ fprintf(logfp, "%s%s: %s", pgm_name, pidstring, text );
+ else
+ fprintf(logfp, "?%s: %s", pidstring, text );
+#ifdef __riscos__
+ fflush( logfp );
+#endif /* __riscos__ */
+}
+
+
+void
+g10_log_info( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ g10_log_print_prefix("");
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(logfp,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+#ifdef __riscos__
+ fflush( logfp );
+#endif /* __riscos__ */
+}
+
+
+void
+g10_log_warning( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ if(strict)
+ {
+ errorcount++;
+ g10_log_print_prefix(_("ERROR: "));
+ }
+ else
+ g10_log_print_prefix(_("WARNING: "));
+
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(logfp,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+#ifdef __riscos__
+ fflush( logfp );
+#endif /* __riscos__ */
+}
+
+
+void
+g10_log_error( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ g10_log_print_prefix("");
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(logfp,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ errorcount++;
+#ifdef __riscos__
+ fflush( logfp );
+#endif /* __riscos__ */
+}
+
+
+void
+g10_log_fatal( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ g10_log_print_prefix("fatal: ");
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(logfp,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ secmem_dump_stats();
+#ifdef __riscos__
+ fflush( logfp );
+#endif /* __riscos__ */
+ exit(2);
+}
+
+void
+g10_log_bug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ putc('\n', stderr );
+ g10_log_print_prefix("Ohhhh jeeee: ");
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ fflush(stderr);
+ secmem_dump_stats();
+ abort();
+}
+
+#if defined (__riscos__) \
+ || ( __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ))
+void
+g10_log_bug0( const char *file, int line, const char *func )
+{
+ log_bug(_("... this is a bug (%s:%d:%s)\n"), file, line, func );
+}
+#else
+void
+g10_log_bug0( const char *file, int line )
+{
+ log_bug(_("you found a bug ... (%s:%d)\n"), file, line);
+}
+#endif
+
+void
+g10_log_debug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ g10_log_print_prefix("DBG: ");
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(logfp,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+#ifdef __riscos__
+ fflush( logfp );
+#endif /* __riscos__ */
+}
+
+
+
+void
+g10_log_hexdump( const char *text, const char *buf, size_t len )
+{
+ int i;
+
+ g10_log_print_prefix(text);
+ for(i=0; i < len; i++ )
+ fprintf(logfp, " %02X", ((const byte*)buf)[i] );
+ fputc('\n', logfp);
+#ifdef __riscos__
+ fflush( logfp );
+#endif /* __riscos__ */
+}
+
+
+
diff -uNr a/mpi/Makefile b/mpi/Makefile
--- a/mpi/Makefile false
+++ b/mpi/Makefile d946187edc8013acec997499092eb30464487922925230fbfe5d21ea6cd76320625e947b8f47cf19ec4c47987cc5dcd0c22e6dbfb4b40e4b0f93189c29b5bfc9
@@ -0,0 +1,25 @@
+PROGRAM = mpi.a
+
+BUILD=obj
+DIST=bin
+
+CXX = gcc
+OBJECTS = $(addprefix $(BUILD)/, $(patsubst %.c,%.o,$(wildcard *.c)))
+FLAGS = -g -Wall
+INCLUDE = -I include
+
+.SUFFIXES: .o .c
+
+$(BUILD)/%.o:
+ $(CXX) $(FLAGS) $(INCLUDE) -c $*.c -o $@
+
+all: $(PROGRAM)
+
+$(PROGRAM): $(OBJECTS)
+ ar rcs $(DIST)/$(PROGRAM) $(OBJECTS)
+
+clean :
+ rm -rf nul core *flymake* $(BUILD)/*.o $(DIST)/$(PROGRAM) *~ bin/*
+
+check-syntax:
+ $(CXX) -c $(FLAGS) $(INCLUDE) -o nul -Wall -S $(CHK_SOURCES)
diff -uNr a/mpi/memory.c b/mpi/memory.c
--- a/mpi/memory.c false
+++ b/mpi/memory.c 9dea2170de57ac92123d3dac0fd5930bc5c1a5ac88ca1c2fda88c8555091a38e5862fd7ac5bced9393349f66ab970707b27d759fe0041f358a0d205e066ecde0
@@ -0,0 +1,681 @@
+/* memory.c - memory allocation
+ * Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ *
+ * We use our own memory allocation functions instead of plain malloc(),
+ * so that we can provide some special enhancements:
+ * a) functions to provide memory from a secure memory.
+ * b) by looking at the requested allocation size we
+ * can reuse memory very quickly (e.g. MPI storage)
+ * (really needed?)
+ * c) memory usage reporting if compiled with M_DEBUG
+ * d) memory checking if compiled with M_GUARD
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "types.h"
+#include "memory.h"
+#include "util.h"
+
+
+#define MAGIC_NOR_BYTE 0x55
+#define MAGIC_SEC_BYTE 0xcc
+#define MAGIC_END_BYTE 0xaa
+
+/* This is a very crude alignment check which does not work on all CPUs
+ * IIRC, I once introduced it for testing on an Alpha. We should better
+ * replace this guard stuff with one provided by a modern malloc library
+ */
+#if SIZEOF_UNSIGNED_LONG == 8
+#define EXTRA_ALIGN 4
+#else
+#define EXTRA_ALIGN 0
+#endif
+
+#if defined(M_DEBUG) || defined(M_GUARD)
+ static void membug( const char *fmt, ... );
+#endif
+
+#ifdef M_DEBUG
+
+#ifndef M_GUARD
+#define M_GUARD 1
+#endif
+#undef xmalloc
+#undef xtrymalloc
+#undef xmalloc_clear
+#undef xmalloc_secure
+#undef xmalloc_secure_clear
+#undef xrealloc
+#undef xfree
+#undef m_check
+#undef xstrdup
+#undef xtrystrdup
+#define FNAME(a) m_debug_ ##a
+#define FNAMEX(a) m_debug_ ##a
+#define FNAMEXM(a) m_debug_ ##a
+#define FNAMEPRT , const char *info
+#define FNAMEARG , info
+#ifndef __riscos__
+#define store_len(p,n,m) do { add_entry(p,n,m, \
+ info, __FUNCTION__); } while(0)
+#else
+#define store_len(p,n,m) do { add_entry(p,n,m, \
+ info, __func__ ); } while(0)
+#endif
+#else
+#define FNAME(a) m_ ##a
+#define FNAMEX(a) x ##a
+#define FNAMEXM(a) xm ##a
+#define FNAMEPRT
+#define FNAMEARG
+#define store_len(p,n,m) do { ((byte*)p)[EXTRA_ALIGN+0] = n; \
+ ((byte*)p)[EXTRA_ALIGN+1] = n >> 8 ; \
+ ((byte*)p)[EXTRA_ALIGN+2] = n >> 16 ; \
+ ((byte*)p)[EXTRA_ALIGN+3] = m? MAGIC_SEC_BYTE \
+ : MAGIC_NOR_BYTE; \
+ } while(0)
+#endif
+
+
+#ifdef M_GUARD
+static long used_memory;
+#endif
+
+#ifdef M_DEBUG /* stuff used for memory debuging */
+
+struct info_entry {
+ struct info_entry *next;
+ unsigned count; /* call count */
+ const char *info; /* the reference to the info string */
+};
+
+struct memtbl_entry {
+ const void *user_p; /* for reference: the pointer given to the user */
+ size_t user_n; /* length requested by the user */
+ struct memtbl_entry *next; /* to build a list of unused entries */
+ const struct info_entry *info; /* points into the table with */
+ /* the info strings */
+ unsigned inuse:1; /* this entry is in use */
+ unsigned count:31;
+};
+
+
+#define INFO_BUCKETS 53
+#define info_hash(p) ( *(u32*)((p)) % INFO_BUCKETS )
+static struct info_entry *info_strings[INFO_BUCKETS]; /* hash table */
+
+static struct memtbl_entry *memtbl; /* the table with the memory info */
+static unsigned memtbl_size; /* number of allocated entries */
+static unsigned memtbl_len; /* number of used entries */
+static struct memtbl_entry *memtbl_unused;/* to keep track of unused entries */
+
+static void dump_table_at_exit(void);
+static void dump_table(void);
+static void check_allmem( const char *info );
+
+/****************
+ * Put the new P into the debug table and return a pointer to the table entry.
+ * mode is true for security. BY is the name of the function which called us.
+ */
+static void
+add_entry( byte *p, unsigned n, int mode, const char *info, const char *by )
+{
+ unsigned index;
+ struct memtbl_entry *e;
+ struct info_entry *ie;
+
+ if( memtbl_len < memtbl_size )
+ index = memtbl_len++;
+ else {
+ struct memtbl_entry *e;
+ /* look for a used entry in the table. We take the first one,
+ * so that freed entries remain as long as possible in the table
+ * (free appends a new one)
+ */
+ if( (e = memtbl_unused) ) {
+ index = e - memtbl;
+ memtbl_unused = e->next;
+ e->next = NULL;
+ }
+ else { /* no free entries in the table: extend the table */
+ if( !memtbl_size ) { /* first time */
+ memtbl_size = 100;
+ if( !(memtbl = calloc( memtbl_size, sizeof *memtbl )) )
+ membug("memory debug table malloc failed\n");
+ index = 0;
+ memtbl_len = 1;
+ atexit( dump_table_at_exit );
+ }
+ else { /* realloc */
+ unsigned n = memtbl_size / 4; /* enlarge by 25% */
+ if(!(memtbl = realloc(memtbl, (memtbl_size+n)*sizeof *memtbl)))
+ membug("memory debug table realloc failed\n");
+ memset(memtbl+memtbl_size, 0, n*sizeof *memtbl );
+ memtbl_size += n;
+ index = memtbl_len++;
+ }
+ }
+ }
+ e = memtbl+index;
+ if( e->inuse )
+ membug("Ooops: entry %u is flagged as in use\n", index);
+ e->user_p = p + EXTRA_ALIGN + 4;
+ e->user_n = n;
+ e->count++;
+ if( e->next )
+ membug("Ooops: entry is in free entry list\n");
+ /* do we already have this info string */
+ for( ie = info_strings[info_hash(info)]; ie; ie = ie->next )
+ if( ie->info == info )
+ break;
+ if( !ie ) { /* no: make a new entry */
+ if( !(ie = malloc( sizeof *ie )) )
+ membug("can't allocate info entry\n");
+ ie->next = info_strings[info_hash(info)];
+ info_strings[info_hash(info)] = ie;
+ ie->info = info;
+ ie->count = 0;
+ }
+ ie->count++;
+ e->info = ie;
+ e->inuse = 1;
+
+ /* put the index at the start of the memory */
+ p[EXTRA_ALIGN+0] = index;
+ p[EXTRA_ALIGN+1] = index >> 8 ;
+ p[EXTRA_ALIGN+2] = index >> 16 ;
+ p[EXTRA_ALIGN+3] = mode? MAGIC_SEC_BYTE : MAGIC_NOR_BYTE ;
+ if( DBG_MEMORY )
+ log_debug( "%s allocates %u bytes using %s\n", info, e->user_n, by );
+}
+
+
+
+/****************
+ * Check that the memory block is correct. The magic byte has already been
+ * checked. Checks which are done here:
+ * - see whether the index points into our memory table
+ * - see whether P is the same as the one stored in the table
+ * - see whether we have already freed this block.
+ */
+struct memtbl_entry *
+check_mem( const byte *p, const char *info )
+{
+ unsigned n;
+ struct memtbl_entry *e;
+
+ n = p[EXTRA_ALIGN+0];
+ n |= p[EXTRA_ALIGN+1] << 8;
+ n |= p[EXTRA_ALIGN+2] << 16;
+
+ if( n >= memtbl_len )
+ membug("memory at %p corrupted: index=%u table_len=%u (%s)\n",
+ p+EXTRA_ALIGN+4, n, memtbl_len, info );
+ e = memtbl+n;
+
+ if( e->user_p != p+EXTRA_ALIGN+4 )
+ membug("memory at %p corrupted: reference mismatch (%s)\n",
+ p+EXTRA_ALIGN+4, info );
+ if( !e->inuse )
+ membug("memory at %p corrupted: marked as free (%s)\n",
+ p+EXTRA_ALIGN+4, info );
+
+ if( !(p[EXTRA_ALIGN+3] == MAGIC_NOR_BYTE
+ || p[EXTRA_ALIGN+3] == MAGIC_SEC_BYTE) )
+ membug("memory at %p corrupted: underflow=%02x (%s)\n",
+ p+EXTRA_ALIGN+4, p[EXTRA_ALIGN+3], info );
+ if( p[EXTRA_ALIGN+4+e->user_n] != MAGIC_END_BYTE )
+ membug("memory at %p corrupted: overflow=%02x (%s)\n",
+ p+EXTRA_ALIGN+4, p[EXTRA_ALIGN+4+e->user_n], info );
+ return e;
+}
+
+
+/****************
+ * free the entry and the memory (replaces free)
+ */
+static void
+free_entry( byte *p, const char *info )
+{
+ struct memtbl_entry *e, *e2;
+
+ check_allmem("add_entry");
+
+ e = check_mem(p, info);
+ if( DBG_MEMORY )
+ log_debug( "%s frees %u bytes alloced by %s\n",
+ info, e->user_n, e->info->info );
+ if( !e->inuse ) {
+ if( e->user_p == p + EXTRA_ALIGN+ 4 )
+ membug("freeing an already freed pointer at %p\n", p+EXTRA_ALIGN+4 );
+ else
+ membug("freeing pointer %p which is flagged as freed\n", p+EXTRA_ALIGN+4 );
+ }
+
+ e->inuse = 0;
+ e->next = NULL;
+ if( !memtbl_unused )
+ memtbl_unused = e;
+ else {
+ for(e2=memtbl_unused; e2->next; e2 = e2->next )
+ ;
+ e2->next = e;
+ }
+ if( m_is_secure(p+EXTRA_ALIGN+4) )
+ secmem_free(p);
+ else {
+ memset(p,'f', e->user_n+5);
+ free(p);
+ }
+}
+
+static void
+dump_entry(struct memtbl_entry *e )
+{
+ unsigned n = e - memtbl;
+
+ fprintf(stderr, "mem %4u%c %5u %p %5u %s (%u)\n",
+ n, e->inuse?'a':'u', e->count, e->user_p, e->user_n,
+ e->info->info, e->info->count );
+
+
+}
+
+
+static void
+dump_table_at_exit( void)
+{
+ if( DBG_MEMSTAT )
+ dump_table();
+}
+
+static void
+dump_table( void)
+{
+ unsigned n;
+ struct memtbl_entry *e;
+ ulong sum = 0, chunks =0;
+
+ for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) {
+ if(e->inuse) {
+ dump_entry(e);
+ sum += e->user_n;
+ chunks++;
+ }
+ }
+ fprintf(stderr, " memory used: %8lu bytes in %ld chunks\n",
+ sum, chunks );
+}
+
+
+static void
+check_allmem( const char *info )
+{
+ unsigned n;
+ struct memtbl_entry *e;
+
+ for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) {
+ if( e->inuse ) {
+#ifndef __riscos__
+ check_mem(e->user_p-4-EXTRA_ALIGN, info);
+#else
+ check_mem((const byte *) e->user_p-4-EXTRA_ALIGN, info);
+#endif
+ }
+ }
+}
+
+#endif /* M_DEBUG */
+
+#if defined(M_DEBUG) || defined(M_GUARD)
+static void
+membug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "\nMemory Error: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ fflush(stderr);
+#ifdef M_DEBUG
+ if( DBG_MEMSTAT )
+ dump_table();
+#endif
+ abort();
+}
+#endif
+
+void
+m_print_stats( const char *prefix )
+{
+#ifdef M_DEBUG
+ unsigned n;
+ struct memtbl_entry *e;
+ ulong sum = 0, chunks =0;
+
+ for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) {
+ if(e->inuse) {
+ sum += e->user_n;
+ chunks++;
+ }
+ }
+
+ log_debug( "%s%smemstat: %8lu bytes in %ld chunks used\n",
+ prefix? prefix:"", prefix? ": ":"", sum, chunks );
+#elif defined(M_GUARD)
+ log_debug( "%s%smemstat: %8ld bytes\n",
+ prefix? prefix:"", prefix? ": ":"", used_memory );
+#endif
+}
+
+void
+m_dump_table( const char *prefix )
+{
+#ifdef M_DEBUG
+ fprintf(stderr,"Memory-Table-Dump: %s\n", prefix);
+ dump_table();
+#endif
+ m_print_stats( prefix );
+}
+
+
+static void
+out_of_core(size_t n, int secure)
+{
+ log_error ("out of %s memory while allocating %u bytes\n",
+ secure? "secure":"" ,(unsigned)n );
+ if (secure) {
+ /*secmem_dump_stats ();*/
+ log_info ("(this may be caused by too many secret keys used "
+ "simultaneously or due to excessive large key sizes)\n");
+ }
+#if defined(M_GUARD) && defined(__riscos__)
+ abort();
+#endif
+ exit (2);
+}
+
+/****************
+ * Allocate memory of size n.
+ * This function gives up if we do not have enough memory
+ */
+void *
+FNAMEXM(alloc)( size_t n FNAMEPRT )
+{
+ char *p;
+
+#ifdef M_GUARD
+ if(!n)
+ out_of_core(n,0); /* should never happen */
+ if( !(p = malloc( n + EXTRA_ALIGN+5 )) )
+ out_of_core(n,0);
+ store_len(p,n,0);
+ used_memory += n;
+ p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE;
+ return p+EXTRA_ALIGN+4;
+#else
+ /* mallocing zero bytes is undefined by ISO-C, so we better make
+ sure that it won't happen */
+ if (!n)
+ n = 1;
+ if( !(p = malloc( n )) )
+ out_of_core(n,0);
+ return p;
+#endif
+}
+
+/* Allocate memory of size n. This function returns NULL if we do not
+ have enough memory. */
+void *
+FNAMEX(trymalloc)(size_t n FNAMEPRT)
+{
+#ifdef M_GUARD
+ char *p;
+
+ if (!n)
+ n = 1;
+ p = malloc (n + EXTRA_ALIGN+5);
+ if (!p)
+ return NULL;
+ store_len(p,n,0);
+ used_memory += n;
+ p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE;
+ return p+EXTRA_ALIGN+4;
+#else
+ /* Mallocing zero bytes is undefined by ISO-C, so we better make
+ sure that it won't happen. */
+ return malloc (n? n: 1);
+#endif
+}
+
+/****************
+ * Allocate memory of size n from the secure memory pool.
+ * This function gives up if we do not have enough memory
+ */
+void *
+FNAMEXM(alloc_secure)( size_t n FNAMEPRT )
+{
+ char *p;
+
+#ifdef M_GUARD
+ if(!n)
+ out_of_core(n,1); /* should never happen */
+ if( !(p = secmem_malloc( n +EXTRA_ALIGN+ 5 )) )
+ out_of_core(n,1);
+ store_len(p,n,1);
+ p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE;
+ return p+EXTRA_ALIGN+4;
+#else
+ /* mallocing zero bytes is undefined by ISO-C, so we better make
+ sure that it won't happen */
+ if (!n)
+ n = 1;
+ if( !(p = secmem_malloc( n )) )
+ out_of_core(n,1);
+ return p;
+#endif
+}
+
+void *
+FNAMEXM(alloc_clear)( size_t n FNAMEPRT )
+{
+ void *p;
+ p = FNAMEXM(alloc)( n FNAMEARG );
+ memset(p, 0, n );
+ return p;
+}
+
+void *
+FNAMEXM(alloc_secure_clear)( size_t n FNAMEPRT)
+{
+ void *p;
+ p = FNAMEXM(alloc_secure)( n FNAMEARG );
+ memset(p, 0, n );
+ return p;
+}
+
+
+/****************
+ * realloc and clear the old space
+ */
+void *
+FNAMEX(realloc)( void *a, size_t n FNAMEPRT )
+{
+ void *b;
+
+#ifdef M_GUARD
+ if( a ) {
+#error "--enable-m-guard does not currently work"
+ unsigned char *p = a;
+ size_t len = m_size(a);
+
+ if( len >= n ) /* we don't shrink for now */
+ return a;
+ if( p[-1] == MAGIC_SEC_BYTE )
+ b = FNAME(alloc_secure_clear)(n FNAMEARG);
+ else
+ b = FNAME(alloc_clear)(n FNAMEARG);
+ FNAME(check)(NULL FNAMEARG);
+ memcpy(b, a, len );
+ FNAME(free)(p FNAMEARG);
+ }
+ else
+ b = FNAME(alloc)(n FNAMEARG);
+#else
+ if( m_is_secure(a) ) {
+ if( !(b = secmexrealloc( a, n )) )
+ out_of_core(n,1);
+ }
+ else {
+ if( !(b = realloc( a, n )) )
+ out_of_core(n,0);
+ }
+#endif
+
+ return b;
+}
+
+
+
+/****************
+ * Free a pointer
+ */
+void
+FNAMEX(free)( void *a FNAMEPRT )
+{
+ byte *p = a;
+
+ if( !p )
+ return;
+#ifdef M_DEBUG
+ free_entry(p-EXTRA_ALIGN-4, info);
+#elif defined M_GUARD
+ m_check(p);
+ if( m_is_secure(a) )
+ secmem_free(p-EXTRA_ALIGN-4);
+ else {
+ used_memory -= m_size(a);
+ free(p-EXTRA_ALIGN-4);
+ }
+#else
+ if( m_is_secure(a) )
+ secmem_free(p);
+ else
+ free(p);
+#endif
+}
+
+
+void
+FNAME(check)( const void *a FNAMEPRT )
+{
+#ifdef M_GUARD
+ const byte *p = a;
+
+#ifdef M_DEBUG
+ if( p )
+ check_mem(p-EXTRA_ALIGN-4, info);
+ else
+ check_allmem(info);
+#else
+ if( !p )
+ return;
+ if( !(p[-1] == MAGIC_NOR_BYTE || p[-1] == MAGIC_SEC_BYTE) )
+ membug("memory at %p corrupted (underflow=%02x)\n", p, p[-1] );
+ else if( p[m_size(p)] != MAGIC_END_BYTE )
+ membug("memory at %p corrupted (overflow=%02x)\n", p, p[-1] );
+#endif
+#endif
+}
+
+
+size_t
+m_size( const void *a )
+{
+#ifndef M_GUARD
+ log_debug("dummy m_size called\n");
+ return 0;
+#else
+ const byte *p = a;
+ size_t n;
+
+#ifdef M_DEBUG
+ n = check_mem(p-EXTRA_ALIGN-4, "m_size")->user_n;
+#else
+ n = ((byte*)p)[-4];
+ n |= ((byte*)p)[-3] << 8;
+ n |= ((byte*)p)[-2] << 16;
+#endif
+ return n;
+#endif
+}
+
+
+char *
+FNAMEX(strdup)( const char *a FNAMEPRT )
+{
+ size_t n = strlen(a);
+ char *p = FNAMEXM(alloc)(n+1 FNAMEARG);
+ strcpy(p, a);
+ return p;
+}
+
+char *
+FNAMEX(trystrdup)(const char *a FNAMEPRT)
+{
+ size_t n = strlen (a);
+ char *p = FNAMEX(trymalloc)(n+1 FNAMEARG);
+ if (p)
+ strcpy (p, a);
+ return p;
+}
+
+
+/* Wrapper around xmalloc_clear to take the usual 2 arguments of a
+ calloc style function. */
+void *
+xcalloc (size_t n, size_t m)
+{
+ size_t nbytes;
+
+ nbytes = n * m;
+ if (m && nbytes / m != n)
+ out_of_core (nbytes, 0);
+ return xmalloc_clear (nbytes);
+}
+
+/* Wrapper around xmalloc_csecure_lear to take the usual 2 arguments
+ of a calloc style function. */
+void *
+xcalloc_secure (size_t n, size_t m)
+{
+ size_t nbytes;
+
+ nbytes = n * m;
+ if (m && nbytes / m != n)
+ out_of_core (nbytes, 1);
+ return xmalloc_secure_clear (nbytes);
+}
+
diff -uNr a/mpi/mpi-add.c b/mpi/mpi-add.c
--- a/mpi/mpi-add.c false
+++ b/mpi/mpi-add.c ffcea4f2389eb4919df50fc60423606d2835e4be6a853fa885754cf04c397fe96d4a688eccd591c60bc687846ae1e230304d3554b3e504e2e53662270342c591
@@ -0,0 +1,246 @@
+/* mpi-add.c - MPI functions
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ * Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+
+#include "mpi-internal.h"
+
+
+/****************
+ * Add the unsigned integer V to the mpi-integer U and store the
+ * result in W. U and V may be the same.
+ */
+void
+mpi_add_ui(MPI w, MPI u, unsigned long v )
+{
+ mpi_ptr_t wp, up;
+ mpi_size_t usize, wsize;
+ int usign, wsign;
+
+ usize = u->nlimbs;
+ usign = u->sign;
+ wsign = 0;
+
+ /* If not space for W (and possible carry), increase space. */
+ wsize = usize + 1;
+ if( w->alloced < wsize )
+ mpi_resize(w, wsize);
+
+ /* These must be after realloc (U may be the same as W). */
+ up = u->d;
+ wp = w->d;
+
+ if( !usize ) { /* simple */
+ wp[0] = v;
+ wsize = v? 1:0;
+ }
+ else if( !usign ) { /* mpi is not negative */
+ mpi_limb_t cy;
+ cy = mpihelp_add_1(wp, up, usize, v);
+ wp[usize] = cy;
+ wsize = usize + cy;
+ }
+ else { /* The signs are different. Need exact comparison to determine
+ * which operand to subtract from which. */
+ if( usize == 1 && up[0] < v ) {
+ wp[0] = v - up[0];
+ wsize = 1;
+ }
+ else {
+ mpihelp_sub_1(wp, up, usize, v);
+ /* Size can decrease with at most one limb. */
+ wsize = usize - (wp[usize-1]==0);
+ 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;
+
+ if( u->nlimbs < v->nlimbs ) { /* Swap U and V. */
+ usize = v->nlimbs;
+ usign = v->sign;
+ vsize = u->nlimbs;
+ vsign = u->sign;
+ wsize = usize + 1;
+ RESIZE_IF_NEEDED(w, wsize);
+ /* These must be after realloc (u or v may be the same as w). */
+ up = v->d;
+ vp = u->d;
+ }
+ else {
+ usize = u->nlimbs;
+ usign = u->sign;
+ vsize = v->nlimbs;
+ vsign = v->sign;
+ wsize = usize + 1;
+ RESIZE_IF_NEEDED(w, wsize);
+ /* These must be after realloc (u or v may be the same as w). */
+ up = u->d;
+ vp = v->d;
+ }
+ wp = w->d;
+ wsign = 0;
+
+ 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 )
+ wsign = 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]==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 );
+ mpi_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;
+ }
+}
+
+
+void
+mpi_addm( MPI w, MPI u, MPI v, MPI m)
+{
+ mpi_add(w, u, v);
+ mpi_fdiv_r( w, w, m );
+}
+
+void
+mpi_subm( MPI w, MPI u, MPI v, MPI m)
+{
+ mpi_sub(w, u, v);
+ mpi_fdiv_r( w, w, m );
+}
+
diff -uNr a/mpi/mpi-bit.c b/mpi/mpi-bit.c
--- a/mpi/mpi-bit.c false
+++ b/mpi/mpi-bit.c a48f6dcd95712d600a89efae6dc7425b5cade2869b48aa49d6d6fc5c42d63ec462e2a1fcb08cb1df5468a9a5ad8c8dd419dc7fb8f5758ad0d93007960b19a153
@@ -0,0 +1,254 @@
+/* mpi-bit.c - MPI bit level fucntions
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+
+
+#ifdef MPI_INTERNAL_NEED_CLZ_TAB
+#ifdef __STDC__
+const
+#endif
+unsigned char
+__clz_tab[] =
+{
+ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+};
+#endif
+
+
+#define A_LIMB_1 ((mpi_limb_t)1)
+
+
+/****************
+ * Sometimes we have MSL (most significant limbs) which are 0;
+ * this is for some reasons not good, so this function removes them.
+ */
+void
+mpi_normalize( MPI a )
+{
+ if( mpi_is_opaque (a) )
+ return;
+
+ for( ; a->nlimbs && !a->d[a->nlimbs-1]; a->nlimbs-- )
+ ;
+}
+
+
+
+/****************
+ * Return the number of bits in A.
+ */
+unsigned
+mpi_get_nbits( MPI a )
+{
+ unsigned n;
+
+ mpi_normalize( a );
+ if( a->nlimbs ) {
+ mpi_limb_t alimb = a->d[a->nlimbs-1];
+ if( alimb )
+ count_leading_zeros( n, alimb );
+ else
+ n = BITS_PER_MPI_LIMB;
+ n = BITS_PER_MPI_LIMB - n + (a->nlimbs-1) * BITS_PER_MPI_LIMB;
+ }
+ else
+ n = 0;
+ return n;
+}
+
+
+/****************
+ * Test whether 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 & (A_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] |= (A_LIMB_1<= a->nlimbs ) { /* resize */
+ if( a->alloced >= limbno )
+ mpi_resize(a, limbno+1 );
+ a->nlimbs = limbno+1;
+ }
+ a->d[limbno] |= (A_LIMB_1<d[limbno] &= ~(A_LIMB_1 << bitno);
+ a->nlimbs = limbno+1;
+}
+
+/****************
+ * clear bit N of A and all bits above
+ */
+void
+mpi_clear_highbit( MPI a, unsigned n )
+{
+ unsigned limbno, bitno;
+
+ limbno = n / BITS_PER_MPI_LIMB;
+ bitno = n % BITS_PER_MPI_LIMB;
+
+ if( limbno >= a->nlimbs )
+ return; /* not allocated, so need to clear bits :-) */
+
+ for( ; bitno < BITS_PER_MPI_LIMB; bitno++ )
+ a->d[limbno] &= ~(A_LIMB_1 << bitno);
+ a->nlimbs = limbno+1;
+}
+
+/****************
+ * 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] &= ~(A_LIMB_1 << bitno);
+}
+
+
+/****************
+ * Shift A by N bits to the right
+ * FIXME: should use alloc_limb if X and A are same.
+ */
+void
+mpi_rshift( MPI x, MPI a, unsigned n )
+{
+ mpi_ptr_t xp;
+ mpi_size_t xsize;
+
+ xsize = a->nlimbs;
+ x->sign = a->sign;
+ RESIZE_IF_NEEDED(x, xsize);
+ xp = x->d;
+
+ if( xsize ) {
+ mpihelp_rshift( xp, a->d, xsize, n);
+ MPN_NORMALIZE( xp, xsize);
+ }
+ x->nlimbs = xsize;
+}
+
+
+/****************
+ * Shift A by COUNT limbs to the left
+ * This is used only within the MPI library
+ */
+void
+mpi_lshift_limbs( MPI a, unsigned int count )
+{
+ mpi_ptr_t ap = a->d;
+ int n = a->nlimbs;
+ int i;
+
+ if( !count || !n )
+ return;
+
+ RESIZE_IF_NEEDED( a, n+count );
+
+ for( i = n-1; i >= 0; i-- )
+ ap[i+count] = ap[i];
+ for(i=0; i < count; i++ )
+ ap[i] = 0;
+ a->nlimbs += count;
+}
+
+
+/****************
+ * Shift A by COUNT limbs to the right
+ * This is used only within the MPI library
+ */
+void
+mpi_rshift_limbs( MPI a, unsigned int count )
+{
+ mpi_ptr_t ap = a->d;
+ mpi_size_t n = a->nlimbs;
+ unsigned int i;
+
+ if( count >= n ) {
+ a->nlimbs = 0;
+ return;
+ }
+
+ for( i = 0; i < n - count; i++ )
+ ap[i] = ap[i+count];
+ ap[i] = 0;
+ a->nlimbs -= count;
+}
+
+
diff -uNr a/mpi/mpi-cmp.c b/mpi/mpi-cmp.c
--- a/mpi/mpi-cmp.c false
+++ b/mpi/mpi-cmp.c 83c978461ca2fc606eab05035db9a67d600396f013e5ce0db8cc110d8881e9be513d540b27daecc8b0293178d7ab27ee52f5c947a0b9976863b9094f82ebd522
@@ -0,0 +1,73 @@
+/* mpi-cmp.c - MPI functions
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+
+int
+mpi_cmp_ui( MPI u, unsigned long v )
+{
+ mpi_limb_t limb = v;
+
+ mpi_normalize( u );
+ 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, vsize;
+ int cmp;
+
+ mpi_normalize( u );
+ mpi_normalize( v );
+ usize = u->nlimbs;
+ vsize = v->nlimbs;
+ if( !u->sign && v->sign )
+ return 1;
+ if( u->sign && !v->sign )
+ return -1;
+ if( usize != vsize && !u->sign && !v->sign )
+ return usize - vsize;
+ if( usize != vsize && u->sign && v->sign )
+ return vsize + usize;
+ if( !usize )
+ return 0;
+ if( !(cmp=mpihelp_cmp( u->d, v->d, usize )) )
+ return 0;
+ if( (cmp < 0?1:0) == (u->sign?1:0))
+ return 1;
+ return -1;
+}
+
+
diff -uNr a/mpi/mpicoder.c b/mpi/mpicoder.c
--- a/mpi/mpicoder.c false
+++ b/mpi/mpicoder.c 6a4860ea723098a2e2ba703d8748f6d26c22d1ae72647a5ccca67ab93976390b0d992ba870796be3da3b736b1a11b36f700a93214ae5926ec2652d1edee390a3
@@ -0,0 +1,472 @@
+/* mpicoder.c - Coder for the external representation of MPIs
+ * Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "mpi.h"
+#include "mpi-internal.h"
+#include "iobuf.h"
+#include "memory.h"
+#include "util.h"
+
+#ifdef M_DEBUG
+#undef mpi_read
+#endif
+
+#define MAX_EXTERN_MPI_BITS 16384
+
+/****************
+ * write an mpi to out.
+ */
+int
+mpi_write( IOBUF out, MPI a )
+{
+ int rc;
+ unsigned nbits = mpi_get_nbits(a);
+ byte *p, *buf;
+ unsigned n;
+
+ if( nbits > MAX_EXTERN_MPI_BITS )
+ log_bug("mpi_encode: mpi too large (%u bits)\n", nbits);
+
+ iobuf_put(out, (nbits >>8) );
+ iobuf_put(out, (nbits) );
+
+ p = buf = mpi_get_buffer( a, &n, NULL );
+ rc = iobuf_write( out, p, n );
+ xfree(buf);
+ return rc;
+}
+
+
+/****************
+ * Read an external representation of an mpi and return the 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_read(IOBUF inp, unsigned *ret_nread, int secure, const char *info)
+#else
+mpi_read(IOBUF inp, unsigned *ret_nread, int secure)
+#endif
+{
+ int c, i, j;
+ unsigned int nmax = *ret_nread;
+ unsigned nbits, nbytes, nlimbs, nread=0;
+ mpi_limb_t a;
+ MPI val = NULL;
+
+ if (nread == nmax)
+ goto overflow;
+ if( (c = iobuf_get(inp)) == -1 )
+ goto leave;
+ nread++;
+ nbits = c << 8;
+
+ if (nread == nmax)
+ goto overflow;
+ if( (c = iobuf_get(inp)) == -1 )
+ goto leave;
+ nread++;
+ nbits |= c;
+
+ if( nbits > MAX_EXTERN_MPI_BITS ) {
+ log_error("mpi too large for this implementation (%u bits)\n", nbits);
+ goto leave;
+ }
+
+ nbytes = (nbits+7) / 8;
+ nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+#ifdef M_DEBUG
+ val = secure? mpi_debug_alloc_secure( nlimbs, info )
+ : mpi_debug_alloc( nlimbs, info );
+#else
+ val = secure? mpi_alloc_secure( nlimbs )
+ : mpi_alloc( nlimbs );
+#endif
+ i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
+ i %= BYTES_PER_MPI_LIMB;
+ val->nbits = nbits;
+ j= val->nlimbs = nlimbs;
+ val->sign = 0;
+ for( ; j > 0; j-- ) {
+ a = 0;
+ for(; i < BYTES_PER_MPI_LIMB; i++ ) {
+ if (nread == nmax) {
+#ifdef M_DEBUG
+ mpi_debug_free (val);
+#else
+ mpi_free (val);
+#endif
+ val = NULL;
+ goto overflow;
+ }
+ a <<= 8;
+ a |= iobuf_get(inp) & 0xff; nread++;
+ }
+ i = 0;
+ val->d[j-1] = a;
+ }
+
+ leave:
+ *ret_nread = nread;
+ return val;
+ overflow:
+ log_error ("mpi larger than indicated length (%u bytes)\n", nmax);
+ *ret_nread = nread;
+ return val;
+}
+
+
+MPI
+mpi_read_from_buffer(byte *buffer, unsigned int *ret_nread, int secure)
+{
+ int i, j;
+ unsigned nbits, nbytes, nlimbs, nread=0;
+ mpi_limb_t a;
+ MPI val = NULL;
+
+ if( *ret_nread < 2 )
+ goto leave;
+ nbits = buffer[0] << 8 | buffer[1];
+ if( nbits > MAX_EXTERN_MPI_BITS ) {
+ log_info ("mpi too large (%u bits)\n", nbits);
+ goto leave;
+ }
+ buffer += 2;
+ nread = 2;
+
+ nbytes = (nbits+7) / 8;
+ nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+ val = secure? mpi_alloc_secure( nlimbs )
+ : mpi_alloc( nlimbs );
+ i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
+ i %= BYTES_PER_MPI_LIMB;
+ val->nbits = nbits;
+ j= val->nlimbs = nlimbs;
+ val->sign = 0;
+ for( ; j > 0; j-- ) {
+ a = 0;
+ for(; i < BYTES_PER_MPI_LIMB; i++ ) {
+ if( ++nread > *ret_nread ) {
+ /* This (as well as the above error condition) may
+ happen if we use this function to parse a decrypted
+ MPI which didn't turn out to be a real MPI - possible
+ because the supplied key was wrong but the OpenPGP
+ checksum didn't caught it. */
+ log_info ("mpi larger than buffer\n");
+ mpi_free (val);
+ val = NULL;
+ goto leave;
+ }
+ a <<= 8;
+ a |= *buffer++;
+ }
+ i = 0;
+ val->d[j-1] = a;
+ }
+
+ leave:
+ *ret_nread = nread;
+ return val;
+}
+
+
+/****************
+ * Make an 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 given stream and return the number of characters
+ * printed.
+ */
+int
+mpi_print( FILE *fp, MPI a, int mode )
+{
+ int i, n=0;
+
+ if( a == NULL )
+ return fprintf(fp, "[MPI_NULL]");
+ if( !mode ) {
+ unsigned int n1;
+
+ n1 = mpi_get_nbits(a);
+ n += fprintf(fp, "[%u bits]", n1);
+ }
+ else {
+ if( a->sign )
+ putc('-', fp);
+#if BYTES_PER_MPI_LIMB == 2
+#define X "4"
+#elif BYTES_PER_MPI_LIMB == 4
+#define X "8"
+#elif BYTES_PER_MPI_LIMB == 8
+#define X "16"
+#else
+#error please define the format here
+#endif
+ for(i=a->nlimbs; i > 0 ; i-- ) {
+ n += fprintf(fp, i!=a->nlimbs? "%0" X "lX":"%lX", (ulong)a->d[i-1]);
+#undef X
+ }
+ if( !a->nlimbs )
+ putc('0', fp );
+ }
+ return n;
+}
+
+
+void
+g10_log_mpidump( const char *text, MPI a )
+{
+ FILE *fp = log_stream();
+
+ g10_log_print_prefix(text);
+ mpi_print(fp, a, 1 );
+ fputc('\n', fp);
+}
+
+/****************
+ * Special function to get the low 8 bytes from an mpi.
+ * This can be used as a keyid; KEYID is an 2 element array.
+ * Return the low 4 bytes.
+ */
+u32
+mpi_get_keyid( MPI a, u32 *keyid )
+{
+#if BYTES_PER_MPI_LIMB == 4
+ 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;
+#elif BYTES_PER_MPI_LIMB == 8
+ if( keyid ) {
+ keyid[0] = a->nlimbs? (u32)(a->d[0] >> 32) : 0;
+ keyid[1] = a->nlimbs? (u32)(a->d[0] & 0xffffffff) : 0;
+ }
+ return a->nlimbs? (u32)(a->d[0] & 0xffffffff) : 0;
+#else
+#error Make this function work with other LIMB sizes
+#endif
+}
+
+
+/****************
+ * Return an xmalloced buffer with the MPI (msb first).
+ * NBYTES receives the length of this buffer. Caller must free the
+ * return string (This function does return a 0 byte buffer with NBYTES
+ * set to zero if the value of A is zero. If sign is not NULL, it will
+ * be set to the sign of the A.
+ */
+static byte *
+do_get_buffer( MPI a, unsigned *nbytes, int *sign, int force_secure )
+{
+ byte *p, *buffer;
+ mpi_limb_t alimb;
+ int i;
+ unsigned int n;
+
+ if( sign )
+ *sign = a->sign;
+ *nbytes = n = a->nlimbs * BYTES_PER_MPI_LIMB;
+ if (!n)
+ n++; /* avoid zero length allocation */
+ p = buffer = force_secure || mpi_is_secure(a) ? xmalloc_secure(n)
+ : xmalloc(n);
+
+ for(i=a->nlimbs-1; i >= 0; i-- ) {
+ alimb = a->d[i];
+#if BYTES_PER_MPI_LIMB == 4
+ *p++ = alimb >> 24;
+ *p++ = alimb >> 16;
+ *p++ = alimb >> 8;
+ *p++ = alimb ;
+#elif BYTES_PER_MPI_LIMB == 8
+ *p++ = alimb >> 56;
+ *p++ = alimb >> 48;
+ *p++ = alimb >> 40;
+ *p++ = alimb >> 32;
+ *p++ = alimb >> 24;
+ *p++ = alimb >> 16;
+ *p++ = alimb >> 8;
+ *p++ = alimb ;
+#else
+#error please implement for this limb size.
+#endif
+ }
+
+ /* this is sub-optimal but we need to do the shift operation
+ * because the caller has to free the returned buffer */
+ for(p=buffer; !*p && *nbytes; p++, --*nbytes )
+ ;
+ if( p != buffer )
+ memmove(buffer,p, *nbytes);
+
+ return buffer;
+}
+
+
+byte *
+mpi_get_buffer( MPI a, unsigned *nbytes, int *sign )
+{
+ return do_get_buffer( a, nbytes, sign, 0 );
+}
+
+byte *
+mpi_get_secure_buffer( MPI a, unsigned *nbytes, int *sign )
+{
+ return do_get_buffer( a, nbytes, sign, 1 );
+}
+
+/****************
+ * Use BUFFER to update MPI.
+ */
+void
+mpi_set_buffer( MPI a, const byte *buffer, unsigned nbytes, int sign )
+{
+ const byte *p;
+ mpi_limb_t alimb;
+ int nlimbs;
+ int i;
+
+ nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
+ RESIZE_IF_NEEDED(a, nlimbs);
+ a->sign = sign;
+
+ for(i=0, p = buffer+nbytes-1; p >= buffer+BYTES_PER_MPI_LIMB; ) {
+#if BYTES_PER_MPI_LIMB == 4
+ alimb = (mpi_limb_t)*p-- ;
+ alimb |= (mpi_limb_t)*p-- << 8 ;
+ alimb |= (mpi_limb_t)*p-- << 16 ;
+ alimb |= (mpi_limb_t)*p-- << 24 ;
+#elif BYTES_PER_MPI_LIMB == 8
+ alimb = (mpi_limb_t)*p-- ;
+ alimb |= (mpi_limb_t)*p-- << 8 ;
+ alimb |= (mpi_limb_t)*p-- << 16 ;
+ alimb |= (mpi_limb_t)*p-- << 24 ;
+ alimb |= (mpi_limb_t)*p-- << 32 ;
+ alimb |= (mpi_limb_t)*p-- << 40 ;
+ alimb |= (mpi_limb_t)*p-- << 48 ;
+ alimb |= (mpi_limb_t)*p-- << 56 ;
+#else
+#error please implement for this limb size.
+#endif
+ a->d[i++] = alimb;
+ }
+ if( p >= buffer ) {
+#if BYTES_PER_MPI_LIMB == 4
+ alimb = *p-- ;
+ if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 8 ;
+ if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 16 ;
+ if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 24 ;
+#elif BYTES_PER_MPI_LIMB == 8
+ alimb = (mpi_limb_t)*p-- ;
+ if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 8 ;
+ if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 16 ;
+ if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 24 ;
+ if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 32 ;
+ if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 40 ;
+ if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 48 ;
+ if( p >= buffer ) alimb |= (mpi_limb_t)*p-- << 56 ;
+#else
+#error please implement for this limb size.
+#endif
+ a->d[i++] = alimb;
+ }
+ a->nlimbs = i;
+ assert( i == nlimbs );
+}
diff -uNr a/mpi/mpi-div.c b/mpi/mpi-div.c
--- a/mpi/mpi-div.c false
+++ b/mpi/mpi-div.c b320709b57b3cf0c00bc98277b037494c62fed93fd99bca0412ea633f8662844d35ed62990cbe1fc02a47dee5795d3a7b6b401440f6e80a8a00243868815c06a
@@ -0,0 +1,321 @@
+/* mpi-div.c - MPI functions
+ * Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+
+
+
+void
+mpi_fdiv_r( MPI rem, MPI dividend, MPI divisor )
+{
+ int divisor_sign = divisor->sign;
+ MPI temp_divisor = NULL;
+
+ /* We need the original value of the divisor after the remainder has been
+ * preliminary calculated. We have to copy it to temporary space if it's
+ * the same variable as REM. */
+ if( rem == divisor ) {
+ temp_divisor = mpi_copy( divisor );
+ divisor = temp_divisor;
+ }
+
+ mpi_tdiv_r( rem, dividend, divisor );
+
+ if( ((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs )
+ mpi_add( rem, rem, divisor);
+
+ if( temp_divisor )
+ mpi_free(temp_divisor);
+}
+
+
+
+/****************
+ * Division rounding the quotient towards -infinity.
+ * The remainder gets the same sign as the denominator.
+ * rem is optional
+ */
+
+ulong
+mpi_fdiv_r_ui( MPI rem, MPI dividend, ulong divisor )
+{
+ mpi_limb_t rlimb;
+
+ rlimb = mpihelp_mod_1( dividend->d, dividend->nlimbs, divisor );
+ if( rlimb && dividend->sign )
+ rlimb = divisor - rlimb;
+
+ if( rem ) {
+ rem->d[0] = rlimb;
+ rem->nlimbs = rlimb? 1:0;
+ }
+ return rlimb;
+}
+
+
+void
+mpi_fdiv_q( MPI quot, MPI dividend, MPI divisor )
+{
+ MPI tmp = mpi_alloc( mpi_get_nlimbs(quot) );
+ mpi_fdiv_qr( quot, tmp, dividend, divisor);
+ mpi_free(tmp);
+}
+
+void
+mpi_fdiv_qr( MPI quot, MPI rem, MPI dividend, MPI divisor )
+{
+ int divisor_sign = divisor->sign;
+ MPI temp_divisor = NULL;
+
+ if( quot == divisor || rem == divisor ) {
+ temp_divisor = mpi_copy( divisor );
+ divisor = temp_divisor;
+ }
+
+ mpi_tdiv_qr( quot, rem, dividend, divisor );
+
+ if( (divisor_sign ^ dividend->sign) && rem->nlimbs ) {
+ mpi_sub_ui( quot, quot, 1 );
+ mpi_add( rem, rem, divisor);
+ }
+
+ if( temp_divisor )
+ mpi_free(temp_divisor);
+}
+
+
+/* If den == quot, den needs temporary storage.
+ * If den == rem, den needs temporary storage.
+ * If num == quot, num needs temporary storage.
+ * If den has temporary storage, it can be normalized while being copied,
+ * i.e no extra storage should be allocated.
+ */
+
+void
+mpi_tdiv_r( MPI rem, MPI num, MPI den)
+{
+ mpi_tdiv_qr(NULL, rem, num, den );
+}
+
+void
+mpi_tdiv_qr( MPI quot, MPI rem, MPI num, MPI den)
+{
+ mpi_ptr_t np, dp;
+ mpi_ptr_t qp, rp;
+ mpi_size_t nsize = num->nlimbs;
+ mpi_size_t dsize = den->nlimbs;
+ mpi_size_t qsize, rsize;
+ mpi_size_t sign_remainder = num->sign;
+ mpi_size_t sign_quotient = num->sign ^ den->sign;
+ unsigned normalization_steps;
+ mpi_limb_t q_limb;
+ mpi_ptr_t marker[5];
+ int markidx=0;
+
+ /* Ensure space is enough for quotient and remainder.
+ * We need space for an extra limb in the remainder, because it's
+ * up-shifted (normalized) below. */
+ rsize = nsize + 1;
+ 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 )
+ 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,
+ mpi_is_secure(quot));
+ 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,mpi_is_secure(den));
+ 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, mpi_is_secure(den));
+ 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]);
+}
+
+void
+mpi_tdiv_q_2exp( MPI w, MPI u, unsigned count )
+{
+ mpi_size_t usize, wsize;
+ mpi_size_t limb_cnt;
+
+ usize = u->nlimbs;
+ limb_cnt = count / BITS_PER_MPI_LIMB;
+ wsize = usize - limb_cnt;
+ if( limb_cnt >= usize )
+ w->nlimbs = 0;
+ else {
+ mpi_ptr_t wp;
+ mpi_ptr_t up;
+
+ RESIZE_IF_NEEDED( w, wsize );
+ wp = w->d;
+ up = u->d;
+
+ count %= BITS_PER_MPI_LIMB;
+ if( count ) {
+ mpihelp_rshift( wp, up + limb_cnt, wsize, count );
+ wsize -= !wp[wsize - 1];
+ }
+ else {
+ MPN_COPY_INCR( wp, up + limb_cnt, wsize);
+ }
+
+ w->nlimbs = wsize;
+ }
+}
+
+/****************
+ * Check whether dividend is divisible by divisor
+ * (note: divisor must fit into a limb)
+ */
+int
+mpi_divisible_ui(MPI dividend, ulong divisor )
+{
+ return !mpihelp_mod_1( dividend->d, dividend->nlimbs, divisor );
+}
+
diff -uNr a/mpi/mpi-gcd.c b/mpi/mpi-gcd.c
--- a/mpi/mpi-gcd.c false
+++ b/mpi/mpi-gcd.c f582de56ee9bc1d4cf2eea35bdabdcd61e0cc93dd186950709e32fc707d2f769669bafdcfbf2ad074596ba474bf1e7af5e29ea81cff2316acbfcd27a0f93f185
@@ -0,0 +1,53 @@
+/* mpi-gcd.c - MPI functions
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+
+/****************
+ * Find the greatest common divisor G of A and B.
+ * Return: true if this 1, false in all other cases
+ */
+int
+mpi_gcd( MPI g, MPI xa, MPI xb )
+{
+ MPI a, b;
+
+ a = mpi_copy(xa);
+ b = mpi_copy(xb);
+
+ /* TAOCP Vol II, 4.5.2, Algorithm A */
+ a->sign = 0;
+ b->sign = 0;
+ while( mpi_cmp_ui( b, 0 ) ) {
+ mpi_fdiv_r( g, a, b ); /* g used as temorary variable */
+ mpi_set(a,b);
+ mpi_set(b,g);
+ }
+ mpi_set(g, a);
+
+ mpi_free(a);
+ mpi_free(b);
+ return !mpi_cmp_ui( g, 1);
+}
+
+
+
diff -uNr a/mpi/mpih-add1.c b/mpi/mpih-add1.c
--- a/mpi/mpih-add1.c false
+++ b/mpi/mpih-add1.c fb06ea790bd2b2c18013b3fb51f05a5c1577f45fdd67644e7745c3373fa26fa90de8f30fd9221e978ba9676423ed1c4c27c0407f22a50e10f216ae9bbf4ac3f3
@@ -0,0 +1,64 @@
+/* mpihelp-add_1.c - MPI helper functions
+ * Copyright (C) 1994, 1996, 1997, 1998,
+ * 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+
+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; /* get out carry from that addition */
+ y += x; /* add other addend */
+ cy += y < x; /* get out carry from that add, combine */
+ res_ptr[j] = y;
+ } while( ++j );
+
+ return cy;
+}
+
diff -uNr a/mpi/mpih-cmp.c b/mpi/mpih-cmp.c
--- a/mpi/mpih-cmp.c false
+++ b/mpi/mpih-cmp.c 88a21583524c37a7febb2eedaf38f0942183a201ee8df8b9e04a8098e892dd88b7f8566e40cc8bf042d5713e2f78886526cc23de79c61463e7763685f280c37e
@@ -0,0 +1,61 @@
+/* mpihelp-sub.c - MPI helper functions
+ * Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+
+#include "mpi-internal.h"
+
+/****************
+ * Compare OP1_PTR/OP1_SIZE with OP2_PTR/OP2_SIZE.
+ * There are no restrictions on the relative sizes of
+ * the two arguments.
+ * Return 1 if OP1 > OP2, 0 if they are equal, and -1 if OP1 < OP2.
+ */
+int
+mpihelp_cmp( mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size )
+{
+ mpi_size_t i;
+ mpi_limb_t op1_word, op2_word;
+
+ for( i = size - 1; i >= 0 ; i--) {
+ op1_word = op1_ptr[i];
+ op2_word = op2_ptr[i];
+ if( op1_word != op2_word )
+ goto diff;
+ }
+ return 0;
+
+ diff:
+ /* This can *not* be simplified to
+ * op2_word - op2_word
+ * since that expression might give signed overflow. */
+ return (op1_word > op2_word) ? 1 : -1;
+}
+
diff -uNr a/mpi/mpih-div.c b/mpi/mpih-div.c
--- a/mpi/mpih-div.c false
+++ b/mpi/mpih-div.c aa4e2efa1e53416aedf9cbf7a73a00fbde7a8266f532002dc046b0b995cf49d060496c45c74944ec3f41cf0dd441884ff6230260978fcbf227903eb7213b074a
@@ -0,0 +1,534 @@
+/* mpihelp-div.c - MPI helper functions
+ * Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+
+#ifndef UMUL_TIME
+#define UMUL_TIME 1
+#endif
+#ifndef UDIV_TIME
+#define UDIV_TIME UMUL_TIME
+#endif
+
+/* FIXME: We should be using invert_limb (or invert_normalized_limb)
+ * here (not udiv_qrnnd).
+ */
+
+mpi_limb_t
+mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+ mpi_limb_t divisor_limb)
+{
+ mpi_size_t i;
+ mpi_limb_t n1, n0, r;
+ int dummy;
+
+ /* Botch: Should this be handled at all? Rely on callers? */
+ if( !dividend_size )
+ return 0;
+
+ /* If multiplication is much faster than division, and the
+ * dividend is large, pre-invert the divisor, and use
+ * only multiplications in the inner loop.
+ *
+ * This test should be read:
+ * Does it ever help to use udiv_qrnnd_preinv?
+ * && Does what we save compensate for the inversion overhead?
+ */
+ if( UDIV_TIME > (2 * UMUL_TIME + 6)
+ && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME ) {
+ int normalization_steps;
+
+ count_leading_zeros( normalization_steps, divisor_limb );
+ if( normalization_steps ) {
+ mpi_limb_t divisor_limb_inverted;
+
+ divisor_limb <<= normalization_steps;
+
+ /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The
+ * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+ * most significant bit (with weight 2**N) implicit.
+ *
+ * Special case for DIVISOR_LIMB == 100...000.
+ */
+ if( !(divisor_limb << 1) )
+ divisor_limb_inverted = ~(mpi_limb_t)0;
+ else
+ udiv_qrnnd(divisor_limb_inverted, dummy,
+ -divisor_limb, 0, divisor_limb);
+
+ n1 = dividend_ptr[dividend_size - 1];
+ r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+ /* Possible optimization:
+ * if (r == 0
+ * && divisor_limb > ((n1 << normalization_steps)
+ * | (dividend_ptr[dividend_size - 2] >> ...)))
+ * ...one division less...
+ */
+ for( i = dividend_size - 2; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ UDIV_QRNND_PREINV(dummy, r, r,
+ ((n1 << normalization_steps)
+ | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+ divisor_limb, divisor_limb_inverted);
+ n1 = n0;
+ }
+ UDIV_QRNND_PREINV(dummy, r, r,
+ n1 << normalization_steps,
+ divisor_limb, divisor_limb_inverted);
+ return r >> normalization_steps;
+ }
+ else {
+ mpi_limb_t divisor_limb_inverted;
+
+ /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The
+ * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+ * most significant bit (with weight 2**N) implicit.
+ *
+ * Special case for DIVISOR_LIMB == 100...000.
+ */
+ if( !(divisor_limb << 1) )
+ divisor_limb_inverted = ~(mpi_limb_t)0;
+ else
+ udiv_qrnnd(divisor_limb_inverted, dummy,
+ -divisor_limb, 0, divisor_limb);
+
+ i = dividend_size - 1;
+ r = dividend_ptr[i];
+
+ if( r >= divisor_limb )
+ r = 0;
+ else
+ i--;
+
+ for( ; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ UDIV_QRNND_PREINV(dummy, r, r,
+ n0, divisor_limb, divisor_limb_inverted);
+ }
+ return r;
+ }
+ }
+ else {
+ if( UDIV_NEEDS_NORMALIZATION ) {
+ int normalization_steps;
+
+ count_leading_zeros(normalization_steps, divisor_limb);
+ if( normalization_steps ) {
+ divisor_limb <<= normalization_steps;
+
+ n1 = dividend_ptr[dividend_size - 1];
+ r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+ /* Possible optimization:
+ * if (r == 0
+ * && divisor_limb > ((n1 << normalization_steps)
+ * | (dividend_ptr[dividend_size - 2] >> ...)))
+ * ...one division less...
+ */
+ for(i = dividend_size - 2; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ udiv_qrnnd (dummy, r, r,
+ ((n1 << normalization_steps)
+ | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+ divisor_limb);
+ n1 = n0;
+ }
+ udiv_qrnnd (dummy, r, r,
+ n1 << normalization_steps,
+ divisor_limb);
+ return r >> normalization_steps;
+ }
+ }
+ /* No normalization needed, either because udiv_qrnnd doesn't require
+ * it, or because DIVISOR_LIMB is already normalized. */
+ i = dividend_size - 1;
+ r = dividend_ptr[i];
+
+ if(r >= divisor_limb)
+ r = 0;
+ else
+ i--;
+
+ for(; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ udiv_qrnnd (dummy, r, r, n0, divisor_limb);
+ }
+ return r;
+ }
+}
+
+/* Divide num (NP/NSIZE) by den (DP/DSIZE) and write
+ * the NSIZE-DSIZE least significant quotient limbs at QP
+ * and the DSIZE long remainder at NP. If QEXTRA_LIMBS is
+ * non-zero, generate that many fraction bits and append them after the
+ * other quotient limbs.
+ * Return the most significant limb of the quotient, this is always 0 or 1.
+ *
+ * Preconditions:
+ * 0. NSIZE >= DSIZE.
+ * 1. The most significant bit of the divisor must be set.
+ * 2. QP must either not overlap with the input operands at all, or
+ * QP + DSIZE >= NP must hold true. (This means that it's
+ * possible to put the quotient in the high part of NUM, right after the
+ * remainder in NUM.
+ * 3. NSIZE >= DSIZE, even if QEXTRA_LIMBS is non-zero.
+ */
+
+mpi_limb_t
+mpihelp_divrem( mpi_ptr_t qp, mpi_size_t qextra_limbs,
+ mpi_ptr_t np, mpi_size_t nsize,
+ mpi_ptr_t dp, mpi_size_t dsize)
+{
+ mpi_limb_t most_significant_q_limb = 0;
+
+ switch(dsize) {
+ case 0:
+ /* We are asked to divide by zero, so go ahead and do it! (To make
+ the compiler not remove this statement, return the value.) */
+ return 1 / dsize;
+
+ case 1:
+ {
+ mpi_size_t i;
+ mpi_limb_t n1;
+ mpi_limb_t d;
+
+ d = dp[0];
+ n1 = np[nsize - 1];
+
+ if( n1 >= d ) {
+ n1 -= d;
+ most_significant_q_limb = 1;
+ }
+
+ qp += qextra_limbs;
+ for( i = nsize - 2; i >= 0; i--)
+ udiv_qrnnd( qp[i], n1, n1, np[i], d );
+ qp -= qextra_limbs;
+
+ for( i = qextra_limbs - 1; i >= 0; i-- )
+ udiv_qrnnd (qp[i], n1, n1, 0, d);
+
+ np[0] = n1;
+ }
+ break;
+
+ case 2:
+ {
+ mpi_size_t i;
+ mpi_limb_t n1, n0, n2;
+ mpi_limb_t d1, d0;
+
+ np += nsize - 2;
+ d1 = dp[1];
+ d0 = dp[0];
+ n1 = np[1];
+ n0 = np[0];
+
+ if( n1 >= d1 && (n1 > d1 || n0 >= d0) ) {
+ sub_ddmmss (n1, n0, n1, n0, d1, d0);
+ most_significant_q_limb = 1;
+ }
+
+ for( i = qextra_limbs + nsize - 2 - 1; i >= 0; i-- ) {
+ mpi_limb_t q;
+ mpi_limb_t r;
+
+ if( i >= qextra_limbs )
+ np--;
+ else
+ np[0] = 0;
+
+ if( n1 == d1 ) {
+ /* Q should be either 111..111 or 111..110. Need special
+ * treatment of this rare case as normal division would
+ * give overflow. */
+ q = ~(mpi_limb_t)0;
+
+ r = n0 + d1;
+ if( r < d1 ) { /* Carry in the addition? */
+ add_ssaaaa( n1, n0, r - d0, np[0], 0, d0 );
+ qp[i] = q;
+ continue;
+ }
+ n1 = d0 - (d0 != 0?1:0);
+ n0 = -d0;
+ }
+ else {
+ udiv_qrnnd (q, r, n1, n0, d1);
+ umul_ppmm (n1, n0, d0, q);
+ }
+
+ n2 = np[0];
+ q_test:
+ if( n1 > r || (n1 == r && n0 > n2) ) {
+ /* The estimated Q was too large. */
+ q--;
+ sub_ddmmss (n1, n0, n1, n0, 0, d0);
+ r += d1;
+ if( r >= d1 ) /* If not carry, test Q again. */
+ goto q_test;
+ }
+
+ qp[i] = q;
+ sub_ddmmss (n1, n0, r, n2, n1, n0);
+ }
+ np[1] = n1;
+ np[0] = n0;
+ }
+ break;
+
+ default:
+ {
+ mpi_size_t i;
+ mpi_limb_t dX, d1, n0;
+
+ np += nsize - dsize;
+ dX = dp[dsize - 1];
+ d1 = dp[dsize - 2];
+ n0 = np[dsize - 1];
+
+ if( n0 >= dX ) {
+ if(n0 > dX || mpihelp_cmp(np, dp, dsize - 1) >= 0 ) {
+ mpihelp_sub_n(np, np, dp, dsize);
+ n0 = np[dsize - 1];
+ most_significant_q_limb = 1;
+ }
+ }
+
+ for( i = qextra_limbs + nsize - dsize - 1; i >= 0; i--) {
+ mpi_limb_t q;
+ mpi_limb_t n1, n2;
+ mpi_limb_t cy_limb;
+
+ if( i >= qextra_limbs ) {
+ np--;
+ n2 = np[dsize];
+ }
+ else {
+ n2 = np[dsize - 1];
+ MPN_COPY_DECR (np + 1, np, dsize - 1);
+ np[0] = 0;
+ }
+
+ if( n0 == dX ) {
+ /* This might over-estimate q, but it's probably not worth
+ * the extra code here to find out. */
+ q = ~(mpi_limb_t)0;
+ }
+ else {
+ mpi_limb_t r;
+
+ udiv_qrnnd(q, r, n0, np[dsize - 1], dX);
+ umul_ppmm(n1, n0, d1, q);
+
+ while( n1 > r || (n1 == r && n0 > np[dsize - 2])) {
+ q--;
+ r += dX;
+ if( r < dX ) /* I.e. "carry in previous addition?" */
+ break;
+ n1 -= n0 < d1;
+ n0 -= d1;
+ }
+ }
+
+ /* Possible optimization: We already have (q * n0) and (1 * n1)
+ * after the calculation of q. Taking advantage of that, we
+ * could make this loop make two iterations less. */
+ cy_limb = mpihelp_submul_1(np, dp, dsize, q);
+
+ if( n2 != cy_limb ) {
+ mpihelp_add_n(np, np, dp, dsize);
+ q--;
+ }
+
+ qp[i] = q;
+ n0 = np[dsize - 1];
+ }
+ }
+ }
+
+ return most_significant_q_limb;
+}
+
+
+/****************
+ * Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB.
+ * Write DIVIDEND_SIZE limbs of quotient at QUOT_PTR.
+ * Return the single-limb remainder.
+ * There are no constraints on the value of the divisor.
+ *
+ * QUOT_PTR and DIVIDEND_PTR might point to the same limb.
+ */
+
+mpi_limb_t
+mpihelp_divmod_1( mpi_ptr_t quot_ptr,
+ mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+ mpi_limb_t divisor_limb)
+{
+ mpi_size_t i;
+ mpi_limb_t n1, n0, r;
+ int dummy;
+
+ if( !dividend_size )
+ return 0;
+
+ /* If multiplication is much faster than division, and the
+ * dividend is large, pre-invert the divisor, and use
+ * only multiplications in the inner loop.
+ *
+ * This test should be read:
+ * Does it ever help to use udiv_qrnnd_preinv?
+ * && Does what we save compensate for the inversion overhead?
+ */
+ if( UDIV_TIME > (2 * UMUL_TIME + 6)
+ && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME ) {
+ int normalization_steps;
+
+ count_leading_zeros( normalization_steps, divisor_limb );
+ if( normalization_steps ) {
+ mpi_limb_t divisor_limb_inverted;
+
+ divisor_limb <<= normalization_steps;
+
+ /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The
+ * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+ * most significant bit (with weight 2**N) implicit.
+ */
+ /* Special case for DIVISOR_LIMB == 100...000. */
+ if( !(divisor_limb << 1) )
+ divisor_limb_inverted = ~(mpi_limb_t)0;
+ else
+ udiv_qrnnd(divisor_limb_inverted, dummy,
+ -divisor_limb, 0, divisor_limb);
+
+ n1 = dividend_ptr[dividend_size - 1];
+ r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+ /* Possible optimization:
+ * if (r == 0
+ * && divisor_limb > ((n1 << normalization_steps)
+ * | (dividend_ptr[dividend_size - 2] >> ...)))
+ * ...one division less...
+ */
+ for( i = dividend_size - 2; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ UDIV_QRNND_PREINV( quot_ptr[i + 1], r, r,
+ ((n1 << normalization_steps)
+ | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+ divisor_limb, divisor_limb_inverted);
+ n1 = n0;
+ }
+ UDIV_QRNND_PREINV( quot_ptr[0], r, r,
+ n1 << normalization_steps,
+ divisor_limb, divisor_limb_inverted);
+ return r >> normalization_steps;
+ }
+ else {
+ mpi_limb_t divisor_limb_inverted;
+
+ /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The
+ * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+ * most significant bit (with weight 2**N) implicit.
+ */
+ /* Special case for DIVISOR_LIMB == 100...000. */
+ if( !(divisor_limb << 1) )
+ divisor_limb_inverted = ~(mpi_limb_t) 0;
+ else
+ udiv_qrnnd(divisor_limb_inverted, dummy,
+ -divisor_limb, 0, divisor_limb);
+
+ i = dividend_size - 1;
+ r = dividend_ptr[i];
+
+ if( r >= divisor_limb )
+ r = 0;
+ else
+ quot_ptr[i--] = 0;
+
+ for( ; i >= 0; i-- ) {
+ n0 = dividend_ptr[i];
+ UDIV_QRNND_PREINV( quot_ptr[i], r, r,
+ n0, divisor_limb, divisor_limb_inverted);
+ }
+ return r;
+ }
+ }
+ else {
+ if(UDIV_NEEDS_NORMALIZATION) {
+ int normalization_steps;
+
+ count_leading_zeros (normalization_steps, divisor_limb);
+ if( normalization_steps ) {
+ divisor_limb <<= normalization_steps;
+
+ n1 = dividend_ptr[dividend_size - 1];
+ r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+ /* Possible optimization:
+ * if (r == 0
+ * && divisor_limb > ((n1 << normalization_steps)
+ * | (dividend_ptr[dividend_size - 2] >> ...)))
+ * ...one division less...
+ */
+ for( i = dividend_size - 2; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ udiv_qrnnd (quot_ptr[i + 1], r, r,
+ ((n1 << normalization_steps)
+ | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
+ divisor_limb);
+ n1 = n0;
+ }
+ udiv_qrnnd (quot_ptr[0], r, r,
+ n1 << normalization_steps,
+ divisor_limb);
+ return r >> normalization_steps;
+ }
+ }
+ /* No normalization needed, either because udiv_qrnnd doesn't require
+ * it, or because DIVISOR_LIMB is already normalized. */
+ i = dividend_size - 1;
+ r = dividend_ptr[i];
+
+ if(r >= divisor_limb)
+ r = 0;
+ else
+ quot_ptr[i--] = 0;
+
+ for(; i >= 0; i--) {
+ n0 = dividend_ptr[i];
+ udiv_qrnnd( quot_ptr[i], r, r, n0, divisor_limb );
+ }
+ return r;
+ }
+}
diff -uNr a/mpi/mpih-lshift.c b/mpi/mpih-lshift.c
--- a/mpi/mpih-lshift.c false
+++ b/mpi/mpih-lshift.c 3222bfc241fa6104936cc585fda392f220d88031fa0fdf460bb201a3aa7295e6d1dc75007bf53d2e501734d9faaa31934eed944ce7452a6aa3afcd3a333d3c13
@@ -0,0 +1,68 @@
+/* mpihelp-lshift.c - MPI helper functions
+ * Copyright (C) 1994, 1996, 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+
+/* Shift U (pointed to by UP and USIZE digits long) CNT bits to the left
+ * and store the USIZE least significant digits of the result at WP.
+ * Return the bits shifted out from the most significant digit.
+ *
+ * Argument constraints:
+ * 1. 0 < CNT < BITS_PER_MP_LIMB
+ * 2. If the result is to be written over the input, WP must be >= UP.
+ */
+
+mpi_limb_t
+mpihelp_lshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
+ unsigned int cnt)
+{
+ mpi_limb_t high_limb, low_limb;
+ unsigned sh_1, sh_2;
+ mpi_size_t i;
+ mpi_limb_t retval;
+
+ sh_1 = cnt;
+ wp += 1;
+ sh_2 = BITS_PER_MPI_LIMB - sh_1;
+ i = usize - 1;
+ low_limb = up[i];
+ retval = low_limb >> sh_2;
+ high_limb = low_limb;
+ while( --i >= 0 ) {
+ low_limb = up[i];
+ wp[i] = (high_limb << sh_1) | (low_limb >> sh_2);
+ high_limb = low_limb;
+ }
+ wp[i] = high_limb << sh_1;
+
+ return retval;
+}
+
+
diff -uNr a/mpi/mpih-mul1.c b/mpi/mpih-mul1.c
--- a/mpi/mpih-mul1.c false
+++ b/mpi/mpih-mul1.c 86b925acdaedfaaf9c7f7ff783da4a049c62c8f63929bf288fdc8e4760dc9b451440ed5ed5f8549e8b2ccbd4f00175f068de9dc337eedfd8fad8348d21f3ed13
@@ -0,0 +1,60 @@
+/* mpihelp-mul_1.c - MPI helper functions
+ * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+
+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;
+}
+
diff -uNr a/mpi/mpih-mul2.c b/mpi/mpih-mul2.c
--- a/mpi/mpih-mul2.c false
+++ b/mpi/mpih-mul2.c 340744f79d1466a916fca829c66f86915b808800bf3ebe2ccadaba1d5fd89ef5c5db486c94b0f01ace52f13d7a74784b68214499f5ac120ac8449fc9eb5c61c3
@@ -0,0 +1,65 @@
+/* mpihelp-mul_2.c - MPI helper functions
+ * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+
+
+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;
+}
+
+
diff -uNr a/mpi/mpih-mul3.c b/mpi/mpih-mul3.c
--- a/mpi/mpih-mul3.c false
+++ b/mpi/mpih-mul3.c 683f47357b0f57e3dc50aefc32bdcd8c20e7a9a4c3dc48d3ba9e5715e12836b6ce53b8dff653bdb86cdd197daab9af7532def5bb06d861bdf48f4dc705ac6aa4
@@ -0,0 +1,66 @@
+/* mpihelp-mul_3.c - MPI helper functions
+ * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+
+
+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;
+}
+
+
diff -uNr a/mpi/mpih-mul.c b/mpi/mpih-mul.c
--- a/mpi/mpih-mul.c false
+++ b/mpi/mpih-mul.c 2d6f3c1ecb3331cdfb54c9efa53246cac6a6dfa16465d2e354c6801974964229cb173e7aff19c4c92e896b8c65cfbc6da79ef03c20022772f5c299f1c3cbc063
@@ -0,0 +1,527 @@
+/* mpihelp-mul.c - MPI helper functions
+ * Copyright (C) 1994, 1996, 1998, 1999,
+ * 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+
+
+
+#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) \
+ mpih_sqr_n_basecase (prodp, up, size); \
+ else \
+ mpih_sqr_n (prodp, up, size, tspace); \
+ } while (0);
+
+
+
+
+/* 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, and the 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);
+ }
+}
+
+
+void
+mpih_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++;
+ }
+}
+
+
+void
+mpih_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, and the 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)
+{
+ int secure;
+
+ if( up == vp ) {
+ if( size < KARATSUBA_THRESHOLD )
+ mpih_sqr_n_basecase( prodp, up, size );
+ else {
+ mpi_ptr_t tspace;
+ secure = m_is_secure( up );
+ tspace = mpi_alloc_limb_space( 2 * size, secure );
+ mpih_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;
+ secure = m_is_secure( up ) || m_is_secure( vp );
+ tspace = mpi_alloc_limb_space( 2 * size, secure );
+ mul_n (prodp, up, vp, size, tspace);
+ mpi_free_limb_space( tspace );
+ }
+ }
+}
+
+
+
+void
+mpihelp_mul_karatsuba_case( mpi_ptr_t prodp,
+ mpi_ptr_t up, mpi_size_t usize,
+ mpi_ptr_t vp, mpi_size_t vsize,
+ struct karatsuba_ctx *ctx )
+{
+ mpi_limb_t cy;
+
+ if( !ctx->tspace || ctx->tspace_size < vsize ) {
+ if( ctx->tspace )
+ mpi_free_limb_space( ctx->tspace );
+ ctx->tspace = mpi_alloc_limb_space( 2 * vsize,
+ m_is_secure( up ) || m_is_secure( vp ) );
+ ctx->tspace_size = vsize;
+ }
+
+ MPN_MUL_N_RECURSE( prodp, up, vp, vsize, ctx->tspace );
+
+ prodp += vsize;
+ up += vsize;
+ usize -= vsize;
+ if( usize >= vsize ) {
+ if( !ctx->tp || ctx->tp_size < vsize ) {
+ if( ctx->tp )
+ mpi_free_limb_space( ctx->tp );
+ ctx->tp = mpi_alloc_limb_space( 2 * vsize, m_is_secure( up )
+ || m_is_secure( vp ) );
+ ctx->tp_size = vsize;
+ }
+
+ do {
+ MPN_MUL_N_RECURSE( ctx->tp, up, vp, vsize, ctx->tspace );
+ cy = mpihelp_add_n( prodp, prodp, ctx->tp, vsize );
+ mpihelp_add_1( prodp + vsize, ctx->tp + vsize, vsize, cy );
+ prodp += vsize;
+ up += vsize;
+ usize -= vsize;
+ } while( usize >= vsize );
+ }
+
+ if( usize ) {
+ if( usize < KARATSUBA_THRESHOLD ) {
+ mpihelp_mul( ctx->tspace, vp, vsize, up, usize );
+ }
+ else {
+ if( !ctx->next ) {
+ ctx->next = xmalloc_clear( sizeof *ctx );
+ }
+ mpihelp_mul_karatsuba_case( ctx->tspace,
+ vp, vsize,
+ up, usize,
+ ctx->next );
+ }
+
+ cy = mpihelp_add_n( prodp, prodp, ctx->tspace, vsize);
+ mpihelp_add_1( prodp + vsize, ctx->tspace + vsize, usize, cy );
+ }
+}
+
+
+void
+mpihelp_release_karatsuba_ctx( struct karatsuba_ctx *ctx )
+{
+ struct karatsuba_ctx *ctx2;
+
+ if( ctx->tp )
+ mpi_free_limb_space( ctx->tp );
+ if( ctx->tspace )
+ mpi_free_limb_space( ctx->tspace );
+ for( ctx=ctx->next; ctx; ctx = ctx2 ) {
+ ctx2 = ctx->next;
+ if( ctx->tp )
+ mpi_free_limb_space( ctx->tp );
+ if( ctx->tspace )
+ mpi_free_limb_space( ctx->tspace );
+ xfree( ctx );
+ }
+}
+
+/* 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;
+ struct karatsuba_ctx ctx;
+
+ 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;
+ }
+
+ memset( &ctx, 0, sizeof ctx );
+ mpihelp_mul_karatsuba_case( prodp, up, usize, vp, vsize, &ctx );
+ mpihelp_release_karatsuba_ctx( &ctx );
+ return *prod_endp;
+}
+
+
diff -uNr a/mpi/mpih-rshift.c b/mpi/mpih-rshift.c
--- a/mpi/mpih-rshift.c false
+++ b/mpi/mpih-rshift.c b98cf2fb49b284c7ffda191d6e1a336e87bc9d5c302753c04e704de455793bd9736d6318e1c314fc8cf97baebc830eae998c35382afb2810126c1cc9bd18bdce
@@ -0,0 +1,67 @@
+/* mpih-rshift.c - MPI helper functions
+ * Copyright (C) 1994, 1996, 1998, 1999,
+ * 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+
+
+/* Shift U (pointed to by UP and USIZE limbs long) CNT bits to the right
+ * and store the USIZE least significant limbs of the result at WP.
+ * The bits shifted out to the right are returned.
+ *
+ * Argument constraints:
+ * 1. 0 < CNT < BITS_PER_MP_LIMB
+ * 2. If the result is to be written over the input, WP must be <= UP.
+ */
+
+mpi_limb_t
+mpihelp_rshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned cnt)
+{
+ mpi_limb_t high_limb, low_limb;
+ unsigned sh_1, sh_2;
+ mpi_size_t i;
+ mpi_limb_t retval;
+
+ sh_1 = cnt;
+ wp -= 1;
+ sh_2 = BITS_PER_MPI_LIMB - sh_1;
+ high_limb = up[0];
+ retval = high_limb << sh_2;
+ low_limb = high_limb;
+ for( i=1; i < usize; i++) {
+ high_limb = up[i];
+ wp[i] = (low_limb >> sh_1) | (high_limb << sh_2);
+ low_limb = high_limb;
+ }
+ wp[i] = low_limb >> sh_1;
+
+ return retval;
+}
+
diff -uNr a/mpi/mpih-sub1.c b/mpi/mpih-sub1.c
--- a/mpi/mpih-sub1.c false
+++ b/mpi/mpih-sub1.c 1f021e754f091eac1ab7b46306b00849f7160cfa7cd0cc8a6481020b6d42cb12058cd12ac9e2b1d7f730688fbe2d876374ec9d5bb7a5f9d66a42cc9259cf2539
@@ -0,0 +1,64 @@
+/* mpihelp-add_2.c - MPI helper functions
+ * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+
+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; /* get out carry from that addition */
+ y = x - y; /* main subtract */
+ cy += y > x; /* get out carry from the subtract, combine */
+ res_ptr[j] = y;
+ } while( ++j );
+
+ return cy;
+}
+
+
diff -uNr a/mpi/mpi-inline.c b/mpi/mpi-inline.c
--- a/mpi/mpi-inline.c false
+++ b/mpi/mpi-inline.c 22b8e75d35abc0449e048a2b18461b17d7ef5a6a00a56fe1a16bd89b526b8f6f19dea196a258d6e3760f84b1124d7d40fa28d1b6c5bc4932be11b9d91c7077ec
@@ -0,0 +1,35 @@
+/* mpi-inline.c
+ * Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+
+/* put the inline functions as real functions into the lib */
+#define G10_MPI_INLINE_DECL
+
+#include "mpi-internal.h"
+
+/* always include the header becuase it is only
+ * included by mpi-internal if __GCC__ is defined but we
+ * need it here in all cases and the above definition of
+ * of the macro allows us to do so
+ */
+#include "mpi-inline.h"
+
diff -uNr a/mpi/mpi-inv.c b/mpi/mpi-inv.c
--- a/mpi/mpi-inv.c false
+++ b/mpi/mpi-inv.c 66edf48a07bb672b7d9329150436a40ab2f1628f1f289b4c52b2e4bdb987b9105f36c441fb21a141346406a675d34b6265a4a0bc00d3c4de471f461d0acc5765
@@ -0,0 +1,266 @@
+/* mpi-inv.c - MPI functions
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+
+
+/****************
+ * Calculate the multiplicative inverse X of A mod N
+ * That is: Find the solution x for
+ * 1 = (a*x) mod n
+ */
+void
+mpi_invm( MPI x, MPI a, MPI n )
+{
+#if 0
+ MPI u, v, u1, u2, u3, v1, v2, v3, q, t1, t2, t3;
+ MPI ta, tb, tc;
+
+ u = mpi_copy(a);
+ v = mpi_copy(n);
+ 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)+1 );
+ t1 = mpi_alloc( mpi_get_nlimbs(u)+1 );
+ t2 = mpi_alloc( mpi_get_nlimbs(u)+1 );
+ t3 = mpi_alloc( mpi_get_nlimbs(u)+1 );
+ while( mpi_cmp_ui( v3, 0 ) ) {
+ 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);
+ }
+ /* log_debug("result:\n");
+ log_mpidump("q =", q );
+ log_mpidump("u1=", u1);
+ log_mpidump("u2=", u2);
+ log_mpidump("u3=", u3);
+ log_mpidump("v1=", v1);
+ log_mpidump("v2=", v2); */
+ mpi_set(x, u1);
+
+ 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);
+ mpi_free(u);
+ mpi_free(v);
+#elif 0
+ /* Extended Euclid's algorithm (See TAOPC Vol II, 4.5.2, Alg X)
+ * modified according to Michael Penk's solution for Exercice 35 */
+
+ /* FIXME: we can simplify this in most cases (see Knuth) */
+ MPI u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3;
+ unsigned k;
+ int sign;
+
+ u = mpi_copy(a);
+ v = mpi_copy(n);
+ for(k=0; !mpi_test_bit(u,0) && !mpi_test_bit(v,0); k++ ) {
+ mpi_rshift(u, u, 1);
+ mpi_rshift(v, v, 1);
+ }
+
+
+ u1 = mpi_alloc_set_ui(1);
+ u2 = mpi_alloc_set_ui(0);
+ u3 = mpi_copy(u);
+ v1 = mpi_copy(v); /* !-- used as const 1 */
+ v2 = mpi_alloc( mpi_get_nlimbs(u) ); mpi_sub( v2, u1, u );
+ v3 = mpi_copy(v);
+ if( mpi_test_bit(u, 0) ) { /* u is odd */
+ t1 = mpi_alloc_set_ui(0);
+ t2 = mpi_alloc_set_ui(1); t2->sign = 1;
+ t3 = mpi_copy(v); t3->sign = !t3->sign;
+ goto Y4;
+ }
+ else {
+ t1 = mpi_alloc_set_ui(1);
+ t2 = mpi_alloc_set_ui(0);
+ t3 = mpi_copy(u);
+ }
+ do {
+ do {
+ if( mpi_test_bit(t1, 0) || mpi_test_bit(t2, 0) ) { /* one is odd */
+ mpi_add(t1, t1, v);
+ mpi_sub(t2, t2, u);
+ }
+ mpi_rshift(t1, t1, 1);
+ mpi_rshift(t2, t2, 1);
+ mpi_rshift(t3, t3, 1);
+ Y4:
+ ;
+ } while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */
+
+ if( !t3->sign ) {
+ mpi_set(u1, t1);
+ mpi_set(u2, t2);
+ mpi_set(u3, t3);
+ }
+ else {
+ mpi_sub(v1, v, t1);
+ sign = u->sign; u->sign = !u->sign;
+ mpi_sub(v2, u, t2);
+ u->sign = sign;
+ sign = t3->sign; t3->sign = !t3->sign;
+ mpi_set(v3, t3);
+ t3->sign = sign;
+ }
+ mpi_sub(t1, u1, v1);
+ mpi_sub(t2, u2, v2);
+ mpi_sub(t3, u3, v3);
+ if( t1->sign ) {
+ mpi_add(t1, t1, v);
+ mpi_sub(t2, t2, u);
+ }
+ } while( mpi_cmp_ui( t3, 0 ) ); /* while t3 != 0 */
+ /* mpi_lshift( u3, k ); */
+ mpi_set(x, u1);
+
+ mpi_free(u1);
+ mpi_free(u2);
+ mpi_free(u3);
+ mpi_free(v1);
+ mpi_free(v2);
+ mpi_free(v3);
+ mpi_free(t1);
+ mpi_free(t2);
+ mpi_free(t3);
+#else
+ /* Extended Euclid's algorithm (See TAOPC Vol II, 4.5.2, Alg X)
+ * modified according to Michael Penk's solution for Exercice 35
+ * with further enhancement */
+ MPI u, v, u1, u2=NULL, u3, v1, v2=NULL, v3, t1, t2=NULL, t3;
+ unsigned k;
+ int sign;
+ int odd ;
+
+ u = mpi_copy(a);
+ v = mpi_copy(n);
+
+ for(k=0; !mpi_test_bit(u,0) && !mpi_test_bit(v,0); k++ ) {
+ mpi_rshift(u, u, 1);
+ mpi_rshift(v, v, 1);
+ }
+ odd = mpi_test_bit(v,0);
+
+ u1 = mpi_alloc_set_ui(1);
+ if( !odd )
+ u2 = mpi_alloc_set_ui(0);
+ u3 = mpi_copy(u);
+ v1 = mpi_copy(v);
+ if( !odd ) {
+ v2 = mpi_alloc( mpi_get_nlimbs(u) );
+ mpi_sub( v2, u1, u ); /* U is used as const 1 */
+ }
+ v3 = mpi_copy(v);
+ if( mpi_test_bit(u, 0) ) { /* u is odd */
+ t1 = mpi_alloc_set_ui(0);
+ if( !odd ) {
+ t2 = mpi_alloc_set_ui(1); t2->sign = 1;
+ }
+ t3 = mpi_copy(v); t3->sign = !t3->sign;
+ goto Y4;
+ }
+ else {
+ t1 = mpi_alloc_set_ui(1);
+ if( !odd )
+ t2 = mpi_alloc_set_ui(0);
+ t3 = mpi_copy(u);
+ }
+ do {
+ do {
+ if( !odd ) {
+ if( mpi_test_bit(t1, 0) || mpi_test_bit(t2, 0) ) { /* one is odd */
+ mpi_add(t1, t1, v);
+ mpi_sub(t2, t2, u);
+ }
+ mpi_rshift(t1, t1, 1);
+ mpi_rshift(t2, t2, 1);
+ mpi_rshift(t3, t3, 1);
+ }
+ else {
+ if( mpi_test_bit(t1, 0) )
+ mpi_add(t1, t1, v);
+ mpi_rshift(t1, t1, 1);
+ mpi_rshift(t3, t3, 1);
+ }
+ Y4:
+ ;
+ } while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */
+
+ if( !t3->sign ) {
+ mpi_set(u1, t1);
+ if( !odd )
+ mpi_set(u2, t2);
+ mpi_set(u3, t3);
+ }
+ else {
+ mpi_sub(v1, v, t1);
+ sign = u->sign; u->sign = !u->sign;
+ if( !odd )
+ mpi_sub(v2, u, t2);
+ u->sign = sign;
+ sign = t3->sign; t3->sign = !t3->sign;
+ mpi_set(v3, t3);
+ t3->sign = sign;
+ }
+ mpi_sub(t1, u1, v1);
+ if( !odd )
+ mpi_sub(t2, u2, v2);
+ mpi_sub(t3, u3, v3);
+ if( t1->sign ) {
+ mpi_add(t1, t1, v);
+ if( !odd )
+ mpi_sub(t2, t2, u);
+ }
+ } while( mpi_cmp_ui( t3, 0 ) ); /* while t3 != 0 */
+ /* mpi_lshift( u3, k ); */
+ mpi_set(x, u1);
+
+ mpi_free(u1);
+ mpi_free(v1);
+ mpi_free(t1);
+ if( !odd ) {
+ mpi_free(u2);
+ mpi_free(v2);
+ mpi_free(t2);
+ }
+ mpi_free(u3);
+ mpi_free(v3);
+ mpi_free(t3);
+
+ mpi_free(u);
+ mpi_free(v);
+#endif
+}
diff -uNr a/mpi/mpi-mpow.c b/mpi/mpi-mpow.c
--- a/mpi/mpi-mpow.c false
+++ b/mpi/mpi-mpow.c a87ebb2e2397f5903eaa0066a9adf8f977bf7a67866cd181d0699b6d6a029880d86f349be9cb9e6901d35b052bd871380e18ab19efcf319c8a3662a93691856e
@@ -0,0 +1,98 @@
+/* mpi-mpow.c - MPI functions
+ * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+#include
+
+static int
+build_index( MPI *exparray, int k, int i, int t )
+{
+ int j, bitno;
+ int idx = 0;
+
+ bitno = t-i;
+ for(j=k-1; j >= 0; j-- ) {
+ idx <<= 1;
+ if( mpi_test_bit( exparray[j], bitno ) )
+ idx |= 1;
+ }
+ return idx;
+}
+
+/****************
+ * RES = (BASE[0] ^ EXP[0]) * (BASE[1] ^ EXP[1]) * ... * mod M
+ */
+void
+mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m)
+{
+ int k; /* number of elements */
+ int t; /* bit size of largest exponent */
+ int i, j, idx;
+ MPI *G; /* table with precomputed values of size 2^k */
+ MPI tmp;
+
+ for(k=0; basearray[k]; k++ )
+ ;
+ assert(k);
+ for(t=0, i=0; (tmp=exparray[i]); i++ ) {
+ j = mpi_get_nbits(tmp);
+ if( j > t )
+ t = j;
+ }
+ assert(i==k);
+ assert(t);
+ assert( k < 10 );
+
+ G = xmalloc_clear( (1<= 0 && idx < (1<.
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+
+
+void
+mpi_mul_ui( MPI prod, MPI mult, unsigned long small_mult )
+{
+ mpi_size_t size, prod_size;
+ mpi_ptr_t prod_ptr;
+ mpi_limb_t cy;
+ int sign;
+
+ size = mult->nlimbs;
+ sign = mult->sign;
+
+ if( !size || !small_mult ) {
+ prod->nlimbs = 0;
+ prod->sign = 0;
+ return;
+ }
+
+ prod_size = size + 1;
+ if( prod->alloced < prod_size )
+ mpi_resize( prod, prod_size );
+ prod_ptr = prod->d;
+
+ cy = mpihelp_mul_1( prod_ptr, mult->d, size, (mpi_limb_t)small_mult );
+ if( cy )
+ prod_ptr[size++] = cy;
+ prod->nlimbs = size;
+ prod->sign = sign;
+}
+
+
+void
+mpi_mul_2exp( MPI w, MPI u, unsigned long cnt)
+{
+ mpi_size_t usize, wsize, limb_cnt;
+ mpi_ptr_t wp;
+ mpi_limb_t wlimb;
+ int usign, wsign;
+
+ usize = u->nlimbs;
+ usign = u->sign;
+
+ if( !usize ) {
+ w->nlimbs = 0;
+ w->sign = 0;
+ return;
+ }
+
+ limb_cnt = cnt / BITS_PER_MPI_LIMB;
+ wsize = usize + limb_cnt + 1;
+ if( w->alloced < wsize )
+ mpi_resize(w, wsize );
+ wp = w->d;
+ wsize = usize + limb_cnt;
+ wsign = usign;
+
+ cnt %= BITS_PER_MPI_LIMB;
+ if( cnt ) {
+ wlimb = mpihelp_lshift( wp + limb_cnt, u->d, usize, cnt );
+ if( wlimb ) {
+ wp[wsize] = wlimb;
+ wsize++;
+ }
+ }
+ else {
+ MPN_COPY_DECR( wp + limb_cnt, u->d, usize );
+ }
+
+ /* Zero all whole limbs at low end. Do it here and not before calling
+ * mpn_lshift, not to lose for U == W. */
+ MPN_ZERO( wp, limb_cnt );
+
+ w->nlimbs = wsize;
+ w->sign = wsign;
+}
+
+
+
+void
+mpi_mul( MPI w, MPI u, MPI v)
+{
+ mpi_size_t usize, vsize, wsize;
+ mpi_ptr_t up, vp, wp;
+ mpi_limb_t cy;
+ int usign, vsign, usecure, vsecure, 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;
+ usecure = mpi_is_secure(v);
+ up = v->d;
+ vsize = u->nlimbs;
+ vsign = u->sign;
+ vsecure = mpi_is_secure(u);
+ vp = u->d;
+ }
+ else {
+ usize = u->nlimbs;
+ usign = u->sign;
+ usecure = mpi_is_secure(u);
+ up = u->d;
+ vsize = v->nlimbs;
+ vsign = v->sign;
+ vsecure = mpi_is_secure(v);
+ vp = v->d;
+ }
+ sign_product = usign ^ vsign;
+ wp = w->d;
+
+ /* Ensure W has space enough to store the result. */
+ wsize = usize + vsize;
+ if ( !mpi_is_secure (w) && (mpi_is_secure (u) || mpi_is_secure (v)) ) {
+ /* w is not allocated in secure space but u or v is. To make sure
+ * that no temporray results are stored in w, we temporary use
+ * a newly allocated limb space for w */
+ wp = mpi_alloc_limb_space( wsize, 1 );
+ assign_wp = 2; /* mark it as 2 so that we can later copy it back to
+ * mormal memory */
+ }
+ else if( w->alloced < wsize ) {
+ if( wp == up || wp == vp ) {
+ wp = mpi_alloc_limb_space( wsize, mpi_is_secure(w) );
+ 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, usecure );
+ /* 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, vsecure );
+ /* 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 ) {
+ if (assign_wp == 2) {
+ /* copy the temp wp from secure memory back to normal memory */
+ mpi_ptr_t tmp_wp = mpi_alloc_limb_space (wsize, 0);
+ MPN_COPY (tmp_wp, wp, wsize);
+ mpi_free_limb_space (wp);
+ wp = tmp_wp;
+ }
+ mpi_assign_limb_space( w, wp, wsize );
+ }
+ w->nlimbs = wsize;
+ w->sign = sign_product;
+ if( tmp_limb )
+ mpi_free_limb_space( tmp_limb );
+}
+
+
+void
+mpi_mulm( MPI w, MPI u, MPI v, MPI m)
+{
+ mpi_mul(w, u, v);
+ mpi_fdiv_r( w, w, m );
+}
+
diff -uNr a/mpi/mpi-pow.c b/mpi/mpi-pow.c
--- a/mpi/mpi-pow.c false
+++ b/mpi/mpi-pow.c 8341923461226ec55de5b29209cc03051587de11885cb49433ff4c0eba2160798b7dc27573b9bc363ee0954a8fc08cbd21af3f655a9c0bc8aa294a74f80eb2c9
@@ -0,0 +1,294 @@
+/* mpi-pow.c - MPI functions
+ * Copyright (C) 1994, 1996, 1998, 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ * Actually it's the same code with only minor changes in the
+ * way the data is stored; this is to support the abstraction
+ * of an optional secure memory allocation which may be used
+ * to avoid revealing of sensitive data due to paging etc.
+ * The GNU MP Library itself is published under the LGPL;
+ * however I decided to publish this code under the plain GPL.
+ */
+
+#include
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+#include
+
+
+/****************
+ * RES = BASE ^ EXP mod MOD
+ */
+void
+mpi_powm( MPI res, MPI base, MPI exponent, MPI mod)
+{
+ mpi_ptr_t rp, ep, mp, bp;
+ mpi_size_t esize, msize, bsize, rsize;
+ int esign, msign, bsign, rsign;
+ int esec, msec, bsec, rsec;
+ 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;
+ mpi_ptr_t tspace = NULL;
+ mpi_size_t tsize=0; /* to avoid compiler warning */
+ /* fixme: we should check that the warning is void*/
+
+ esize = exponent->nlimbs;
+ msize = mod->nlimbs;
+ size = 2 * msize;
+ esign = exponent->sign;
+ msign = mod->sign;
+
+ esec = mpi_is_secure(exponent);
+ msec = mpi_is_secure(mod);
+ bsec = mpi_is_secure(base);
+ rsec = mpi_is_secure(res);
+
+ rp = res->d;
+ ep = exponent->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, msec);
+ 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, bsec );
+ 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, rsec );
+ assign_rp = 1;
+ }
+ else {
+ mpi_resize( res, size );
+ rp = res->d;
+ }
+ }
+ else { /* Make BASE, EXPONENT 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, bsec );
+ MPN_COPY(bp, rp, bsize);
+ }
+ if( rp == ep ) {
+ /* RES and EXPONENT are identical.
+ Allocate temp. space for EXPONENT. */
+ ep = ep_marker = mpi_alloc_limb_space( esize, esec );
+ 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, msec );
+ 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), msec );
+ int c;
+ mpi_limb_t e;
+ mpi_limb_t carry_limb;
+ struct karatsuba_ctx karactx;
+
+ memset( &karactx, 0, sizeof karactx );
+ 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);*/
+ if( rsize < KARATSUBA_THRESHOLD )
+ mpih_sqr_n_basecase( xp, rp, rsize );
+ else {
+ if( !tspace ) {
+ tsize = 2 * rsize;
+ tspace = mpi_alloc_limb_space( tsize, 0 );
+ }
+ else if( tsize < (2*rsize) ) {
+ mpi_free_limb_space( tspace );
+ tsize = 2 * rsize;
+ tspace = mpi_alloc_limb_space( tsize, 0 );
+ }
+ mpih_sqr_n( xp, rp, rsize, tspace );
+ }
+
+ 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 );*/
+ if( bsize < KARATSUBA_THRESHOLD ) {
+ mpihelp_mul( xp, rp, rsize, bp, bsize );
+ }
+ else {
+ mpihelp_mul_karatsuba_case(
+ xp, rp, rsize, bp, bsize, &karactx );
+ }
+
+ 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);
+
+ mpihelp_release_karatsuba_ctx( &karactx );
+ }
+
+ 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 );
+ if( tspace ) mpi_free_limb_space( tspace );
+}
+
diff -uNr a/mpi/mpi-scan.c b/mpi/mpi-scan.c
--- a/mpi/mpi-scan.c false
+++ b/mpi/mpi-scan.c affa0e93e6625cad75cd10c454b493cbebf061aeca3185e45b6571a26ae10f03947a1ef363c0898609f95cc737053e45a73926b22f14f4ec6a800410915d3ff9
@@ -0,0 +1,138 @@
+/* mpi-scan.c - MPI functions
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.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!
+ */
+#if 0 /* Code is not used */
+int
+mpi_getbyte( MPI a, unsigned idx )
+{
+ 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 == idx )
+ return (limb >> j*8) & 0xff;
+ }
+ return -1;
+}
+#endif /* Code is not used */
+
+
+/****************
+ * Put a value at position IDX into A. idx counts from lsb to msb
+ */
+/* FIXME: There is a problem with the long constants which should have
+a LL prefix or better the macros we use at other places. */
+#if 0 /* Code is not used */
+void
+mpi_putbyte( MPI a, unsigned idx, int xc )
+{
+
+ int i, j;
+ unsigned n;
+ mpi_ptr_t ap;
+ mpi_limb_t limb, c;
+
+ c = xc & 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 == idx ) {
+#if BYTES_PER_MPI_LIMB == 4
+ 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);
+#elif BYTES_PER_MPI_LIMB == 8
+ if( j == 0 )
+ limb = (limb & 0xffffffffffffff00) | c;
+ else if( j == 1 )
+ limb = (limb & 0xffffffffffff00ff) | (c<<8);
+ else if( j == 2 )
+ limb = (limb & 0xffffffffff00ffff) | (c<<16);
+ else if( j == 3 )
+ limb = (limb & 0xffffffff00ffffff) | (c<<24);
+ else if( j == 4 )
+ limb = (limb & 0xffffff00ffffffff) | (c<<32);
+ else if( j == 5 )
+ limb = (limb & 0xffff00ffffffffff) | (c<<40);
+ else if( j == 6 )
+ limb = (limb & 0xff00ffffffffffff) | (c<<48);
+ else
+ limb = (limb & 0x00ffffffffffffff) | (c<<56);
+#else
+#error please enhance this function, its ugly - i know.
+#endif
+ if( a->nlimbs <= i )
+ a->nlimbs = i+1;
+ ap[i] = limb;
+ return;
+ }
+ }
+ abort(); /* index out of range */
+}
+#endif /* Code is not used */
+
+
+/****************
+ * Count the number of zerobits at the low end of A
+ */
+unsigned int
+mpi_trailing_zeros( MPI a )
+{
+ unsigned n, count = 0;
+
+ for(n=0; n < a->nlimbs; n++ ) {
+ if( a->d[n] ) {
+ unsigned nn;
+ mpi_limb_t alimb = a->d[n];
+
+ count_trailing_zeros( nn, alimb );
+ count += nn;
+ break;
+ }
+ count += BITS_PER_MPI_LIMB;
+ }
+ return count;
+
+}
+
+
diff -uNr a/mpi/mpiutil.c b/mpi/mpiutil.c
--- a/mpi/mpiutil.c false
+++ b/mpi/mpiutil.c 757f8a9ffa7640843abc7a20ee7f0460fae4cb11a2928963c85399b7ea7aba3332f5c1574e86dab4bba8384e5bf3f95161c1d1e15db7b85bb96f369f1e67f6fa
@@ -0,0 +1,505 @@
+/* mpiutil.ac - Utility functions for MPI
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "mpi.h"
+#include "mpi-internal.h"
+#include "memory.h"
+#include "util.h"
+
+
+#ifdef M_DEBUG
+#undef mpi_alloc
+#undef mpi_alloc_secure
+#undef mpi_free
+#endif
+
+/****************
+ * Note: It was a bad idea to use the number of limbs to allocate
+ * because on a alpha the limbs are large but we normally need
+ * integers of n bits - So we should chnage this to bits (or bytes).
+ *
+ * But mpi_alloc is used in a lot of places :-)
+ */
+MPI
+#ifdef M_DEBUG
+mpi_debug_alloc( unsigned nlimbs, const char *info )
+#else
+mpi_alloc( unsigned nlimbs )
+#endif
+{
+ MPI a;
+
+ if( DBG_MEMORY )
+ log_debug("mpi_alloc(%u)\n", nlimbs*BITS_PER_MPI_LIMB );
+#ifdef M_DEBUG
+ a = m_debug_alloc( sizeof *a, info );
+ a->d = nlimbs? mpi_debug_alloc_limb_space( nlimbs, 0, info ) : NULL;
+#else
+ a = xmalloc( sizeof *a );
+ a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 0 ) : NULL;
+#endif
+ a->alloced = nlimbs;
+ a->nlimbs = 0;
+ a->sign = 0;
+ a->flags = 0;
+ a->nbits = 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;
+
+ if( DBG_MEMORY )
+ log_debug("mpi_alloc_secure(%u)\n", nlimbs*BITS_PER_MPI_LIMB );
+#ifdef M_DEBUG
+ a = m_debug_alloc( sizeof *a, info );
+ a->d = nlimbs? mpi_debug_alloc_limb_space( nlimbs, 1, info ) : NULL;
+#else
+ a = xmalloc( sizeof *a );
+ a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 1 ) : NULL;
+#endif
+ a->alloced = nlimbs;
+ a->flags = 1;
+ a->nlimbs = 0;
+ a->sign = 0;
+ a->nbits = 0;
+ return a;
+}
+
+
+#if 0
+static void *unused_limbs_5;
+static void *unused_limbs_32;
+static void *unused_limbs_64;
+#endif
+
+mpi_ptr_t
+#ifdef M_DEBUG
+mpi_debug_alloc_limb_space( unsigned nlimbs, int secure, const char *info )
+#else
+mpi_alloc_limb_space( unsigned nlimbs, int secure )
+#endif
+{
+ size_t len = nlimbs * sizeof(mpi_limb_t);
+ mpi_ptr_t p;
+
+ if( DBG_MEMORY )
+ log_debug("mpi_alloc_limb_space(%u)\n", (unsigned)len*8 );
+#if 0
+ if( !secure ) {
+ if( nlimbs == 5 && unused_limbs_5 ) { /* DSA 160 bits */
+ p = unused_limbs_5;
+ unused_limbs_5 = *p;
+ return p;
+ }
+ else if( nlimbs == 32 && unused_limbs_32 ) { /* DSA 1024 bits */
+ p = unused_limbs_32;
+ unused_limbs_32 = *p;
+ return p;
+ }
+ else if( nlimbs == 64 && unused_limbs_64 ) { /* DSA 2*1024 bits */
+ p = unused_limbs_64;
+ unused_limbs_64 = *p;
+ return p;
+ }
+ }
+#endif
+
+#ifdef M_DEBUG
+ p = secure? m_debug_alloc_secure(len, info):m_debug_alloc( len, info );
+#else
+ p = secure? xmalloc_secure( len ):xmalloc( len );
+#endif
+
+ return p;
+}
+
+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
+{
+ if( !a )
+ return;
+ if( DBG_MEMORY )
+ log_debug("mpi_free_limb_space of size %lu\n", (ulong)m_size(a)*8 );
+
+#if 0
+ if( !m_is_secure(a) ) {
+ size_t nlimbs = m_size(a) / 4 ;
+ void *p = a;
+
+ if( nlimbs == 5 ) { /* DSA 160 bits */
+ *a = unused_limbs_5;
+ unused_limbs_5 = a;
+ return;
+ }
+ else if( nlimbs == 32 ) { /* DSA 1024 bits */
+ *a = unused_limbs_32;
+ unused_limbs_32 = a;
+ return;
+ }
+ else if( nlimbs == 64 ) { /* DSA 2*1024 bits */
+ *a = unused_limbs_64;
+ unused_limbs_64 = a;
+ return;
+ }
+ }
+#endif
+
+ xfree(a);
+}
+
+
+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 xrealloc()]
+ */
+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 */
+ /* Note: a->secure is not used - instead the realloc functions
+ * take care of it. Maybe we should drop a->secure completely
+ * and rely on a mpi_is_secure function, which would be
+ * a wrapper around m_is_secure
+ */
+#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 = xrealloc(a->d, nlimbs * sizeof(mpi_limb_t) );
+ else
+ a->d = xmalloc_clear( nlimbs * sizeof(mpi_limb_t) );
+#endif
+ a->alloced = nlimbs;
+}
+
+void
+mpi_clear( MPI a )
+{
+ a->nlimbs = 0;
+ a->nbits = 0;
+ a->flags = 0;
+}
+
+
+void
+#ifdef M_DEBUG
+mpi_debug_free( MPI a, const char *info )
+#else
+mpi_free( MPI a )
+#endif
+{
+ if( !a )
+ return;
+ if( DBG_MEMORY )
+ log_debug("mpi_free\n" );
+ if( a->flags & 4 )
+ xfree( a->d );
+ else {
+#ifdef M_DEBUG
+ mpi_debug_free_limb_space(a->d, info);
+#else
+ mpi_free_limb_space(a->d);
+#endif
+ }
+ if( a->flags & ~7 )
+ log_bug("invalid flag value in mpi\n");
+ xfree(a);
+}
+
+
+void
+mpi_set_secure( MPI a )
+{
+ mpi_ptr_t ap, bp;
+
+ if( (a->flags & 1) )
+ return;
+ a->flags |= 1;
+ ap = a->d;
+ if( !a->nlimbs ) {
+ assert(!ap);
+ return;
+ }
+#ifdef M_DEBUG
+ bp = mpi_debug_alloc_limb_space( a->nlimbs, 1, "set_secure" );
+#else
+ bp = mpi_alloc_limb_space( a->nlimbs, 1 );
+#endif
+ MPN_COPY( bp, ap, a->nlimbs );
+ a->d = bp;
+#ifdef M_DEBUG
+ mpi_debug_free_limb_space(ap, "set_secure");
+#else
+ mpi_free_limb_space(ap);
+#endif
+}
+
+
+MPI
+mpi_set_opaque( MPI a, void *p, unsigned int len )
+{
+ if( !a ) {
+#ifdef M_DEBUG
+ a = mpi_debug_alloc(0,"alloc_opaque");
+#else
+ a = mpi_alloc(0);
+#endif
+ }
+
+ if( a->flags & 4 )
+ xfree( a->d );
+ else {
+#ifdef M_DEBUG
+ mpi_debug_free_limb_space(a->d, "alloc_opaque");
+#else
+ mpi_free_limb_space(a->d);
+#endif
+ }
+
+ a->d = p;
+ a->alloced = 0;
+ a->nlimbs = 0;
+ a->nbits = len;
+ a->flags = 4;
+ return a;
+}
+
+
+void *
+mpi_get_opaque( MPI a, unsigned int *len )
+{
+ if( !(a->flags & 4) )
+ log_bug("mpi_get_opaque on normal mpi\n");
+ if( len )
+ *len = a->nbits;
+ return a->d;
+}
+
+
+/****************
+ * Note: This copy function should not interpret the MPI
+ * but copy it transparently.
+ */
+MPI
+#ifdef M_DEBUG
+mpi_debug_copy( MPI a, const char *info )
+#else
+mpi_copy( MPI a )
+#endif
+{
+ int i;
+ MPI b;
+
+ if( a && (a->flags & 4) ) {
+ void *p = m_is_secure(a->d)? xmalloc_secure( a->nbits )
+ : xmalloc( a->nbits );
+ memcpy( p, a->d, a->nbits );
+ b = mpi_set_opaque( NULL, p, a->nbits );
+ }
+ else if( a ) {
+#ifdef M_DEBUG
+ b = mpi_is_secure(a)? mpi_debug_alloc_secure( a->nlimbs, info )
+ : mpi_debug_alloc( a->nlimbs, info );
+#else
+ b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs )
+ : mpi_alloc( a->nlimbs );
+#endif
+ b->nlimbs = a->nlimbs;
+ b->sign = a->sign;
+ b->flags = a->flags;
+ b->nbits = a->nbits;
+ for(i=0; i < b->nlimbs; i++ )
+ b->d[i] = a->d[i];
+ }
+ else
+ b = NULL;
+ return b;
+}
+
+
+/****************
+ * This function allocates an MPI which is optimized to hold
+ * a value as large as the one given in the argument and allocates it
+ * with the same flags as A.
+ */
+MPI
+#ifdef M_DEBUG
+mpi_debug_alloc_like( MPI a, const char *info )
+#else
+mpi_alloc_like( MPI a )
+#endif
+{
+ MPI b;
+
+ if( a && (a->flags & 4) ) {
+ void *p = m_is_secure(a->d)? xmalloc_secure( a->nbits )
+ : xmalloc( a->nbits );
+ memcpy( p, a->d, a->nbits );
+ b = mpi_set_opaque( NULL, p, a->nbits );
+ }
+ else if( a ) {
+#ifdef M_DEBUG
+ b = mpi_is_secure(a)? mpi_debug_alloc_secure( a->nlimbs, info )
+ : mpi_debug_alloc( a->nlimbs, info );
+#else
+ b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs )
+ : mpi_alloc( a->nlimbs );
+#endif
+ b->nlimbs = 0;
+ b->sign = 0;
+ b->flags = a->flags;
+ b->nbits = 0;
+ }
+ 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->nbits = u->nbits;
+ w->flags = u->flags;
+ 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;
+ w->nbits = 0;
+ w->flags = 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)
+{
+ struct gcry_mpi tmp;
+
+ tmp = *a; *a = *b; *b = tmp;
+}
+
+
+int
+mpi_get_nlimbs (MPI a)
+{
+ return a->nlimbs;
+}
+
+
+int
+mpi_is_neg (MPI a)
+{
+ return a->sign;
+}
+
+
+/* Return the number of limbs to store an MPI which is specified by
+ the number of bytes to represent it. */
+unsigned int
+mpi_nlimb_hint_from_nbytes (unsigned int nbytes)
+{
+ return (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB;
+}
+
+/* Return the number of limbs to store an MPI which is specified by
+ the number of bytes to represent it. */
+unsigned int
+mpi_nlimb_hint_from_nbits (unsigned int nbits)
+{
+ return (nbits+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB;
+}
+
+unsigned int
+mpi_get_flags (MPI a)
+{
+ return a->flags;
+}
diff -uNr a/mpi/obj/README b/mpi/obj/README
--- a/mpi/obj/README false
+++ b/mpi/obj/README 0fba934fb804042ef44214806d9256ee9d9e9a51878ca97942941c1ef5a9e81f779c2ab99c0c6f3c9dd01a748db7d4624e35635fd2a748df00655f95cbd98f22
@@ -0,0 +1 @@
+obj
\ No newline at end of file
diff -uNr a/mpi/README b/mpi/README
--- a/mpi/README false
+++ b/mpi/README 6be57f08ec92d8bb7fba6e14de060ca60d0655b3dad55ccc31b8387b9a305361f208e05589f091f8a0f774d9830e43b015e81e5ddc16ec41c16b00a04a13f69f
@@ -0,0 +1,57 @@
+What you see here is a very classic version of the GNU MPI (bignum) library.
+It has been surgically removed from GnuPG 1.4.10, specifically as found at:
+
+http://trilema.com/wp-content/uploads/2015/10/gnupg-1.4.10.tar.gz.asc
+
+SHA512(gnupg-1.4.10.tar.gz) :
+d037041d2e6882fd3b999500b5a7b42be2c224836afc358e1f8a2465c1b74473d518f185b7c324b2c8dec4ffb70e9e34a03c94d1a54cc55d297f40c9745f6e1b
+
+CHANGES FROM ORIGINAL:
+
+1) Everything pertaining to Automake was nuked, and the earth where it stood -
+ salted.
+
+ Instead, we now have a conventional Makefile. It builds precisely
+ ONE THING - a single 'mpi.a' library suitable for static linking into
+ another project. This will turn up in 'bin'.
+
+ Among other things, this now means that all KNOBS now reside in a
+ MANUALLY-controlled 'config.h' found in 'include'. If you are building
+ on some very peculiar unix, please read it and adjust as appropriate.
+ It contains ONLY those knobs which actually pertain to the code.
+
+ The Makefile contains a 'check-syntax' - users of Emacs and Flymake
+ will see proper error-highlighting.
+
+2) ALL chip-specific ASM optimizations (including those found in longlong.h)
+ have been nuked.
+
+3) GPG-specific cruft has been amputated to the extent practical.
+
+ The logging system has been retained, but it can be easily torn out,
+ which I may choose to do in the near future.
+
+ The I/O buffering system has been retained. I may choose to remove it
+ in the near future.
+
+ The 'secure memory' (unpageable alloc) system has been retained.
+
+ 'Localization' and all related idiocies have been nuked.
+ Write hieroglyphs at home, leave them there, civilized folk
+ don't need'em in their source code.
+
+4) Other code has been altered solely to the extent required by items
+ (1) and (2).
+
+ Cruft which appears in dead #ifdefs may be removed in the future.
+ Don't get comfortable with it being there.
+
+5) Readers who wish to know EXACTLY what I changed, should get a copy of the
+ original tarball and write a simple script involving 'find' and 'vdiff',
+ which sadly did not fit in the margins of this page.
+
+6) To use the library, include 'include/mpi.h' in your project,
+ and statically link with 'bin/mpi.a'.
+
+7) The original code was distributed under GPL 3, which may apply on
+ your planet and is therefore included. (See COPYING.)
diff -uNr a/mpi/secmem.c b/mpi/secmem.c
--- a/mpi/secmem.c false
+++ b/mpi/secmem.c a0b28117315bd9560be404c97e44252316fd19ff9cbc762bf5d46235034846155d5058e22a73d7010f78cf7442ba6624e2417a719ffcbe2f8a163090706e069c
@@ -0,0 +1,519 @@
+/* secmem.c - memory allocation from a secure heap
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ * 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
+#include
+#include
+#include
+#ifdef USE_CAPABILITIES
+#include
+#endif
+#ifdef HAVE_PLOCK
+#include
+#endif
+#endif
+
+#include "types.h"
+#include "memory.h"
+#include "util.h"
+
+/* MinGW doesn't seem to prototype getpagesize, though it does have
+ it. */
+#if !HAVE_DECL_GETPAGESIZE
+int getpagesize(void);
+#endif
+
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+/* It seems that Slackware 7.1 does not know about EPERM */
+#if !defined(EPERM) && defined(ENOMEM)
+#define EPERM ENOMEM
+#endif
+
+
+#define DEFAULT_POOLSIZE 16384
+
+typedef struct memblock_struct MEMBLOCK;
+struct memblock_struct {
+ unsigned size;
+ union {
+ MEMBLOCK *next;
+ PROPERLY_ALIGNED_TYPE aligned;
+ } u;
+};
+
+
+
+static void *pool;
+static volatile int pool_okay; /* may be checked in an atexit function */
+#ifdef HAVE_MMAP
+static volatile int pool_is_mmapped;
+#endif
+static size_t poolsize; /* allocated length */
+static size_t poollen; /* used length */
+static MEMBLOCK *unused_blocks;
+static unsigned max_alloced;
+static unsigned cur_alloced;
+static unsigned max_blocks;
+static unsigned cur_blocks;
+static int disable_secmem;
+static int show_warning;
+static int no_warning;
+static int suspend_warning;
+
+
+static void
+print_warn(void)
+{
+ if (!no_warning)
+ {
+ log_info(_("WARNING: using insecure memory!\n"));
+ log_info(_("please see http://www.gnupg.org/faq.html"
+ " for more information\n"));
+ }
+}
+
+
+static void
+lock_pool( void *p, size_t n )
+{
+#if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
+ int err;
+
+ cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
+ err = mlock( p, n );
+ if( err && errno )
+ err = errno;
+ cap_set_proc( cap_from_text("cap_ipc_lock+p") );
+
+ if( err ) {
+ if( errno != EPERM
+#ifdef EAGAIN /* OpenBSD returns this */
+ && errno != EAGAIN
+#endif
+#ifdef ENOSYS /* Some SCOs return this (function not implemented) */
+ && errno != ENOSYS
+#endif
+#ifdef ENOMEM /* Linux can return this */
+ && errno != ENOMEM
+#endif
+ )
+ log_error("can't lock memory: %s\n", strerror(err));
+ show_warning = 1;
+ }
+
+#elif defined(HAVE_MLOCK)
+ uid_t uid;
+ int err;
+
+ uid = getuid();
+
+#ifdef HAVE_BROKEN_MLOCK
+ /* ick. but at least we get secured memory. about to lock
+ entire data segment. */
+#ifdef HAVE_PLOCK
+# ifdef _AIX
+ /* The configure for AIX returns broken mlock but the plock has
+ the strange requirement to somehow set the stack limit first.
+ The problem might turn out in indeterministic program behaviour
+ and hanging processes which can somehow be solved when enough
+ processes are clogging up the memory. To get this problem out
+ of the way we simply don't try to lock the memory at all.
+ */
+ errno = EPERM;
+ err = errno;
+# else /* !_AIX */
+ err = plock( DATLOCK );
+ if( err && errno )
+ err = errno;
+# endif /*_AIX*/
+#else /*!HAVE_PLOCK*/
+ if( uid ) {
+ errno = EPERM;
+ err = errno;
+ }
+ else {
+ err = mlock( p, n );
+ if( err && errno )
+ err = errno;
+ }
+#endif /*!HAVE_PLOCK*/
+#else
+ err = mlock( p, n );
+ if( err && errno )
+ err = errno;
+#endif
+
+ if( uid && !geteuid() ) {
+ /* check that we really dropped the privs.
+ * Note: setuid(0) should always fail */
+ if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
+ log_fatal("failed to reset uid: %s\n", strerror(errno));
+ }
+
+ if( err ) {
+ if( errno != EPERM
+#ifdef EAGAIN /* OpenBSD returns this */
+ && errno != EAGAIN
+#endif
+#ifdef ENOSYS /* Some SCOs return this (function not implemented) */
+ && errno != ENOSYS
+#endif
+#ifdef ENOMEM /* Linux can return this */
+ && errno != ENOMEM
+#endif
+ )
+ log_error("can't lock memory: %s\n", strerror(err));
+ show_warning = 1;
+ }
+
+#elif defined ( __QNX__ )
+ /* QNX does not page at all, so the whole secure memory stuff does
+ * not make much sense. However it is still of use because it
+ * wipes out the memory on a free().
+ * Therefore it is sufficient to suppress the warning
+ */
+#elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__)
+ /* It does not make sense to print such a warning, given the fact that
+ * this whole Windows !@#$% and their user base are inherently insecure
+ */
+#elif defined (__riscos__)
+ /* no virtual memory on RISC OS, so no pages are swapped to disc,
+ * besides we don't have mmap, so we don't use it! ;-)
+ * But don't complain, as explained above.
+ */
+#else
+ log_info("Please note that you don't have secure memory on this system\n");
+#endif
+}
+
+
+static void
+init_pool( size_t n)
+{
+ long int pgsize_val;
+ size_t pgsize;
+
+ poolsize = n;
+
+ if( disable_secmem )
+ log_bug("secure memory is disabled");
+
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
+ pgsize_val = sysconf (_SC_PAGESIZE);
+#elif defined(HAVE_GETPAGESIZE)
+ pgsize_val = getpagesize ();
+#else
+ pgsize_val = -1;
+#endif
+ pgsize = (pgsize_val != -1 && pgsize_val > 0)? pgsize_val : 4096;
+
+
+#ifdef HAVE_MMAP
+ poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
+#ifdef MAP_ANONYMOUS
+ pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else /* map /dev/zero instead */
+ { int fd;
+
+ fd = open("/dev/zero", O_RDWR);
+ if( fd == -1 ) {
+ log_error("can't open /dev/zero: %s\n", strerror(errno) );
+ pool = (void*)-1;
+ }
+ else {
+ pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE, fd, 0);
+ close (fd);
+ }
+ }
+#endif
+ if( pool == (void*)-1 )
+ log_info("can't mmap pool of %u bytes: %s - using malloc\n",
+ (unsigned)poolsize, strerror(errno));
+ else {
+ pool_is_mmapped = 1;
+ pool_okay = 1;
+ }
+
+#endif
+ if( !pool_okay ) {
+ pool = malloc( poolsize );
+ if( !pool )
+ log_fatal("can't allocate memory pool of %u bytes\n",
+ (unsigned)poolsize);
+ else
+ pool_okay = 1;
+ }
+ lock_pool( pool, poolsize );
+ poollen = 0;
+}
+
+
+/* concatenate unused blocks */
+static void
+compress_pool(void)
+{
+ /* fixme: we really should do this */
+}
+
+void
+secmem_set_flags( unsigned flags )
+{
+ int was_susp = suspend_warning;
+
+ no_warning = flags & 1;
+ suspend_warning = flags & 2;
+
+ /* and now issue the warning if it is not longer suspended */
+ if( was_susp && !suspend_warning && show_warning ) {
+ show_warning = 0;
+ print_warn();
+ }
+}
+
+unsigned
+secmem_get_flags(void)
+{
+ unsigned flags;
+
+ flags = no_warning ? 1:0;
+ flags |= suspend_warning ? 2:0;
+ return flags;
+}
+
+/* Returns 1 if memory was locked, 0 if not. */
+int
+secmem_init( size_t n )
+{
+ if( !n ) {
+#ifndef __riscos__
+#ifdef USE_CAPABILITIES
+ /* drop all capabilities */
+ cap_set_proc( cap_from_text("all-eip") );
+
+#elif !defined(HAVE_DOSISH_SYSTEM)
+ uid_t uid;
+
+ disable_secmem=1;
+ uid = getuid();
+ if( uid != geteuid() ) {
+ if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
+ log_fatal("failed to drop setuid\n" );
+ }
+#endif
+#endif /* !__riscos__ */
+ }
+ else {
+ if( n < DEFAULT_POOLSIZE )
+ n = DEFAULT_POOLSIZE;
+ if( !pool_okay )
+ init_pool(n);
+ else
+ log_error("Oops, secure memory pool already initialized\n");
+ }
+
+ return !show_warning;
+}
+
+
+void *
+secmem_malloc( size_t size )
+{
+ MEMBLOCK *mb, *mb2;
+ int compressed=0;
+
+ if( !pool_okay ) {
+ log_info(
+ _("operation is not possible without initialized secure memory\n"));
+ log_info(_("(you may have used the wrong program for this task)\n"));
+ exit(2);
+ }
+ if( show_warning && !suspend_warning ) {
+ show_warning = 0;
+ print_warn();
+ }
+
+ /* Blocks are always a multiple of 32. Note that we allocate an
+ extra of the size of an entire MEMBLOCK. This is required
+ becuase we do not only need the SIZE info but also extra space
+ to chain up unused memory blocks. */
+ size += sizeof(MEMBLOCK);
+ size = ((size + 31) / 32) * 32;
+
+ retry:
+ /* try to get it from the used blocks */
+ for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
+ if( mb->size >= size ) {
+ if( mb2 )
+ mb2->u.next = mb->u.next;
+ else
+ unused_blocks = mb->u.next;
+ goto leave;
+ }
+ /* allocate a new block */
+ if( (poollen + size <= poolsize) ) {
+ mb = (void*)((char*)pool + poollen);
+ poollen += size;
+ mb->size = size;
+ }
+ else if( !compressed ) {
+ compressed=1;
+ compress_pool();
+ goto retry;
+ }
+ else
+ return NULL;
+
+ leave:
+ cur_alloced += mb->size;
+ cur_blocks++;
+ if( cur_alloced > max_alloced )
+ max_alloced = cur_alloced;
+ if( cur_blocks > max_blocks )
+ max_blocks = cur_blocks;
+
+ return &mb->u.aligned.c;
+}
+
+
+void *
+secmexrealloc( void *p, size_t newsize )
+{
+ MEMBLOCK *mb;
+ size_t size;
+ void *a;
+
+ mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
+ size = mb->size;
+ if (size < sizeof(MEMBLOCK))
+ log_bug ("secure memory corrupted at block %p\n", (void *)mb);
+ size -= ((size_t) &((MEMBLOCK*)0)->u.aligned.c);
+
+ if( newsize <= size )
+ return p; /* It is easier not to shrink the memory. */
+ a = secmem_malloc( newsize );
+ if ( a ) {
+ memcpy(a, p, size);
+ memset((char*)a+size, 0, newsize-size);
+ secmem_free(p);
+ }
+ return a;
+}
+
+
+void
+secmem_free( void *a )
+{
+ MEMBLOCK *mb;
+ size_t size;
+
+ if( !a )
+ return;
+
+ mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
+ size = mb->size;
+ /* This does not make much sense: probably this memory is held in the
+ * cache. We do it anyway: */
+ wipememory2(mb, 0xff, size );
+ wipememory2(mb, 0xaa, size );
+ wipememory2(mb, 0x55, size );
+ wipememory2(mb, 0x00, size );
+ mb->size = size;
+ mb->u.next = unused_blocks;
+ unused_blocks = mb;
+ cur_blocks--;
+ cur_alloced -= size;
+}
+
+
+/* Check whether P points into the pool. */
+static int
+ptr_into_pool_p (const void *p)
+{
+ /* We need to convert pointers to addresses. This is required by
+ C-99 6.5.8 to avoid undefined behaviour. Using size_t is at
+ least only implementation defined. See also
+ http://lists.gnupg.org/pipermail/gcrypt-devel/2007-February/001102.html
+ */
+ size_t p_addr = (size_t)p;
+ size_t pool_addr = (size_t)pool;
+
+ return p_addr >= pool_addr && p_addr < pool_addr+poolsize;
+}
+
+
+int
+m_is_secure( const void *p )
+{
+ return pool_okay && ptr_into_pool_p (p);
+}
+
+
+
+/****************
+ * Warning: This code might be called by an interrupt handler
+ * and frankly, there should really be such a handler,
+ * to make sure that the memory is wiped out.
+ * We hope that the OS wipes out mlocked memory after
+ * receiving a SIGKILL - it really should do so, otherwise
+ * there is no chance to get the secure memory cleaned.
+ */
+void
+secmem_term()
+{
+ if( !pool_okay )
+ return;
+
+ wipememory2( pool, 0xff, poolsize);
+ wipememory2( pool, 0xaa, poolsize);
+ wipememory2( pool, 0x55, poolsize);
+ wipememory2( pool, 0x00, poolsize);
+#ifdef HAVE_MMAP
+ if( pool_is_mmapped )
+ munmap( pool, poolsize );
+#endif
+ pool = NULL;
+ pool_okay = 0;
+ poolsize=0;
+ poollen=0;
+ unused_blocks=NULL;
+}
+
+
+void
+secmem_dump_stats()
+{
+ if( disable_secmem )
+ return;
+ fprintf(stderr,
+ "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
+ cur_alloced, max_alloced, cur_blocks, max_blocks,
+ (ulong)poollen, (ulong)poolsize );
+}
diff -uNr a/mpi/udiv-w-sdiv.c b/mpi/udiv-w-sdiv.c
--- a/mpi/udiv-w-sdiv.c false
+++ b/mpi/udiv-w-sdiv.c fb984a326a9bcda1a4cbc05ee279e55cfefcf157393d2f66405760b256395c3a73f1f41ebfc335722022ea04c79f6e02ab3179ecc9a66e037dd7a106572b4924
@@ -0,0 +1,132 @@
+/* mpihelp_udiv_w_sdiv -- implement udiv_qrnnd on machines with only signed
+ * division.
+ * Copyright (C) 1992, 1994, 1996, 1998 Free Software Foundation, Inc.
+ * Contributed by Peter L. Montgomery.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include "mpi-internal.h"
+#include "longlong.h"
+
+
+#if 0 /* not yet ported to MPI */
+
+mpi_limb_t
+mpihelp_udiv_w_sdiv( mpi_limp_t *rp,
+ mpi_limp_t *a1,
+ mpi_limp_t *a0,
+ mpi_limp_t *d )
+{
+ mp_limb_t q, r;
+ mp_limb_t c0, c1, b1;
+
+ if ((mpi_limb_signed_t) d >= 0)
+ {
+ if (a1 < d - a1 - (a0 >> (BITS_PER_MP_LIMB - 1)))
+ {
+ /* dividend, divisor, and quotient are nonnegative */
+ sdiv_qrnnd (q, r, a1, a0, d);
+ }
+ else
+ {
+ /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
+ sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (BITS_PER_MP_LIMB - 1));
+ /* Divide (c1*2^32 + c0) by d */
+ sdiv_qrnnd (q, r, c1, c0, d);
+ /* Add 2^31 to quotient */
+ q += (mp_limb_t) 1 << (BITS_PER_MP_LIMB - 1);
+ }
+ }
+ else
+ {
+ b1 = d >> 1; /* d/2, between 2^30 and 2^31 - 1 */
+ c1 = a1 >> 1; /* A/2 */
+ c0 = (a1 << (BITS_PER_MP_LIMB - 1)) + (a0 >> 1);
+
+ if (a1 < b1) /* A < 2^32*b1, so A/2 < 2^31*b1 */
+ {
+ sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
+
+ r = 2*r + (a0 & 1); /* Remainder from A/(2*b1) */
+ if ((d & 1) != 0)
+ {
+ if (r >= q)
+ r = r - q;
+ else if (q - r <= d)
+ {
+ r = r - q + d;
+ q--;
+ }
+ else
+ {
+ r = r - q + 2*d;
+ q -= 2;
+ }
+ }
+ }
+ else if (c1 < b1) /* So 2^31 <= (A/2)/b1 < 2^32 */
+ {
+ c1 = (b1 - 1) - c1;
+ c0 = ~c0; /* logical NOT */
+
+ sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
+
+ q = ~q; /* (A/2)/b1 */
+ r = (b1 - 1) - r;
+
+ r = 2*r + (a0 & 1); /* A/(2*b1) */
+
+ if ((d & 1) != 0)
+ {
+ if (r >= q)
+ r = r - q;
+ else if (q - r <= d)
+ {
+ r = r - q + d;
+ q--;
+ }
+ else
+ {
+ r = r - q + 2*d;
+ q -= 2;
+ }
+ }
+ }
+ else /* Implies c1 = b1 */
+ { /* Hence a1 = d - 1 = 2*b1 - 1 */
+ if (a0 >= -d)
+ {
+ q = -1;
+ r = a0 + d;
+ }
+ else
+ {
+ q = -2;
+ r = a0 + 2*d;
+ }
+ }
+ }
+
+ *rp = r;
+ return q;
+}
+
+#endif
+