Repository: kudelskisecurity/cdf Branch: master Commit: 29a75421d9ed Files: 68 Total size: 257.2 KB Directory structure: gitextract_d955lojs/ ├── .gitignore ├── LICENSE ├── README.md ├── cdf-lib/ │ ├── dsa.go │ ├── dsa_test.go │ ├── dudect.go │ ├── ecdsa.go │ ├── ecdsa_test.go │ ├── enc.go │ ├── enc_test.go │ ├── prf.go │ ├── rsaenc.go │ ├── rsasign.go │ ├── termview.go │ ├── utils.go │ ├── utils_test.go │ └── xof.go ├── config.json ├── config.json.enc ├── config.json.oaep ├── config.json.prf ├── examples/ │ ├── .gitignore │ ├── blake2new.py │ ├── blake2ref.py │ ├── dsa_sha256_cryptopp.cpp │ ├── dsa_sha256_go.go │ ├── dsa_sha256_java.java │ ├── dsa_sha256_java_wrapper.go │ ├── dsa_sha256_openssl.c │ ├── dsa_sha256_pycrypto.py │ ├── ecdsa_p256_sha256_cryptography.py │ ├── ecdsa_p256_sha256_cryptopp.cpp │ ├── ecdsa_p256_sha256_go.go │ ├── ecdsa_p256_sha256_java.java │ ├── ecdsa_p256_sha256_java_wrapper.go │ ├── ecdsa_p256_sha256_mbedtls.c │ ├── ecdsa_p256_sha256_openssl.c │ ├── enc_aes128ctr_go-flawed.go │ ├── enc_aes128ctr_go.go │ ├── enc_aes128ctr_openssl.c │ ├── enc_aes128ctr_pycrypto.py │ ├── hash_blake2s_new.py │ ├── hash_blake2s_ref.py │ ├── hash_md5_go.go │ ├── hash_md5_hashlib.py │ ├── hash_md5_openssl.c │ ├── hash_sha256_crypto.io.py │ ├── hash_sha256_go.go │ ├── hash_sha256_hashlib.py │ ├── hash_sha256_openssl.c │ ├── hash_sha512_hashlib.py │ ├── oaep_rsa2048_cryptography.py │ ├── oaep_rsa2048_cryptopp.cpp │ ├── oaep_rsa2048_go-flawed.go │ ├── oaep_rsa2048_go.go │ ├── oaep_rsa2048_java.java │ ├── oaep_rsa2048_java_wrapper.go │ ├── oaep_rsa2048_mbedtls.c │ ├── oaep_rsa2048_openssl.c │ ├── oaep_rsa2048_pycrypto.py │ ├── pkcs_rsa2048_go.go │ ├── pkcs_rsa2048_pycrypto.py │ ├── pkcssign_rsa_go.go │ ├── prf_hmacsha256_go.go │ ├── prf_hmacsha256_hmac.py │ └── prf_hmacsha256_openssl.c ├── main.go └── makefile ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Vim *.swp # Latoex files *.pdf *.aux *.bib *.bbl *.blg *.ent *.log *.run.xml *.synctex.gz # Object files cdf tags *.o *.ko *.obj *.elf # Precompiled Headers *.gch *.pch # Libraries *.lib *.a *.la *.lo # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib # Executables *.exe *.out *.app *.i*86 *.x86_64 *.hex # Debug files *.dSYM/ *.pyc *__pycache__ # Log files log.txt ================================================ FILE: LICENSE ================================================ 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. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 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: {project} Copyright (C) {year} {fullname} 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 . ================================================ FILE: README.md ================================================ # CDF – crypto differential fuzzing CDF is a tool to automatically test the correctness and security of cryptographic software. CDF can detect implementation errors, compliance failures, side-channel leaks, and so on. CDF implements a combination of unit tests with "differential fuzzing", an approach that compares the behavior of different implementations of the same primitives when fed edge cases and values maximizing the code coverage. Unlike general-purpose fuzzers and testing software, CDF is: * **Smart**: CDF knows what kind of algorithm it's testing and adapts to the tested functions * **Fast**: CDF tests only what needs to be tested and parallelizes its tests as much as possible * **Polyvalent**: CDF isn't specific to any language or API, but supports arbitrary executable programs or scripts * **Portable**: CDF will run on any Unix or Windows platform, since it is written in Go without any platform-specific dependency The purpose of CDF is to provide more efficient testing tool to developers and security researchers, being more effective than test vectors and cheaper than manual audit of formal verification. CDF was first presented at Black Hat USA 2017. You can view the [slides](https://www.blackhat.com/docs/us-17/wednesday/us-17-Aumasson-Automated-Testing-Of-Crypto-Software-Using-Differential-Fuzzing.pdf) of our presentation, which contain general information about the rationale behind and the design of CDF. # Requirements CDF is coded in [Go](https://golang.org/), the current version has been developed using Go 1.8. It has no dependencies outside of Go's [standard library](https://golang.org/pkg/#stdlib). However, we provide example programs to be tested using CDF, which are in C, Python, C++, Java and Go and require specific crypto libraries to be run. Currently required libraries are: - [CryptoPP](https://www.cryptopp.com/) - [OpenSSL](https://www.openssl.org/) - [BouncyCastle](https://www.bouncycastle.org/) - [PyCrypto](https://launchpad.net/pycrypto/) - [Cryptography.io](https://cryptography.io/) # Build `make` will build the `cdf` binary. A bunch of example programs are available under [example](examples/): `make examples-all` will build all the examples, while `make examples-go` will only build the Go examples. `make test` will run unit tests (of CDF). # Usage For starters you may want to view usage info by running `cdf -h`. You may then try an example such as the [`rsaenc`](#rsaenc-rsa-encryption-oaep-or-pkcs-15) interface against the RSA OAEP Go and CryptoPP examples. Viewing CryptoPP as our reference, you can test the Go implementation by doing: ``` cdf rsaenc /examples/oaep_rsa2048_go /examples/oaep_rsa2048_cryptopp ``` This command will perform various tests specific to the `rsaenc` interface. In this example, CDF should complain about the maximum public exponent size the Go implementation support: if we check [its code](https://golang.org/src/crypto/rsa/rsa.go#L42) we can see the public exponent is being stored as a normal integer, whereas in CryptoPP (and most other implementations), it is stored as a big integer. This is however [by design](https://www.imperialviolet.org/2012/03/16/rsae.html) and will likely not be changed. Parameters are defined in [config.json](config.json). Most parameters are self-explanatory. You may want to set others private keys for `rsaenc` and `ecdsa` (these interfaces are tested with fixed keys, although some key parameters, such as the exponents, are changed in some of the tests). The `seed` parameter lets you change the seed used in CDF's pseudo-random generators. (Yet, the tested program may be using some PRNG seeded otherwise, like the OAEP examples.) The `concurrency` parameter lets you set the number of concurrent goroutine CDF should be spawning when forking the programs. Note that it is best to keep this number below the real number of cores. The `verboseLog` parameter, if set to `true`, will write all programs' inputs and outputs, even for the succesful tests, to a file log.txt. # Interfaces In order to test your software using CDF, you have to create a program that reads input and writes output in conformance with CDF interfaces, and that internally calls the tested program. CDF interfaces are abstractions of a crypto functionality, in order to allow black-box testing of arbitrary implementations. For example, if you implemented the ECDSA signature scheme, your program should satisfies the [`ecdsa` interface](#ecdsa-ecdsa-signatures) and as such take as inputs 4 or 5 arguments, respectively in order to sign a message or verify a signature. These arguments are the public X coordinate, the public Y coordinate, the private D big integer and the message you want to sign and then it should output only the big integers R and S each on a newline. Or, to verify a message, it should accept X,Y, the R, the S and the message and then it should only output True or False. The interfaces' specifications are detailled [below](#interfaces). Our [examples](#examples) of interface implementations will help you create your owns. Error handling is left to the tested program, however to have meaningful errors in CDF it is best to exit on failure, return a error code and print an error message. The interface program can be written in any language, it just needs to be an executable file conformant with a CDF interface. An interface program is typically written in the same language as the tested program, but that's not mandatory (it may be a wrapper in another language, for example for Java programs). CDF currently supports the following interfaces, wherein parameters are encoded as hexadecimal ASCII strings, unless described otherwise: ## dsa The dsa interface tests implementations of the [Digital Signature Algorithm](https://en.wikipedia.org/wiki/Digital_Signature_Algorithm) (DSA). It must support the signature and verification operations: |Operation |Input |Output | |-------------|---------------|---------------| |Signature |`p q g y x m` | `r s` | |Verification |`p q g y r s m`| `truth value` | Here p, q, g are DSA parameters, y is a public key, x is a private key, m is a message, r and s form the signature, which must returned separated by a newline. The truth value, either “true” or “false”, is represented as a string. The dsa interface supports an optional test: the`-h` allows to bypass the hashing process and directly provide the hash value to be signed. This allows CDF to perform more tests, such as checking for overflows or hash truncation. ## ecdsa The ecdsa interface tests implementations of the [Elliptic Curve Digital Signature Algorithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) (ECDSA). It must support the signature and verification operations: |Operation |Input |Output| |-------------|---------------|---------------| |Signature |`x y d m` | `r s` | |Verification |`x y r s m` | `truth value` | Here x and y are a public ECDSA key coordinates, d is a private key, m is a message, and r and s form the signature, which must be returned separated by a newline. The truth value, either “true” or “false”, is represented by a string. The flag `-h` serves the same purpose as with dsa. Please note that our current design assumes a fixed curve, defined in the tested program. To obtain reproducible results with those tests and leverage all of CDF detection's abilities, you have to either seed you random generator with a fixed seed or use a deterministic ECDSA variant, otherwise CDF can't detect problems such as same tags issues automatically. ## enc The enc interface tests symmetric encryption and decryption operations, typically when performed with a block cipher (stream ciphers can be tested with the prf interface). It must support encryption and decryption: |Operation|Input |Output| |-------------|---------------|---------------| |Encryption |`k m` | `c` | |Decryption |`k c` | `r` | Here k is a key, m is a message, c is a ciphertext c and r is a recovered plaintext. ## prf The prf interface tests keyed hashing (pseudorandom functions, MACs), as well as stream ciphers: |Operation|Input |Output| |-------------|---------------|---------------| |Computation |`k m` | `h` | Here k is a key, m is a message (or nonce in case of a stream cipher), and h is the result of the PRF computation. Our interface assumes fixed key size and variable input lengths. If a specific key is to be specified, it is the responsibility of the tested program to ignore the key input or the xof interface may be a better choice. ## rsaenc The rsaenc tests [RSA](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) encryption and decryption, both [OAEP](https://en.wikipedia.org/wiki/Optimal_asymmetric_encryption_padding) (PKCS 2.1) and PKCS 1.5: |Operation|Input |Output| |-------------|---------------|---------------| |Encryption |`n e m` | `c` | |Decryption |`p q e d c` | `r` | Here n is a modulus, e is a public exponent (for compatibility with certain libraries, e is also needed for decryption), m is a message m, p and q are n's factor (such that p > q, since libraries commonly require it), d is a private exponent, and r is a recovered plaintext. ## xof The xof interface tests hash functions, extendable-output functions (XOFs), deterministic random bit generators (DRBGs): |Operation|Input |Output| |-------------|---------------|---------------| |Computation |`m` | `h` | Here m is the message and h is the result h. # Authors CDF is based on initial ideas by [JP Aumasson](https://github.com/veorq), first disclosed at [WarCon 2016](http://warcon.pl/2016/), and most of the code was written by [Yolan Romailler](https://github.com/anomalroil). # Intellectual property CDF is copyright (c) 2016-2017 Nagravision SA, all rights reserved. CDF is released under GPLv3. ================================================ FILE: cdf-lib/dsa.go ================================================ package cdf import ( "errors" "fmt" "log" "math/rand" "strconv" "strings" "sync" "time" ) // TestDsa implements the tests relying on the cdf interface for DSA signature and verification scheme func TestDsa() error { LogInfo.Print("testing dsa") failed := false // Testing Message length if err := testDsaMsgLen(); err != nil { failed = true LogError.Println("while testing messages lengths:", err) } else { LogSuccess.Println("message lengths tested without error.") } if *TestHashes { // test only if the -h flag is supported if err := testDsaHashLen(); err != nil { failed = true LogError.Println("while testing hash lengths:", err) } else { LogSuccess.Println("hash lengths tested without error.") } } // Testing special cases if err := testDsaCases(); err != nil { failed = true LogError.Println("while testing special cases:", err) } else { LogSuccess.Println("special cases tested without error.") } if limit := *TestTimings; limit > 0 { dudectTest(limit, Prog1, doOneComputationForDsa, prepareInputsForDsa) dudectTest(limit, Prog2, doOneComputationForDsa, prepareInputsForDsa) } if failed { fmt.Print("\n") return errors.New("one of more tests failed") } return nil } // testDsaMsgLen is simply calling the testDsaConsistency function on // the full range from MinMsgLen to MaxMsgLen, on a randomly generated message // (relying on the seed set in Config.json) func testDsaMsgLen() (mainErr error) { TermPrepareFor(1) // generate random chars in the hex range to try and sign those msg := randomHex(Config.MaxMsgLen) LogInfo.Println("testing different message's lengths, from ", Config.MinMsgLen, "to", Config.MaxMsgLen, "bytes") argsP1 := []string{Config.DsaP, Config.DsaQ, Config.DsaG, Config.DsaY, Config.DsaX} argsP2 := []string{Config.DsaP, Config.DsaQ, Config.DsaG, Config.DsaY} mainErr = testDsaConsistency(msg, argsP1, argsP2, 0) return } // testDsaHashLen attempt to test the Dsa process using different hash // lengths, notably bigger hash than the group size. This test will be more // useful in the deterministic Dsa case, since we can compare its output against // the other one to catch no-same tags cases (i.e hash lengths' handling problems // leading to wrong truncation of the hash, typically) func testDsaHashLen() error { TermPrepareFor(1) var mainErr MultiError hasSame := false msg := randomHex(Config.MaxMsgLen) LogInfo.Println("testing different hash's lengths over ") toTest := make(map[string]int) TermPrepareFor(3) // we should add a setting maybe to have the hash range to test? for i := 1; i < Config.MaxMsgLen; i++ { id := "dsa#buf#" + strconv.Itoa(i) TermDisplay(3, "%d / %d \n", i+1, Config.MaxMsgLen) argsP2 := []string{"-h", msg[:i*2], Config.DsaP, Config.DsaQ, Config.DsaG, Config.DsaY} argsP1 := append(argsP2, Config.DsaX) if err := testDsaConsistency(msg, argsP1, argsP2, 1); err != nil { mainErr = append(mainErr, err) continue } out, err := runProg(Prog1, id, append(argsP1, msg)) if err != nil { mainErr = append(mainErr, err) continue } // Then we check if the tag is the same as a previous one, since it // should never be the case. // Note that this is more useful in the deterministic DSA case than // in general. if toTest[out] > 0 { hasSame = true mainErr = append(mainErr, fmt.Errorf("Same tag as with buff %d with len %d on job %s. ", toTest[out], i, id)) } toTest[out] = i } if len(mainErr) > 0 { if hasSame { mainErr = append(mainErr, fmt.Errorf("Note that same tags are expected if you are using DSA deterministic as per RFC6979. If you are not, then this is a problem.")) } return mainErr } return nil } // testDsaConsistency just tests the DSA signature on different message // lengths for the given msg, starting from MinMsgLen and for at most maxIter // iterations or reaches the value MaxMsgLen set in the Config.json file func testDsaConsistency(msg string, argsP1, argsP2 []string, maxIter int) error { LogInfo.Println("testing dsa consistency") nbIter := maxIter + Config.MinMsgLen if nbIter >= Config.MaxMsgLen || maxIter <= 0 { nbIter = Config.MaxMsgLen + 1 } if len(msg) < nbIter { log.Fatalln("The message provided is not big enough to be processed") } // Initializing a common, unbuffered, channel which gives tasks to // the worker goroutines. msgs := make(chan string) errs := make(chan error, nbIter) // Spawn some worker goroutines var wg sync.WaitGroup for j := uint(0); j < Config.Concurrency; j++ { wg.Add(1) go func() { for m := range msgs { id := "dsa#" + strconv.Itoa(len(m)) // We cannot use argsP1, we have to create a copy, // to keep argsP1 unchanged argsP1T := append(argsP1, m) // We run the first program: out1 := runOrExitOnErr(Prog1, id, argsP1T...) out1Arr := strings.Split(out1, "\n") // it is necessary to trim again after splitting to remove the CR rOut := strings.TrimSpace(out1Arr[0]) sOut := strings.TrimSpace(out1Arr[1]) argsP2T := append(argsP2, rOut, sOut, m) // we run the second program: outStr2 := runOrExitOnErr(Prog2, id, argsP2T...) if trueStr != outStr2 { fmt.Print("\n") LogWarning.Printf("verification failed on length %d", len(m)) fmt.Print("\n") LogError.Println(strings.Join(append( []string{"failed to run on length ", strconv.Itoa(len(m)), " ", Prog2}, argsP2T...), " ")) LogError.Println(append([]string{"After running:", Prog1}, argsP1T...)) fmt.Print("\n\n") errs <- fmt.Errorf("verification error on length %d", len(m)) } } wg.Done() }() } // There we could argue that the MinMsgLen should always be 1 byte. // We ignore the Config.MsgIncrement since we are testing each byte-length for i := Config.MinMsgLen; i < nbIter; i++ { TermPrintInline(1, "%d / %d", i-Config.MinMsgLen+1, nbIter-Config.MinMsgLen) // we populate our channel: msgs <- msg[:i*2] } close(msgs) // let us wait for our workers to finish wg.Wait() if len(errs) > 0 { // Initializing the return value var mainErr MultiError firstErr := true for len(errs) > 0 { e := <-errs if firstErr { firstErr = false // This is not guaranteed to be the 1st one, but almost LogInfo.Println("First error:", e) } mainErr = append(mainErr, e) } TermPrepareFor(1) return mainErr } TermPrepareFor(1) return nil } // testDSACases is responsible for running the different tests for edge cases // for DSA. We currently test against 0 inputs, against 1 inputs and other // degenerated cases. Note that this function is simply a bundle of functions // which could have been directly added to the main TestDsa one. func testDsaCases() error { TermPrepareFor(1) var mainErr MultiError // firstly we'll test both program against the 0 values if err := testDsaZeros(Prog1); err != nil { //LogWarning.Println(err) mainErr = append(mainErr, err) } if err := testDsaZeros(Prog2); err != nil { //LogWarning.Println(err) mainErr = append(mainErr, err) } TermPrepareFor(1) if err := testDsaOnes(Prog1); err != nil { mainErr = append(mainErr, err) } if err := testDsaOnes(Prog2); err != nil { mainErr = append(mainErr, err) } TermPrepareFor(1) // next, we test the verification against the (0, s) and the (r, 0) signatures if err := testDsaZeroSign(Prog1); err != nil { mainErr = append(mainErr, err) } if err := testDsaZeroSign(Prog2); err != nil { mainErr = append(mainErr, err) } TermPrepareFor(1) if err := testDsaZeroHash(Prog1); err != nil { mainErr = append(mainErr, err) } if err := testDsaZeroHash(Prog2); err != nil { mainErr = append(mainErr, err) } TermPrepareFor(1) if len(mainErr) > 0 { return mainErr } return nil } // testDsaOnes is a test to sign using the 01 values as a public parameters // as well as the 01 integer as a private key. This should not be accepted // by the tested programs, since it means they do not perform correct domain // parameters checks on their input. Typically it can lead to signature // independent of the actual message, with r=01. func testDsaOnes(prog string) error { LogInfo.Printf("testing %s against the 01 parameters.\n", prog) var mainErr MultiError // we take the MinMsgLen since we don't need a big value, we just need any value msg := randomHex(Config.MinMsgLen) argsP := []string{Config.DsaP, Config.DsaQ, Config.DsaG, Config.DsaY, Config.DsaX, msg} var tmp string for i := 0; i < 3; i++ { id := "dsa#pts#01-" + fmt.Sprint(i) + "_" + prog tmp, argsP[i] = argsP[i], "01" out, err := runProg(prog, id, argsP) argsP[i] = tmp if err != nil { if strings.Contains(err.Error(), "STOP") { mainErr = append(mainErr, err) LogWarning.Println(prog, "timed out using 01 as argument ", i+1, "it may indicate an infinite loop.") } else { LogToFile.Println("As expected,", id, "failed:", out, "\nGot error:", err) LogSuccess.Println(prog, "refused to sign using 01 at arg ", i+1) } continue } LogWarning.Println(prog, "signed using 01 without error at ", i+1) mainErr = append(mainErr, fmt.Errorf("%s let us sign using 01, without error at %d:\n%s", prog, i+1, out)) } if len(mainErr) > 0 { return mainErr } return nil } // testDsaZeros is a simple trial to sign using the 0 values as a public key as well // well as the 00 integer as a private key. This can lead to infinite loops, which // would then trigger the timeout in runProg. This means that the tested program // does not perform proper parameters checks on its inputs. func testDsaZeros(prog string) error { LogInfo.Printf("testing %s against the 00 parameters.\n", prog) var mainErr MultiError // we take the MinMsgLen since we don't need a big value, we just need any value msg := randomHex(Config.MinMsgLen) argsP := []string{Config.DsaP, Config.DsaQ, Config.DsaG, Config.DsaY, Config.DsaX, msg} var tmp string for i := 0; i < 5; i++ { id := "dsa#pts#0-" + fmt.Sprint(i) + "_" + prog if i == 3 { // we don't care about Y when testing the signature process i++ } tmp, argsP[i] = argsP[i], "00" out, err := runProg(prog, id, argsP) argsP[i] = tmp if err != nil { if strings.Contains(err.Error(), "STOP") { mainErr = append(mainErr, err) LogWarning.Println(prog, " timed out using 00 as argument ", i+1, "it may indicate an infinite loop.") } else { LogToFile.Println("As expected,", id, "failed:", out, "\nGot error:", err) LogSuccess.Println(prog, " refused to sign using 00 at arg ", i+1) } continue } LogWarning.Println(prog, " signed using 00 without error at ", i+1) mainErr = append(mainErr, fmt.Errorf("%s let us sign using 00, without error at %d", prog, i+1)) } if len(mainErr) > 0 { return mainErr } return nil } // pair is simply a struct to allow to write the following test in a nicer way. type pair struct { a string b string } // testDsaZeroSign is a test to verify invalid signatures, typically the 00 // 01 and q values should be rejected as not in the proper range for r and s. // Failure to do so can lead to always true signatures, independently of the // message, which is a security concern if it is easily triggered. func testDsaZeroSign(prog string) error { LogInfo.Printf("testing %s against the null signatures.\n", prog) id := "dsa#rs#0-0_" + prog argsP := []string{Config.DsaP, Config.DsaQ, Config.DsaG, Config.DsaY, "00", "00", "434343"} list := []pair{pair{"00", "00"}, pair{"01", "00"}, pair{"00", "01"}, pair{"01", Config.DsaQ}} // This may trigger a faulty true answer for _, p := range list { argsP[4] = p.a argsP[5] = p.b out, err := runProg(prog, id, argsP) if err != nil { LogToFile.Println("As expected, ", id, "failed:", out, "\nGot error:", err) LogSuccess.Println(prog, "rejected r=", p.a, ", s=", p.b, " with an error.") continue } if out == "true" { return fmt.Errorf("%s validated a 0 signature", prog) } LogInfo.Println(prog, "rejected r=", p.a, ", s=", p.b, " without error.") } return nil } // testDsaZeroHash is a simple trial to verify using a wrong 00 hash and // using 01 as x, r and s to fool the standard DSA verification into validation // Note that the point (0,0) note that this should never validate, it's not even // on the curve in most possible cases (the y coordinate being free, it may be). func testDsaZeroHash(prog string) error { LogInfo.Printf("testing %s against the 00 hash.\n", prog) // The point 0,0 shouldn't be accepted as a valid point, so let us try with it: id := "dsa#hash#00_" + prog argsP := []string{"-h", "00", "01", "42", "01", "01", "434343"} out, err := runProg(prog, id, argsP) if err != nil { LogToFile.Println("As expected,", id, "failed:", out, "\nGot error:", err) LogSuccess.Println(prog, "didn't accept this degenerated case, or you did not implement the -h flag.") return nil } if out == trueStr { LogError.Println(prog, "accepted the degenerated -h 00 case.") return fmt.Errorf("%s accepted the degenerated -h 00 case", prog) } return fmt.Errorf("%s refused the degenerated -h 00 case without error", prog) } // doOneComputationForDsa allows to use the dudect test with this interface. func doOneComputationForDsa(prog string) func(string) { return func(data string) { recovered, err := runProg(prog, "dudect-"+prog, []string{Config.DsaP, Config.DsaQ, Config.DsaG, Config.DsaY, Config.DsaX, data}) if err != nil { panic(fmt.Errorf("Error:%v \n leading to: %s", err, recovered)) } } } // prepareInputsForDsa generates inputs to test timings leak, for DSA this test // simply test two message against each other and could benefit from more interesting. func prepareInputsForDsa() (inputData []string, classes []int) { inputData = make([]string, numberMeasurements) classes = make([]int, numberMeasurements) rn := rand.New(rand.NewSource(time.Now().UnixNano())) // we generate two different message and we simply try with them: data := randomHex(20) data2 := randomHex(20) for i := 0; i < numberMeasurements; i++ { classes[i] = rn.Intn(2) if classes[i] == 0 { inputData[i] = data } else { inputData[i] = data2 } } return } ================================================ FILE: cdf-lib/dsa_test.go ================================================ package cdf import ( "crypto/dsa" "crypto/rand" "crypto/sha256" "encoding/hex" "fmt" "hash" "log" "math/big" "os" "strings" "testing" ) func TestTestDSA(t *testing.T) { initForTesting("DSA") Config.Timeout = 1 t.Run("testDsaMsgLen", func(*testing.T) { err := testDsaMsgLen() if err != nil { t.Error("Expected nil, got ", err) } }) t.Run("testDsaCases", func(*testing.T) { err := testDsaCases() // as of Go 1.7.4, the DSA function had two bugs we detect: /*expErr := MultiError{fmt.Errorf(" accepts 00 input for the keys"), fmt.Errorf(" accepts 00 input for the keys")} and it signs using 1 as a generator too.*/ if err == nil { t.Fatalf("The testDsaCases returned without error! We expect it to fail as of Go version 1.8.") } // as of Go 1.8, it does not fall in an infinite loop anymore since they corrected the bug we reported. if !strings.Contains(err.Error(), "(2 errors)") && strings.Count(err.Error(), "0000000000000000000000000000000000000001") == 2 { t.Errorf("Expected 2 signatures with r=01, got\n%v", err) } }) if execCounter != 28 { t.Error("Expected 28 executions, got ", execCounter) } } func ExampleDSA(args []string) { // The hash used var h hash.Hash h = sha256.New() var signing bool args = args[1:] for a := range args { if len(args[a])%2 != 0 { log.Println("one argument has an odd size") os.Exit(2) } } switch { case len(args) == 7: signing = false case len(args) == 6: signing = true default: log.Fatal("Please provide P, Q, G, Y, X, Msg or P, Q, G, Y, R, S, Msg as arguments in order to respectively sign Msg or verify a signature for Msg.") } // Key instanciation privatekey := new(dsa.PrivateKey) pubkey := new(dsa.PublicKey) pubkey.P = fromBase16(args[0]) pubkey.Q = fromBase16(args[1]) pubkey.G = fromBase16(args[2]) pubkey.Y = fromBase16(args[3]) // we need the byte length of the subgroup to comply to FIPS 186-3 sec. 4.6 // recommended truncation. hlen := (pubkey.Q.BitLen() + 7) / 8 // msg is always in latest position // we are decoding from hex to have truly random messages msg, err := hex.DecodeString(args[(len(args) - 1)]) if err != nil { panic(err) } r := big.NewInt(0) s := big.NewInt(0) // We handle the hashing of the data: h.Write(msg) var signhash []byte signhash = h.Sum(nil) if signing { // private key instanciation: privatekey.PublicKey = *pubkey privatekey.X = fromBase16(args[4]) // If signhash is longer than the byte-length of the subgroup, it should // be truncated to that length as per FIPS 186-3 sec. 4.6, but Sign does // not handle this directly. It returns the signature as a pair of big integers. r, s, serr := dsa.Sign(rand.Reader, privatekey, signhash[:hlen]) if serr != nil { fmt.Println(serr) os.Exit(1) } // We first output R, then S with a newline in between as required by // the ECDSA interface answerR := leftPadText(r.Text(16), 20) answerS := leftPadText(s.Text(16), 20) fmt.Printf("%s\n%s\n", answerR, answerS) } else { // if we are not signing, we are verifying : r = fromBase16(args[4]) s = fromBase16(args[5]) verifystatus := dsa.Verify(pubkey, signhash[:hlen], r, s) fmt.Println(verifystatus) } } // leftPadText will ensure the string are in hexadecimal form and satisfy with the // DSA signature length of 160bits. func leftPadText(text string, size int) string { n := len(text) size = 2 * size if n > size { n = size } return strings.Repeat("0", size-n) + text } ================================================ FILE: cdf-lib/dudect.go ================================================ // All credit goes to Oscar Reparaz, Josep Balasch and Ingrid Verbauwhede for dudect's ideas and design package cdf import ( "fmt" "log" "math" "time" ) type tCtx struct { mean [2]float64 m2 [2]float64 n [2]float64 } var ( numberMeasurements = 3000 enoughMeasurements = float64(3000) // may be handled by the Go benchmark package later ) const tThresholdBananas = 500 // test failed, with overwhelming probability const tThresholdModerate = 5 // here we could also take 4.5 e.g. const numberPercentiles = 100 const numberTests = 1 + numberPercentiles + 1 // we perform 1 var dudectStop bool var enough int var percentiles [numberPercentiles]int64 var tests [numberTests]tCtx // preparePercentiles computes the percentiles to use for the tests later func preparePercentiles(ticks []int64) { for i := 0; i < numberPercentiles; i++ { percentiles[i] = percentile( ticks, 1-(math.Pow(0.5, float64(10*(i+1))/float64(numberPercentiles)))) } } // measure times the execution of the provided doOneComputation on the // provided inputDatas func measure(inputDatas []string, doOneComputation func(string)) (execTimes []int64) { ticks := make([]int64, numberMeasurements+1) for i := 0; i < numberMeasurements; i++ { ticks[i] = time.Now().UnixNano() doOneComputation(inputDatas[i]) } ticks[numberMeasurements] = time.Now().UnixNano() execTimes = make([]int64, numberMeasurements) for i := 0; i < numberMeasurements; i++ { execTimes[i] = ticks[i+1] - ticks[i] } return } // updateStatistics will udpate each t-test we are storing, ie. the test on // all data, the tests on each percentiles, and the second order test. func updateStatistics(execTimes []int64, classes []int) { for i := 0; i < numberMeasurements; i++ { difference := execTimes[i] if difference < 0 { continue // the cpu cycle counter overflowed } // do a t-test on the execution time tPush(&tests[0], float64(difference), classes[i]) // do a t-test on cropped execution times, for several cropping thresholds. for cropIndex := 0; cropIndex < numberPercentiles; cropIndex++ { if difference < percentiles[cropIndex] { tPush(&tests[cropIndex+1], float64(difference), classes[i]) } } // do a second-order test (only if we have more than 10000 measurements). // Centered product pre-processing. if tests[0].n[0] > 10000 { centered := float64(difference) - tests[0].mean[classes[i]] tPush(&tests[1+numberPercentiles], centered*centered, classes[i]) } } } // tPush will add the value x to the t context in the provided class and update // its context values func tPush(ctx *tCtx, x float64, class int) { if !(class == 0 || class == 1) { log.Fatalln("Error, wrong class in tPush") } ctx.n[class]++ // Welford method for computing online variance // in a numerically stable way. // see Knuth Vol 2 var delta float64 delta = x - ctx.mean[class] // so we have a/n +(x-a/n)/(n+1) = ((n+1)a + nx-a)/(n(n+1)) = (a+x)/(n+1) ctx.mean[class] += delta / ctx.n[class] ctx.m2[class] += delta * (x - ctx.mean[class]) // the algorithm is finalized in tCompute } // tCompute performs the computation to give the t-value used by our t-test func tCompute(ctx *tCtx) float64 { vars := [2]float64{0.0, 0.0} var den, tValue, num float64 // we divide by n-1 since to finalize the variance computation. vars[0] = ctx.m2[0] / (ctx.n[0] - 1) vars[1] = ctx.m2[1] / (ctx.n[1] - 1) num = (ctx.mean[0] - ctx.mean[1]) den = math.Sqrt(vars[0]/ctx.n[0] + vars[1]/ctx.n[1]) tValue = num / den return tValue } // maxTest returns the index of the test with the greateast t-value func maxTest() int { ret := 0 var max float64 max = 0.0 for i := 0; i < numberTests; i++ { if tests[i].n[0] > enoughMeasurements { var x float64 x = math.Abs(tCompute(&tests[i])) if max < x { max = x ret = i } } } return ret } // report is in charge of printing the data related to the dudect test. func report() string { var res string mt := maxTest() maxT := math.Abs(tCompute(&tests[mt])) numberTracesMaxT := tests[mt].n[0] + tests[mt].n[1] maxTau := maxT / math.Sqrt(numberTracesMaxT) if numberTracesMaxT < enoughMeasurements { return fmt.Sprintf("not enough measurements (%.0f still to go).\n", enoughMeasurements-numberTracesMaxT) } /* * maxT: the t statistic value * maxTau: a t value normalized by sqrt(number of measurements). * this way we can compare maxTau taken with different * number of measurements. This is sort of "distance * between distributions", independent of number of * measurements. * (5/tau)^2: how many measurements we would need to barely * detect the leak, if present. "barely detect the * leak" = have a t value greater than 5. */ res = fmt.Sprintf("meas: %7.2f M, max t(%d): %+7.2f, max tau: %.2e, (5/tau)^2: %.2e. m.time (ms):%7.2f", (numberTracesMaxT / 1e6), mt, maxT, maxTau, float64(5*5)/(maxTau*maxTau), tests[0].mean[0]/float64(1e6)) if maxT > tThresholdBananas { LogWarning.Printf(" Definitely not constant time.\n") dudectStop = true return res } if maxT > tThresholdModerate { LogWarning.Printf(" Probably not constant time.\n") enough++ if enough > 5 { // let us stop before reaching the limit if we have 5 consecutive hints LogWarning.Printf(" Stopping for now. You may want to investigate this further.\n") dudectStop = true } return res } else { LogInfo.Printf(" For the moment, maybe constant time.\n") enough = 0 return res } } // dudectTest is a function which will allow one to perform a constant time // test on the provided doOneComputation function using the data provided // by prepare_input and which will tell, using a t-test whether it seems to // be timing discrepancies between the two class of inputs or not. func dudectTest(limit int, progName string, doOneComputation func(string) func(string), prepareInputs func() (inputData []string, classes []int)) { LogInfo.Println("dudect constant time test starting for", progName) TermView.Println("Preparing input...") TermPrepareFor(1) var countD int // we need to reset our global variables: dudectStop = false percentiles = [numberPercentiles]int64{} tests = [numberTests]tCtx{} for !dudectStop { countD++ inputData, classes := prepareInputs() execTimes := measure(inputData, doOneComputation(progName)) // on the very first run, let's compute the rough esitmate of the percentiles: if percentiles[numberPercentiles-1] == 0 { preparePercentiles(execTimes) } updateStatistics(execTimes, classes) TermPrintInline(2, "%d / %d : %s", countD, limit, report()) if countD >= limit { dudectStop = true } } TermPrepareFor(2) } ================================================ FILE: cdf-lib/ecdsa.go ================================================ package cdf import ( "errors" "fmt" "log" "strconv" "strings" "sync" ) // TestEcdsa implements the cdf interface for ECDSA signature and verification scheme func TestEcdsa() error { LogInfo.Print("testing ecdsa") failed := false // Testing Message length if err := testEcdsaMsgLen(); err != nil { failed = true LogError.Println("while testing messages lengths:", err) } else { LogSuccess.Println("message lengths tested without error.") } // Testing hash length if *TestHashes { // test only if the -h flag is supported if err := testEcdsaHashLen(); err != nil { failed = true LogError.Println("while testing hash lengths:", err) } else { LogSuccess.Println("hash lengths tested without error.") } } // Testing specific point if err := testEcdsaPoints(); err != nil { failed = true //LogError.Println("while testing specific edge cases:", err) } if failed { fmt.Print("\n") return errors.New("one of more tests failed") } return nil } // testEcdsaMsgLen is simply calling the testEcdsaConsistency function on // the full range from MinMsgLen to MaxMsgLen, on a randomly generated message // (relying on the seed set in Config.json) func testEcdsaMsgLen() (mainErr error) { TermPrepareFor(1) // generate random chars in the hex range to try and sign those msg := randomHex(Config.MaxMsgLen) LogInfo.Println("testing different message's lengths, from ", Config.MinMsgLen, "to", Config.MaxMsgLen, "bytes") argsP1 := []string{Config.EcdsaX, Config.EcdsaY, Config.EcdsaD} argsP2 := []string{Config.EcdsaX, Config.EcdsaY} mainErr = testEcdsaConsistency(msg, argsP1, argsP2, 0) return } // testEcdsaHashLen attempt to test the Ecdsa process using different hash // lengths, notably bigger hash than the group size. This test will be more // useful in the deterministic Ecdsa case, since we can compare its output against // the other one to catch no-same tags cases (i.e hash lengths' handling problems // leading to wrong truncation of the hash, typically) func testEcdsaHashLen() error { var first int TermPrepareFor(1) var mainErr MultiError hasSame := false msg := randomHex(Config.MaxMsgLen) LogInfo.Println("testing different hash's lengths") toTest := make(map[string]int) TermPrepareFor(3) // we should add a setting maybe to have the hash range to test? temp := Config.MinMsgLen for i := 1; i < Config.MaxMsgLen/2; i++ { id := "ecdsa#buf#" + strconv.Itoa(i) TermDisplay(3, "%d / %d \n", i+1, Config.MaxMsgLen/2) Config.MinMsgLen = i * 2 argsP2 := []string{"-h", msg[:i*2], Config.EcdsaX, Config.EcdsaY} argsP1 := append(argsP2, Config.EcdsaD) LogToFile.Println("About to run testEcdsaConsistency for HashLen test") if err := testEcdsaConsistency(msg[:i*2], argsP1, argsP2, 1); err != nil { mainErr = append(mainErr, err) continue } LogToFile.Println("Finished to run testEcdsaConsistency:", mainErr) out, err := runProg(Prog1, id, append(argsP1, msg[:i*2])) if err != nil { mainErr = append(mainErr, err) continue } // Then we check if the tag is the same as a previous one, since it // should never be the case. // Note that this is more useful in the deterministic ECDSA case than // in general. if toTest[out] > 0 { hasSame = true mainErr = append(mainErr, fmt.Errorf("Same tag as with buff %d with len %d on job %s. ", toTest[out], i, id)) if first == 0 { first = i } } toTest[out] = i } Config.MinMsgLen = temp if len(mainErr) > 0 { if hasSame { mainErr = append(mainErr, fmt.Errorf("Note that same tags are expected if you are using ECDSA deterministic as per RFC6979. If you are not, then this is a problem. First problem encountered with size %d", first)) } return mainErr } return nil } // testEcdsaConsistency just tests the ECDSA signature on different message // lengths for the given msg, starting from MinMsgLen and for at most maxIter // iterations or reaches the value MaxMsgLen set in the Config.json file func testEcdsaConsistency(msg string, argsP1, argsP2 []string, maxIter int) (mainErr error) { LogInfo.Println("testing ecdsa consistency") nbIter := maxIter if nbIter+Config.MinMsgLen >= Config.MaxMsgLen || maxIter <= 0 { nbIter = (Config.MaxMsgLen-Config.MinMsgLen)/2 + 1 } if len(msg)/2 < nbIter || len(msg) < Config.MinMsgLen { log.Fatalln("The message provided is not big enough to be processed") } // Initializing a common, unbuffered, channel which gives tasks to // the worker goroutines. msgs := make(chan string) errs := make(chan error, nbIter) // Spawn some worker goroutines var wg sync.WaitGroup for j := uint(0); j < Config.Concurrency; j++ { wg.Add(1) go func() { for m := range msgs { id := "ecdsa#" + strconv.Itoa(len(m)) // We cannot use argsP1, we have to create a copy, // to keep argsP1 unchanged argsP1T := append(argsP1, m) // We run the first program: out1 := runOrExitOnErr(Prog1, id, argsP1T...) out1Arr := strings.Split(out1, "\n") //fmt.Println("\nGot:", out1) // it is necessary to trim again after splitting to remove the CR rOut := strings.TrimSpace(out1Arr[0]) sOut := strings.TrimSpace(out1Arr[1]) argsP2T := append(argsP2, rOut, sOut, m) // we run the second program: outStr2 := runOrExitOnErr(Prog2, id, argsP2T...) if trueStr != outStr2 { fmt.Print("\n") LogWarning.Printf("verification failed on length %d", len(m)) fmt.Print("\n") LogError.Println(strings.Join(append( []string{"failed to run on length ", strconv.Itoa(len(m)), " ", Prog2}, argsP2T...), " ")) LogError.Println(append([]string{"After running:", Prog1}, argsP1T...)) LogWarning.Println(argsP2T[:len(argsP1T)-1]) TermPrepareFor(4) errs <- fmt.Errorf("verification error on job %s and length %d", id, len(m)) } } wg.Done() }() } // There we could argue that the MinMsgLen should always be 1 byte. // We ignore the Config.MsgIncrement since we are testing each byte-length for i := Config.MinMsgLen; i < nbIter*2+Config.MinMsgLen; i += 2 { TermPrintInline(1, "%d / %d", (i-Config.MinMsgLen)/2+1, nbIter) // we populate our channel: msgs <- msg[:i] } close(msgs) // let us wait for our workers to finish wg.Wait() if len(errs) > 0 { // Initializing the return value var mainErr MultiError firstErr := true for len(errs) > 0 { e := <-errs if firstErr { firstErr = false // This is not guaranteed to be the 1st one, but almost LogInfo.Println("First error:", e) } mainErr = append(mainErr, e) } TermPrepareFor(1) return mainErr } TermPrepareFor(1) return nil } func testEcdsaPoints() error { TermPrepareFor(1) var mainErr MultiError // firstly we'll test both program against the 0,0 coordinate: if err := testEcdsaZeroPoint(Prog1); err != nil { //LogWarning.Println(err) mainErr = append(mainErr, fmt.Errorf("%s accepts the (0,0) coordinate and 0 as private integer:\n%v", Prog1, err)) } if err := testEcdsaZeroPoint(Prog2); err != nil { //LogWarning.Println(err) mainErr = append(mainErr, fmt.Errorf("%s accepts the (0,0) coordinate and 0 as private integer:\n%v", Prog2, err)) } TermPrepareFor(1) // next, we test the verification against the 0, s and the r, 0 signatures if err := testEcdsaZeroSign(Prog1); err != nil { mainErr = append(mainErr, err) } if err := testEcdsaZeroSign(Prog2); err != nil { mainErr = append(mainErr, err) } TermPrepareFor(1) if *TestHashes { if err := testEcdsaZeroHash(Prog1); err != nil { mainErr = append(mainErr, err) } if err := testEcdsaZeroHash(Prog2); err != nil { mainErr = append(mainErr, err) } TermPrepareFor(1) if err := testInfiniteLoop(Prog1); err != nil { mainErr = append(mainErr, err) } if err := testInfiniteLoop(Prog2); err != nil { mainErr = append(mainErr, err) } } TermPrepareFor(1) if len(mainErr) > 0 { return mainErr } return nil } // testEcdsaZeroPoint is a simple trial to sign using the 0,0 coordinate as a key // and the 0 integer as a private key. Note that the point (0,0) is never on a curve // in short Weierstrass form with a non-zero b parameter. func testEcdsaZeroPoint(prog string) error { LogInfo.Printf("testing %s against the 0,0 coordinate.\n", prog) // The point 0,0 shouldn't be accepted as a valid point, so let us try with it: id := "ecdsa#pts#0-0_" + prog msg := randomHex(Config.MinMsgLen) argsP := []string{"00", "00", "00", msg} out, err := runProg(prog, id, argsP) if err != nil { LogToFile.Println("As expected,", id, "failed:", out, "\nGot error:", err) LogSuccess.Println(prog, " refused to sign using (0,0) and 0 as private key.") return nil } LogWarning.Println(prog, " signed using (0,0) and 0 as private key without error.") return fmt.Errorf("\tit returned:\n%s,\n\ton message %s", out, msg) } func testEcdsaZeroSign(prog string) error { LogInfo.Printf("testing %s against the null signatures.\n", prog) id := "ecdsa#rs#0-0_" + prog argsP := []string{Config.EcdsaX, Config.EcdsaY, "00", "00", "434343"} list := []string{"00", "01"} for _, a := range list { for _, b := range list { if a == "01" && b == "01" { break } argsP[2] = a argsP[3] = b out, err := runProg(prog, id, argsP) if err != nil { LogToFile.Println("As expected, ", id, "failed:", out, "\nGot error:", err) LogSuccess.Println(prog, "rejected r=", a, ", s=", b, " with an error.") continue } if out == trueStr { return fmt.Errorf("%s validated the invalid signature:\nr=%s,\ns=%s", prog, a, b) } LogInfo.Println(prog, "rejected r=", a, ", s=", b, " without error.") } } return nil } // testEcdsaZeroHash is a simple trial to verify using a wrong 00 hash and // using otherwise valid values as x, y, r and s to fool the standard ECDSA // verification into validation func testEcdsaZeroHash(prog string) error { LogInfo.Printf("testing %s against the 00 hash.\n", prog) // The point 0,0 shouldn't be accepted as a valid point, so let us try with it: id := "ecdsa#hash#00_" + prog argsP := []string{"-h", "00", Config.EcdsaX, Config.EcdsaY, Config.EcdsaX, Config.EcdsaX, "DEADC0DE"} out, err := runProg(prog, id, argsP) if err != nil { LogToFile.Println("As expected,", id, "failed:", out, "\nGot error:", err) LogSuccess.Println(prog, "didn't accept this degenerated case.") return nil } if out == trueStr { LogError.Println(prog, "accepted the degenerated -h 00 case.") return fmt.Errorf("%s accepted the degenerated -h 00 case", prog) } return fmt.Errorf("%s refused the degenerated -h 00 case without error", prog) } // testInfiniteLoop is a simple trial to verify using a wrong 00 hash and // using 00 as secret value that the implementation does not fall into an // infinite loop. Note that 00 is not amongst the range of the acceptable // secret values. func testInfiniteLoop(prog string) error { LogInfo.Printf("testing %s against the invalid inf loop.\n", prog) // The point 0,0 shouldn't be accepted as a valid point, so let us try with it: id := "ecdsa#infloop_" + prog argsP := []string{"-h", "00", Config.EcdsaX, Config.EcdsaY, "00", "DEADC0DE"} out, err := runProg(prog, id, argsP) if err != nil && strings.Contains(err.Error(), "STOP") { LogError.Println(prog, "failed and run into an infinite loop.") return fmt.Errorf("%s runned into a degenerate infinite loop: %v", prog, err) } else if err != nil { LogToFile.Println("As expected,", id, "failed:", out, "\nGot error:", err) LogSuccess.Println(prog, "did not run into an infinite loop.") return nil } LogToFile.Println("Unexpected,", id, "did not fail and output:", out, "\non input:", prog, argsP) LogWarning.Println(prog, "didn't run into an infinite loop, but did not fail when running:\n", prog, argsP) return nil } ================================================ FILE: cdf-lib/ecdsa_test.go ================================================ package cdf import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" "encoding/hex" "flag" "fmt" "hash" "math/big" "strings" "testing" ) func TestTestECDSA(t *testing.T) { initForTesting("ECDSA") Config.Timeout = 1 t.Run("testEcdsaMsgLen", func(*testing.T) { err := testEcdsaMsgLen() if err != nil { t.Error("Expected nil, got ", err) } }) t.Run("testEcdsaPoints", func(*testing.T) { err := testEcdsaPoints() // as of Go 1.7.4, the ECDSA function has a bug we detect: if err == nil { t.Fatalf("The testEcdsaPoints returned without error! We expect it to fail with 2 errors.") } if !strings.Contains(err.Error(), "(2 errors)") && strings.Count(err.Error(), "accepts the (0,0)") != 2 { t.Errorf("Expected 2 errors, got\n%v", err) } }) if execCounter != 12 { t.Error("Expected 12 executions, got ", execCounter) } } func ExampleECDSA(args []string) { LogToFile.Println("Starting ExampleECDSA") // In this example, the args[] begins with an empty value when doing tests flag.Parse() // The curve used and the hash used pubkeyCurve := elliptic.P256() var h hash.Hash h = sha256.New() var signing bool LogToFile.Println("Args:", flag.Args()) switch { case len(flag.Args()) == 6: signing = false case len(flag.Args()) == 5: signing = true default: LogToFile.Fatal("Please provide X, Y, Sign or X, Y, D, Msg as arguments") } // Key instanciation privatekey := new(ecdsa.PrivateKey) pubkey := new(ecdsa.PublicKey) pubkey.Curve = pubkeyCurve pubkey.X = fromBase16(flag.Arg(1)) pubkey.Y = fromBase16(flag.Arg(2)) // msg is always in latest position // we are decoding from hex to have truly random messages msg, err := hex.DecodeString(flag.Arg(len(flag.Args()) - 1)) if err != nil { panic(err) } r := big.NewInt(0) s := big.NewInt(0) h.Write(msg) var signhash []byte signhash = h.Sum(nil) if signing { // private key instanciation: privatekey.PublicKey = *pubkey privatekey.D = fromBase16(flag.Arg(3)) // If signhash is longer than the bit-length of the private key's curve // order, signhash will be truncated to that length. It returns the // signature as a pair of big integers. r, s, serr := ecdsa.Sign(rand.Reader, privatekey, signhash) if serr != nil { LogToFile.Fatalln(serr) } // we first output R, then S with a newline in between as required by // the ECDSA interface. TODO: check if it needs leftpadding or not. fmt.Printf("%s\n%s\n", r.Text(16), s.Text(16)) LogToFile.Printf("%s\n%s\n", r.Text(16), s.Text(16)) } else { // if we are not signing, we are verifying : r = fromBase16(flag.Arg(3)) s = fromBase16(flag.Arg(4)) verifystatus := ecdsa.Verify(pubkey, signhash, r, s) fmt.Println(verifystatus) LogToFile.Println(verifystatus) } LogToFile.Println("Finished ExampleECDSA") } ================================================ FILE: cdf-lib/enc.go ================================================ package cdf import ( "errors" "fmt" "log" mrand "math/rand" "strconv" "sync" "time" ) // TestEnc implements the CDF interface for symmetric encryption and decryption // schemes. func TestEnc() error { LogInfo.Print("testing enc") failed := false // to warn if the used Config won't cover the whole range if (Config.MaxKeyLen-Config.MinKeyLen)%Config.IncrementKey != 0 { LogWarning.Println("It seems like the incrementKey and the maxKeyLen values don't fit well together") } if (Config.MaxMsgLen-Config.MinMsgLen)%Config.IncrementMsg != 0 { LogWarning.Println("It seems like the incrementMsg and the maxMsgLen values don't fit well together") } msg := randomHex(Config.MaxMsgLen) key := randomHex(Config.MaxKeyLen) // key length to use in msg test keyAvgNibbles := 2 * Config.MinKeyLen // msg length to use in key test msgAvgNibbles := 2 * ((Config.MaxMsgLen + Config.MinMsgLen) / 2) // Let us call the message length test err := testMessLen(key[:keyAvgNibbles], msg) if err != nil { failed = true } // Let us call the key length test err = testKeyLen(key, msg[:msgAvgNibbles]) if err != nil { failed = true } if limit := *TestTimings; limit > 0 { dudectTest(limit, Prog1, doOneComputationForEnc, prepareInutsForEnc) dudectTest(limit, Prog2, doOneComputationForEnc, prepareInutsForEnc) } if failed { fmt.Print("\n") return errors.New("one of more tests failed") } return nil } // testKeyLen tests the programs with different key lengths func testKeyLen(key string, msg string) (mainErr error) { TermPrepareFor(1) LogInfo.Println("testing key lengths") if len(key) < 2*Config.MaxKeyLen { LogError.Println("the provided key and MaxKeyLen setting are not compatible") return fmt.Errorf("key length and settings mismatch") } return testProgs(msg, chooseKeys, loopKeyLen(key)) } // testMessLen tests the programs with different message lengths func testMessLen(key string, msg string) (mainErr error) { TermPrepareFor(1) LogInfo.Println("testing message lengths") return testProgs(key, chooseMsg, loopMessLen(msg)) } // loopMessLen is the loop wich is to be used for the testProgs function in // the message length case func loopMessLen(msg string) func(chan string) { return func(msgs chan string) { TermPrepareFor(1) for i := Config.MinMsgLen; i <= Config.MaxMsgLen; i += Config.IncrementMsg { TermPrintInline(1, "%d / %d", i, Config.MaxMsgLen) // get the first i bytes, ie first i*2 nibbles msgs <- msg[:(i * 2)] } } } // loopKeyLen is the loop wich is to be used for the testProgs function in // the key length case func loopKeyLen(key string) func(chan string) { return func(keys chan string) { TermPrepareFor(1) for i := Config.MinKeyLen; i <= Config.MaxKeyLen; i += Config.IncrementKey { TermPrintInline(1, "%d / %d", i, Config.MaxKeyLen) // get the first i bytes, ie first i*2 nibbles keys <- key[:(i * 2)] } } } // chooseKey fixes the key and the message to the provided arguments func chooseKeys(fixed, iterated string) (k string, m string) { m = fixed k = iterated return } // chooseMsg fixes the key and the message to the provided arguments func chooseMsg(fixed, iterated string) (k string, m string) { m = iterated k = fixed return } // testProgs is the basic test in charge of checking the programs Prog1 and // Prog2 are respectively encrypting and decrypting correctly with the key // and msg arguments permuted as per chooseArgs, the loop function to provide // the jobs must be provided. Concurrency is supported, as setted in config.json. func testProgs(fixed string, chooseArgs func(string, string) (string, string), loopOver func(chan string)) (mainErr error) { nbIter := Config.MaxMsgLen if Config.MaxKeyLen > nbIter { nbIter = Config.MaxKeyLen } // Initializing a common, unbuffered, channel which gives tasks to the worker goroutines jobs := make(chan string) errs := make(chan error, nbIter) var wg sync.WaitGroup // spawn some worker goroutines according to the Concurrency setting in Config.json for j := uint(0); j < Config.Concurrency; j++ { wg.Add(1) //to be sure to finish all jobs go func() { for j := range jobs { // here we firstly permute the arguments to match our case k, m := chooseArgs(fixed, j) // we define a job id for logging purpose id := "enc#" + strconv.Itoa(len(m)) + "#" + strconv.Itoa(len(k)) cipher := runOrExitOnErr(Prog1, id, k, m) outStr2 := runOrExitOnErr(Prog2, id, k, cipher) if m != outStr2 { fmt.Print("\n") LogWarning.Printf("decryption mismatch on job %s\nInputs :%s %s\n"+ "Outputs\t1: %s\n\t2: %s\n", id, k, m, cipher, outStr2) errs <- fmt.Errorf("decryption mismatch on job %s", id) } } wg.Done() // report the job as finished }() } // we call the loop function to iterate over the right objects loopOver(jobs) //we close our channel since it's unbuffered close(jobs) // let us wait for our workers to finish their jobs wg.Wait() if len(errs) > 0 { // Initializing the return value var mainErr MultiError firstErr := true for len(errs) > 0 { e := <-errs if firstErr { firstErr = false TermPrepareFor(1) // This is not guaranteed to be the 1st one, but almost LogInfo.Println("First error:", e) } mainErr = append(mainErr, e) } TermPrepareFor(1) return mainErr } return nil } func prepareInutsForEnc() (inputData []string, classes []int) { inputData = make([]string, numberMeasurements) classes = make([]int, numberMeasurements) // there we may want to seed it with the seed indicated in the config file // for now this is not the case to have better results rn := mrand.New(mrand.NewSource(time.Now().UnixNano())) data := randomHex(Config.MaxKeyLen + Config.MinMsgLen) // we change only the key between the two class: //data2 := strings.Repeat("0", Config.MaxKeyLen) + data[Config.MaxKeyLen:] // we use the same key and the same message each time for i := 0; i < numberMeasurements; i++ { classes[i] = rn.Intn(2) if classes[i] == 0 { inputData[i] = data } else { inputData[i] = randomHex(Config.MaxKeyLen + Config.MinMsgLen) } } return } func doOneComputationForEnc(prog string) func(data string) { return func(data string) { key := data[:Config.MaxKeyLen] msg := data[Config.MaxKeyLen:] _, err := runProg(prog, "dudectTest", []string{key, msg}) if err != nil { log.Fatal(err) } } } ================================================ FILE: cdf-lib/enc_test.go ================================================ package cdf import ( "fmt" "os" "testing" ) func TestTestEnc(t *testing.T) { initForTesting("ENC") err := TestEnc() if err != nil { t.Error("Expected nil, got ", err) } if execCounter != 8 { t.Error("Expected 8 executions, got ", execCounter) } } func TestTestEncWithTimings(t *testing.T) { initForTesting("ENC") *TestTimings = 1 // it will run 1 dudect pass enoughMeasurements = float64(200) numberMeasurements = 200 err := TestEnc() if err != nil { t.Error("Expected nil, got ", err) } if execCounter != 408 { t.Error("Expected 408 executions, got ", execCounter) } } func testsForEnc(args []string) { key := args[1] msg := args[2] if len(key)%2 != 0 || len(msg)%2 != 0 { fmt.Fprintln(os.Stderr, "Not a string of even length!") // os.Exit(2) } // output for testing: fmt.Println(msg) } ================================================ FILE: cdf-lib/prf.go ================================================ package cdf import ( "errors" "fmt" ) // TestPrf will test the provided prf function on multiple message length // ranging from MinMsgLen to MaxMsgLen as set in the Config.json file func TestPrf() error { LogInfo.Print("testing prf") failed := false // Let us fetch random keys and messages nibbles: msg := randomHex(Config.MaxMsgLen) key := randomHex(Config.MaxKeyLen) // list of tags tags := make(map[string]int) // key length to use in msg test keyAvgNibbles := 2 * ((Config.MaxKeyLen - Config.MinKeyLen) / 2) // msg length to use in key test msgAvgNibbles := 2 * ((Config.MaxMsgLen - Config.MinMsgLen) / 2) LogInfo.Println("testing message lengths") TermPrepareFor(1) currKey := key[:keyAvgNibbles] failedTmp := false // note that we ignore the incrementMsg parameter, since the *2 is hardcoded here. for i := Config.MinMsgLen; i <= Config.MaxMsgLen; i++ { currMsg := msg[:(i * 2)] TermPrintInline(1, "%d / %d", i, Config.MaxMsgLen) failedTmp = failedTmp || runPrf(currKey, currMsg, tags, i) } if !failedTmp { LogSuccess.Println("message length: okay") } fmt.Print("\n") LogInfo.Println("testing key lengths") TermPrepareFor(1) // reset tags list tags = make(map[string]int) currMsg := msg[:msgAvgNibbles] for i := Config.MinKeyLen; i <= Config.MaxKeyLen; i++ { TermPrintInline(1, "%d / %d", i, Config.MaxKeyLen) currKey := key[:(i * 2)] failed = failed || runPrf(currKey, currMsg, tags, i) } if !failedTmp { LogSuccess.Println("key length: okay") } TermPrepareFor(1) if nil != prfPaddingTests() { failed = true } if failed { fmt.Print("\n") return errors.New("one of more tests failed") } fmt.Print("\n") return nil } // runPrf is a helper method which perform the actual test of the two provided // programs. If checks both programs' output for cohension and verify the generated // tags for duplicates. func runPrf(currKey, currMsg string, tags map[string]int, index int) bool { failed := false // get the first i bytes, ie first i*2 nibbles, since the interface is assuming // hexadecimal in/outputs id := fmt.Sprintf("prf#%d#%d", len(currKey), len(currMsg)) outStr1 := runOrExitOnErr(Prog1, id, currKey, currMsg) outStr2 := runOrExitOnErr(Prog2, id, currKey, currMsg) if previous, ok := tags[outStr1]; ok { fmt.Print("\n") LogWarning.Printf("same tag for %d and %d\n", previous, index) failed = true } else { tags[outStr1] = index } if outStr1 != outStr2 { fmt.Print("\n") LogWarning.Printf("mismatch on length %d", index) failed = true // This is highly unlikely, yet let us cover this case if previous, ok := tags[outStr2]; ok { LogWarning.Printf("and same tag for %d and %d", previous, index) failed = true } else { tags[outStr2] = index } } return failed } func prfPaddingTests() error { LogInfo.Println("Testing right 00 padding") tags := make(map[string]int) currMsg := randomHex(Config.MinMsgLen) currKey := randomHex(Config.MinKeyLen) failed := runPrf(currKey, currMsg, tags, 0) if failed { LogError.Fatalln("Something went really wrong") } currKey = currKey + "00" failed = runPrf(currKey, currMsg, tags, 1) if failed { LogError.Println("Left padding with 00 of the key leads to the same output") return fmt.Errorf("left padding error") } /* // TODO: create an additionnal test to test the case with 00 at the end // of a previously used key if i == Config.MaxKeyLen { // this may be an option, but it would be best to refactor the whole // process to have a function testConsistency() which will then // process the different tests, keeping tracks of the previous tags, // and so allowing to add one more easily... currKey = key[:(i-1)*2] + "00" } */ return nil } ================================================ FILE: cdf-lib/rsaenc.go ================================================ package cdf import ( "crypto/rand" "crypto/rsa" "crypto/sha256" "encoding/hex" "errors" "fmt" "log" "math/big" mrand "math/rand" "strconv" "strings" "sync" "time" ) // TestRSAenc implements the cdf interface for RSA-OAEP encryption. // This interface assumes that the Prog1 can encrypt being given the public // modulus N, the public exponent E both in hex format and then a message : ./Prog1 n e msg // It also assumes that Prog2 can decrypt being given the primes P and Q, the // public exponent E (since some libs need it to build a private key), the private // exponent D, all four in hex format and the cipher text : ./Prog2 p q e d cipher // It does not (yet) assume reflexivity, ie: ./Prog2 n e msg does not need to encrypt. func TestRSAenc() error { LogInfo.Print("testing rsaenc") failed := false // Generate random hexadecimal data to try and encrypt those (the tested // program are supposed to unhexlify this data to obtain Config.MaxMsgLen bytes) msg := randomHex(Config.MaxMsgLen) LogInfo.Println("testing different message's lengths") if err := testRSAencConsistency(msg, Config.RsaN, Config.RsaE, Config.RsaD, Config.RsaP, Config.RsaQ, Config.MaxMsgLen); err != nil { failed = true LogError.Println("while testing messages lengths:", err) } else { LogSuccess.Println("message's lengths test okay") } if err := testRSAencPubExponentLen(msg); err != nil { failed = true LogError.Println("while testing exponent lengths:", err) } else { LogSuccess.Println("exponent's lengths test okay") } if err := testRSAencPubMaxExponentLen(msg); err != nil { failed = true LogError.Println("while testing max exponent support:", err) } else { LogSuccess.Println("max exponent's lengths test okay") } if err := testRSAencLargerMod(Prog1); err != nil { failed = true LogError.Println("while testing bigger than modulus support:\n", err) } else { LogSuccess.Println("larger than modulus test okay for", Prog1) } if err := testRSAencLargerMod(Prog2); err != nil { failed = true LogError.Println("while testing bigger than modulus support:\n", err) } else { LogSuccess.Println("larger than modulus test okay for", Prog2) } if err := testRSAsmallD(); err != nil { failed = true LogError.Println("while testing D against Wiener's attack:\n", err) } else { LogSuccess.Println("private exponent vs Wiener's attack: okay") } if limit := *TestTimings; limit > 0 { TermPrepareFor(1) LogInfo.Println("Starting timing tests, those may take hours depending on the max number of iterations set.") dudectTest(limit, Prog1, doOneComputationForRsa, prepareInputsForRsa) dudectTest(limit, Prog2, doOneComputationForRsa, prepareInputsForRsa) for i := 0; i <= 9; i++ { if i == 7 && len(Config.RsaN) != 2048 { LogInfo.Println("Specific tests for keys with a modulus of 1024 bits were skipped.") break } dudectTest(limit, Prog1, doOneComputationForRsa, prepareInputsForSpecialRsa(i)) dudectTest(limit, Prog2, doOneComputationForRsa, prepareInputsForSpecialRsa(i)) } } if failed { fmt.Print("\n") return errors.New("one of more tests failed") } return nil } // generateExponents generates a random bitlen-bit prime E and the // associated private exponent D, given n and phi(n) func generateExponents(bitlen int) (finE, finD string) { if bitlen == 1 { LogError.Fatalln("There are no prime of bit length 1") } // We initialize our variables start := new(big.Int) one := new(big.Int).SetUint64(1) two := new(big.Int).SetUint64(2) min := new(big.Int).Lsh(one, uint(bitlen-1)) // using the left shift operator p11 := new(big.Int).Sub(fromBase16(Config.RsaP), one) p21 := new(big.Int).Sub(fromBase16(Config.RsaQ), one) Phi := new(big.Int).Mul(p11, p21) D := new(big.Int) // It may be better to not use our seeded Prng, but to seed a new one r := Prng // rand.New(rand.NewSource(time.Now().UnixNano())) // We generate a number between 0 and 2^bitlen while setting one to 2^bitlen start.Rand(r, min) // Ensure we do not start with an even number if 0 != one.Cmp(new(big.Int).Mod(start, two)) { start.Add(start, one) } // We begin looking for a prime bigger than 2^bitlen + random value : E := new(big.Int).Add(start, min) errCounter := 0 for found := false; !found; { // we use 8 times a Miller-Rabin test, so we have < 1/4^8 prob to have // a false positive it is not secure, but sufficient for our purpose found = E.ProbablyPrime(8) if found { // since it is probabilist, it does not hurt to cover this border // case where the random start was too big if E.BitLen() >= bitlen+1 { //LogInfo.Println("e was too big, retrying", min, start, E) found = false E.Sub(E, min) errCounter++ } // Ensure our potential E is coprime with Phi to get a valid key if 0 != one.Cmp(new(big.Int).GCD(nil, nil, E, Phi)) { LogToFile.Println("e was relatively prime to phi, \n\tmin:", min, "\n\tstart:", start, "\n\tE:", E, "\nRetrying.") found = false errCounter++ } } // if found is no true, then E is not probably prime, so we can jump to // the next odd integer if !found { E.Add(E, two) } // It is possible to get in a loop, we arbitrarily assume we are stuck // after 100 errors if errCounter > 100 { // fmt.Printf(LINE_UP) LogWarning.Printf("unable to find a public exponent compatible "+ "with bit-length %d\n", bitlen) LogInfo.Println("consider using safer primes e.g. of the form " + "p1=2a+1 and p2=2b+1 for a and b primes " + "if you want to test this length.") LogInfo.Println("skipping bit-length:", bitlen) TermPrepareFor(1) return generateExponents(bitlen + 1) } } // The result is converted to hex since the interface is feeding the keys // as hex values finE = E.Text(16) // Calculate D as the inverse of E mod Phi, it exists since we checked E was // coprime with Phi D = D.ModInverse(E, Phi) finD = D.Text(16) return finE, finD } // testRSAencPubExponentLen tests exponent length support, bit per bit, starting // from 2 bits however it is possible, depending on the selected primes and // resulting modulus that there are no primes on a given (small) bitlength that // is coprime with the phi(N), should it be the case, a Warning is issued and // it skips to a bigger bit-length, this skipping will statistically not lead // to any bug, so bordercases are not yet covered. func testRSAencPubExponentLen(msg string) error { var errs MultiError TermPrepareFor(1) LogInfo.Println("testing exponent lengths") var N, e, d, P, Q string N = Config.RsaN P = Config.RsaP Q = Config.RsaQ // Starting from 2 since there are no prime of bit length 1, while 3 is // a prime a bit length 2 TermPrepareFor(3) for i := 2; i <= Config.MaxKeyLen; i++ { TermDisplay(3, "trying with public exponent of bit-length %d / %d", i, Config.MaxKeyLen) e, d = generateExponents(i) // note we are doing only 3 tests on msg of size 1,2 and 3 : erc := testRSAencConsistency(msg, N, e, d, P, Q, 3) if erc != nil { LogWarning.Printf("problem with bit-length %d:\n%s\n", i, erc.Error()) TermPrepareFor(4) errs = append(errs, fmt.Errorf("exponents test failed on bit-length %d", i)) } } LogInfo.Println("exponent test finished") if len(errs) > 0 { fmt.Print(lineUp(3)) return errs } return nil } // testRSAencConsistency tests the encryption/decryption process using Prog1 // to encrypt and Prog2 to decrypt, for *iter* trials. func testRSAencConsistency(msg, N, e, d, P, Q string, iter int) error { LogInfo.Println("testing consistency:") // the general settings for that test maxIter := Config.MaxMsgLen * 2 // since the settings are in byte incrementMsg := Config.IncrementMsg * 2 // since the settings are in byte if maxIter > iter*incrementMsg { maxIter = iter * incrementMsg } // Initializing a common, unbuffered channel which gives tasks to // the worker goroutines msgs := make(chan string) errs := make(chan error, maxIter) // spawn some worker goroutines var wg sync.WaitGroup for j := uint(0); j < Config.Concurrency; j++ { wg.Add(1) go func() { for m := range msgs { // using range has to be closed later runID := fmt.Sprintf("rsaenc#%d#%d", iter, len(m)) args := []string{N, e, m} // get the message m from channel msgs and encrypt it cipher, errc := runProg(Prog1, strconv.Itoa(len(m)), args) if errc != nil { // Errors which are "expected" should be marked with FAIL // in the tested program if strings.Contains(cipher, "fail") { errs <- fmt.Errorf("FAIL: %v", errc) LogToFile.Println("Skipping the rest of job", runID) continue } else { // other errors are not expected by the tested program // and we stop there fmt.Println("\nUnexpected error on", Prog1) fmt.Println("Got output", cipher) log.Fatalln(errc) } } recovered, errc := runProg(Prog2, runID, []string{P, Q, e, d, cipher}) if errc != nil { // Errors which are "expected" should be marked with FAIL if strings.Contains(recovered, "fail") { errs <- fmt.Errorf("FAIL: %v", errc) LogToFile.Printf("failed to run Prog2 on job#%s", runID) continue } else { // other errors are not expected and we stop there LogError.Printf("failed to run %s on run %s\nerror: %v", Prog2, runID, errc) LogInfo.Println("after running:", Prog1, args) log.Fatalln(errc) } fmt.Print("\n") } // If the message we fed to the Prog1 does not match the // recovered plaintext from Prog2, an error must have occurred: if m != recovered { errs <- fmt.Errorf("decryption mismatch on length %d", len(m)/2) LogToFile.Printf("decryption mismatch on inputs : %s \n"+ "Got outputs\t1: %s\n\t2: %s", m, cipher, recovered) } } wg.Done() }() } // Let us now fill our channel with the messages to be processed: for i := Config.MinMsgLen * 2; i <= maxIter; i += incrementMsg { TermPrintInline(1, "%d / %d", i/incrementMsg, maxIter/incrementMsg) msgs <- msg[:i] } fmt.Print("\n") // We have to close the channel to inform the receiver that there are // no more messages coming. close(msgs) // let us wait for our workers to finish wg.Wait() if len(errs) > 0 { // Initializing the return value var mainErr MultiError firstErr := true for len(errs) > 0 { e := <-errs if firstErr { firstErr = false // This is not guaranteed to be the 1st one, but almost LogInfo.Println("First error:", e) } mainErr = append(mainErr, e) } TermPrepareFor(1) return mainErr } return nil } // testRSAencPubMaxExponentLen will test the maximal size of the exponent // the tested program support. Typically it would detect when a library is // using an integer instead of a big integer to store the exponent value. func testRSAencPubMaxExponentLen(msg string) (mainErr error) { TermPrepareFor(1) LogInfo.Println("testing max exponent lengths") failed := false var N, e, d, P, Q string N = Config.RsaN P = Config.RsaP Q = Config.RsaQ nTests := 0 fTests := 0 var errs MultiError maxExp := 0 TermPrepareFor(3) // the range is currently hard-coded, ideally it should be generated using // some kind of dichotomic-search like process with an upper limit for iter, i := range [...]int{29, 30, 31, 32, 62, 63, 64, 126, 127, 128} { e, d = generateExponents(i) TermDisplay(3, "trying with public exponent of bit-length %d/%d", i, 128) erc := testRSAencConsistency(msg, N, e, d, P, Q, 1) if erc != nil { failed = true if maxExp == 0 { maxExp = i } errs = append(errs, fmt.Errorf("problem with bit-length %d", i)) fTests++ } nTests = iter + 1 } if failed { mainErr = fmt.Errorf("%d / %d exponents' tests failed:\n%v\n"+ "it seems like the max exponent bit length of one of the programs"+ " is smaller than %d", fTests, nTests, errs, maxExp) } LogInfo.Println("max supported exponent test finished") return mainErr } // testRSAencLargerMod tests the provided program against messages larger than // the used modulus, it does so by computing the size of the modulus and // generating a bigger message, before tring it and expecting an error. If no // error is thrown, then it'll return an error, otherwise it returns nil. // (TODO:We may argue later whether the throwned error should be outputed or not. // It is sowieso logged by the runProg function.) func testRSAencLargerMod(prog string) error { TermPrepareFor(1) LogInfo.Println("testing larger than modulus against", prog) id := "rsaenc#large_" + prog var N, e string N = Config.RsaN e = Config.RsaE msg := randomHex((fromBase16(N).BitLen()+7)/8 + 8) argsP := []string{N, e, msg} _, err := runProg(prog, id, argsP) if err == nil { return fmt.Errorf("%s accepted a message larged than the modulus", prog) } return nil } // testRSAsmallD is a side-check against the provided key, so it doesn't mean // much, unless you are using real keys. Wiener's attack works when d is small, // so let us check if it may work with the current key. (It may also not.) func testRSAsmallD() error { TermPrepareFor(1) LogInfo.Println("testing current key against Wiener's attack precondition") N := fromBase16(Config.RsaN) D := fromBase16(Config.RsaD) temp := big.NewInt(0).Div(bigSqrt(bigSqrt(N)), big.NewInt(3)) if D.Cmp(temp) == -1 { return fmt.Errorf("private exponent too small, may be vulnerable to Wiener's attack") } return nil } // doOneComputationForRsa provides the functions we can pass to the timing tests // to perform rsa on the desired program. func doOneComputationForRsa(prog string) func(string) { return func(data string) { recovered, err := runProg(prog, "dudect-"+prog, []string{Config.RsaP, Config.RsaQ, Config.RsaE, Config.RsaD, data}) if err == nil { // odds are too odd for the decryption to be successful, yet it avoids any compiler optimisation since we use recovered in it. panic(fmt.Errorf("decryption successful: %s", recovered)) } } } // prepareInputs generates inputs to test timings leak, it is a bit optimized // for OAEP but not too much. func prepareInputsForRsa() (inputData []string, classes []int) { inputData = make([]string, numberMeasurements) classes = make([]int, numberMeasurements) rn := mrand.New(mrand.NewSource(time.Now().UnixNano())) // we initialize the key and the big integers we need : N := fromBase16(Config.RsaN) k := uint((N.BitLen() + 7) / 8) // byte len lowerB := new(big.Int).Lsh(big.NewInt(1), 8*(k-1)) // one byte less upperB := new(big.Int).Sub(N, lowerB) ee, err := strconv.ParseInt(Config.RsaE, 16, 8) if err != nil { log.Fatal(err) } pubK := &rsa.PublicKey{N: N, E: int(ee)} for i := 0; i < numberMeasurements; i++ { classes[i] = rn.Intn(2) var tmp *big.Int if classes[i] == 0 { // we don't want a 00 MSB // we generate a big int of 255 bytes tmp = new(big.Int).Rand(rn, upperB) tmp.Add(tmp, lowerB) // ensure us to be have 256 bytes } else { // we want a 00 MSB: tmp = new(big.Int).Rand(rn, lowerB) } // we craft the cipher, since we know the key: // we encrypt to be sure of its size and format when decrypted: it'll be ee data := encryptRSA(new(big.Int), pubK, tmp) inputData[i] = hex.EncodeToString(data) } return } // prepareInputsForSpecialRsa generates inputs to test timings leak, it is a bit optimized // for OAEP but not too much. It also use known inputs that may cause stange behavior. // Those special inputs are thought for 1024-bit modulus using 65537 as public exponent. // Those are coming from the RSA Case Study by Jaffe & al func prepareInputsForSpecialRsa(special int) func() ([]string, []int) { LogInfo.Printf("Testing case %d", special) return func() (inputData []string, classes []int) { inputData = make([]string, numberMeasurements) classes = make([]int, numberMeasurements) rn := mrand.New(mrand.NewSource(time.Now().UnixNano())) // we initialize the key and the big integers we need : N := fromBase16(Config.RsaN) ee, err := strconv.ParseInt(Config.RsaE, 16, 8) if err != nil { log.Fatal(err) } pubK := &rsa.PublicKey{N: N, E: int(ee)} // we craft the cipher, since we know the key: // we encrypt to be sure of its size and format when decrypted: it'll be ee data0, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, pubK, []byte("Test"), []byte("")) if err != nil { log.Fatal(err) } var data []byte one := big.NewInt(1) P := fromBase16(Config.RsaP) k := (N.BitLen() + 7) / 8 // byte len // let us take a few of the special test cases for RSA (1024 bits) from "Efficient side­channel testing for public key algorithms: RSA case study" by J.Jaffe & P.Rohatgi, 2009. switch special { case 0: data = []byte{0} // we need to be sure to match the right ciphertext length of k bytes, // otherwise the test is meaningless. data = leftPad(data, k) case 1: data = []byte{1} data = leftPad(data, k) case 2: data = []byte{2} data = leftPad(data, k) case 3: data = []byte{3} data = leftPad(data, k) case 4: data = new(big.Int).Sub(N, big.NewInt(1)).Bytes() data = leftPad(data, k) case 5: data = new(big.Int).Sub(N, big.NewInt(2)).Bytes() data = leftPad(data, k) case 6: data = new(big.Int).Sub(N, big.NewInt(3)).Bytes() data = leftPad(data, k) // from now on, the tests are though for 1024 bits keys case 7: // in barrett reduction, an intermediate is zero num := new(big.Int).Div(new(big.Int).Lsh(one, 700), P) mult := new(big.Int).Mul(num, new(big.Int).Lsh(one, 528)) denom := new(big.Int).Div(new(big.Int).Lsh(one, 1024), P) num.Mul(num, mult) data = new(big.Int).Div(num, denom).Bytes() data = leftPad(data, k) case 8: // in barrett reduction, an intermediate has high hamming weight num := new(big.Int).Lsh(one, 1000) denom := new(big.Int).Div(new(big.Int).Lsh(one, 1024), P) num.Sub(num, one) data = new(big.Int).Div(num, denom).Bytes() data = leftPad(data, k) case 9: // in barrett reduction, an intermediate is small and low hamming weight num := new(big.Int).Lsh(one, 600) denom := new(big.Int).Div(new(big.Int).Lsh(one, 1024), P) data = new(big.Int).Div(num, denom).Bytes() data = leftPad(data, k) default: log.Fatalln("An unexpected index was provided to the special case RSA input preparation function") } for i := 0; i < numberMeasurements; i++ { classes[i] = rn.Intn(2) if classes[i] == 1 { // we want a special case inputData[i] = hex.EncodeToString(data) } else { // we use the constant ciphertext generated above inputData[i] = hex.EncodeToString(data0) } } return } } ================================================ FILE: cdf-lib/rsasign.go ================================================ package cdf import ( "errors" "fmt" "log" "strconv" "strings" "sync" ) // TestRSAsign implements the cdf interface for RSA based signature schemes. // This interface assumes that the Prog1 can sign being given the primes P // and Q, the public exponent E (since some libs need it to build a private // key), the private exponent D, all four in hex format and the message: // ./Prog1 p q e d msg // It also assumes that Prog2 can verify the signature being given the public // modulus N and the public exponent E, as well as the signature S // all given in hex format and the message : ./Prog2 n e s msg // It does not (for now) assume reflexivity. func TestRSAsign() error { LogInfo.Print("testing rsasign") failed := false // Generate random hexadecimal data to try and sign those (the tested // program are supposed to unhexlify this data to obtain bytes) msg := randomHex(Config.MaxMsgLen) LogInfo.Println("testing different message's lengths") if err := testRsaSignConsistency(msg, Config.RsaN, Config.RsaE, Config.RsaD, Config.RsaP, Config.RsaQ, Config.MaxMsgLen); err != nil { failed = true LogError.Println("while testing messages lengths:", err) } else { LogSuccess.Println("message's lengths test okay") } if failed { fmt.Print("\n") return errors.New("one of more tests failed") } return nil } // testRsaSignConsistency tests the sign/verify process using Prog1 // to sign and Prog2 to verify, for *iter* trials. func testRsaSignConsistency(msg, N, e, d, P, Q string, iter int) error { LogInfo.Println("testing consistency:") var errs MultiError // Initializing a common, unbuffered channel which gives tasks to // the worker goroutines msgs := make(chan string) // spawn some worker goroutines var wg sync.WaitGroup for j := uint(0); j < Config.Concurrency; j++ { wg.Add(1) go func() { for m := range msgs { // using range has to be closed later runID := fmt.Sprintf("rsasign#%d#%d", iter, len(m)) args := []string{P, Q, e, d, m} // get the message m from channel msgs and sign it signature, errc := runProg(Prog1, strconv.Itoa(len(m)), args) if errc != nil { // Errors which are "expected" should be marked with FAIL // in the tested program if strings.Contains(signature, "fail") { errs = append(errs, fmt.Errorf("FAIL: %v", errc)) LogToFile.Println("Skipping the rest of job", runID) continue } else { // other errors are not expected by the tested program // and we stop there fmt.Println("\nUnexpected error on", Prog1) fmt.Println("Got output", signature) log.Fatalln(errc) } } result, errc := runProg(Prog2, runID, []string{N, e, signature, m}) if errc != nil { // Errors which are "expected" should be marked with FAIL if strings.Contains(result, "fail") { errs = append(errs, fmt.Errorf("FAIL: %v", errc)) LogToFile.Printf("failed to run Prog2 on job#%s", runID) continue } else { // other errors are not expected and we stop there LogError.Printf("failed to run %s on run %s\nerror: %v", Prog2, runID, errc) LogInfo.Println("after running:", Prog1, args) log.Fatalln(errc) } fmt.Print("\n") } // If the message we fed to the Prog1 is not valid wrt its sign // according to Prog2, an error must have occurred: if result != trueStr { errs = append(errs, fmt.Errorf("verification failed on length %d", len(m)/2)) LogToFile.Printf("error on inputs : %s \n"+ "Got outputs\t1: %s\n\t2: %s", m, signature, result) } } wg.Done() }() } maxIter := Config.MaxMsgLen * 2 // since the settings are in byte incrementMsg := Config.IncrementMsg * 2 // since the settings are in byte if maxIter > iter*incrementMsg { maxIter = iter * incrementMsg } // Let us now fill our channel with the messages to be processed: for i := Config.MinMsgLen * 2; i <= maxIter; i += incrementMsg { TermPrintInline(1, "%d / %d", i/incrementMsg, maxIter/incrementMsg) msgs <- msg[:i] } fmt.Print("\n") // We have to close the channel to inform the receiver that there are // no more messages coming. close(msgs) // let us wait for our workers to finish wg.Wait() if len(errs) > 0 { return errs } return nil } ================================================ FILE: cdf-lib/termview.go ================================================ package cdf import ( "log" "os" "strconv" "strings" ) // Escape sequences for terminal rendering. var ( esc = "\033[" cl = esc + "2K" clearScreen = esc + "2J" resetCursor = esc + "0;0H" clearLine = esc + "1G" + cl TermView = log.New(os.Stdout, "", 0) ) // lineUp will return the escape sequence to move up by n lines in the terminal // and clear the line func lineUp(n int) string { return esc + strconv.Itoa(n) + "F" + clearLine } // lineDown will return the escape sequence to move down by n lines in the // terminal and clear the line func lineDown(n int) string { return esc + strconv.Itoa(n) + "E" + clearLine } // TermClear is a function which allow to clear the terminal to prepare // displaying the data func TermClear() { TermView.Print(clearScreen + resetCursor) } // TermPrepareFor is a function which allow to allocate the lines we will be // using later. Its purpose is to make the terminal display we use compatible // with the default logging functions. func TermPrepareFor(size int) { TermView.Print(strings.Repeat("\n", size)) } // TermDisplay moves the cursor up and then displays the specified content as // well as writing to the log file if it is enabled func TermDisplay(size int, format string, a ...interface{}) { TermView.Printf(lineUp(size)+format, a...) LogToFile.Printf(format, a...) } // TermPrintInline prints inline the provided string, with string formatting func TermPrintInline(size int, format string, a ...interface{}) { TermView.Printf(lineUp(size)+clearLine+format, a...) LogToFile.Printf(format, a...) } ================================================ FILE: cdf-lib/utils.go ================================================ package cdf import ( "bytes" "crypto/rsa" "fmt" "io" "io/ioutil" "log" "math/big" "math/rand" "os" "os/exec" "sort" "strings" "time" ) // Here are our constants const ( hexChars = "abcdef0123456789" trueStr = "true" ) // Those are the different global variables used by CDF var ( ForceVerbose *bool // enables verbose logging LogInfo *log.Logger // info on cdf execution LogSuccess *log.Logger // all test cases past LogWarning *log.Logger // when a test fails LogError *log.Logger // when something's wrong and unexpected LogToFile *log.Logger // write it to the log file to avoid verbose output Prng *rand.Rand // non-crypto Prng to randomize tests Interf string // interface Prog1 string // the path to the first executable Prog2 string // the path to the second executable in interfaces where two are needed TestHashes *bool // specify if the -h flag is supported by both program TestTimings *int // specify how many, if any, timing tests should be run ) // Config contains the global cdf Configuration variables: // Seed is the Prng seed // *MsgLen for xof, prf, enc, rsaenc: the different lengths of the tested messages // *KeyLen for prf, enc: length of key; for rsaenc: length of tested public exponents // increment* is the number of bytes of increment between two loops in some interfaces // Rsa* for oaep/pkcs encryption: the primes P,Q, the modulus N, the public exponent E and the private one D. Must be given as hex strings in big endian representation // Ecdsa*: the X and Y public coordinates to use and the private big integer D, all to be given as hex strings in big endian representation // Concurrency: the maximum number of concurrent go routine which should be running an exec call to the tested program at the same time // VerboseLog: a boolean specifying whether all inputs/outputs are to be written to a log file or not. Can help with debugging var Config struct { Seed int64 `json:"seed"` MinMsgLen int `json:"minMsgLen"` MaxMsgLen int `json:"maxMsgLen"` IncrementMsg int `json:"incrementMsg"` MinKeyLen int `json:"minKeyLen"` MaxKeyLen int `json:"maxKeyLen"` IncrementKey int `json:"incrementKey"` RsaP string `json:"rsaP"` RsaQ string `json:"rsaQ"` RsaN string `json:"rsaN"` RsaE string `json:"rsaE"` RsaD string `json:"rsaD"` EcdsaX string `json:"ecdsaX"` EcdsaY string `json:"ecdsaY"` EcdsaD string `json:"ecdsaD"` DsaP string `json:"dsaP"` DsaQ string `json:"dsaQ"` DsaG string `json:"dsaG"` DsaY string `json:"dsaY"` DsaX string `json:"dsaX"` Timeout int `json:"timeout"` Concurrency uint `json:"concurrency"` VerboseLog bool `json:"verboseLog"` } // MultiError allows to store multiple errors // like those we get from our external tests type MultiError []error // (MultiError) Error implements the error interface for our MultiError type func (m MultiError) Error() string { s, n := "", 0 for _, e := range m { if e != nil { s += "\n" + e.Error() n++ } } switch n { case 0: return "(0 error)" case 1: return fmt.Sprintf("(1 error)%s", s) } return fmt.Sprintf("(%d errors)%s", n, s) } // InitLog allows one to initialise the logging system to output data to the specified file. func InitLog(logFile *os.File) { if logFile != nil { multiO := io.MultiWriter(logFile, os.Stdout) multiE := io.MultiWriter(logFile, os.Stderr) // Configure loggers LogInfo = log.New(multiO, "\x1b[0;36mINFO:\x1b[0m ", 0) LogSuccess = log.New(multiO, "\x1b[0;32mSUCCESS:\x1b[0m ", 0) LogWarning = log.New(multiO, "\x1b[0;35mWARNING:\x1b[0m ", log.Lshortfile) LogError = log.New(multiE, "\x1b[0;31mERROR:\x1b[0m ", log.Lshortfile) LogToFile = log.New(logFile, "", log.Ldate|log.Ltime|log.Lshortfile) log.SetOutput(multiO) LogToFile.Println("Intiliazing logs : done") } else { LogInfo = log.New(ioutil.Discard, "\x1b[0;36mINFO:\x1b[0m ", 0) LogSuccess = log.New(ioutil.Discard, "\x1b[0;32mSUCCESS:\x1b[0m ", 0) LogWarning = log.New(ioutil.Discard, "\x1b[0;35mWARNING:\x1b[0m ", log.Lshortfile) LogError = log.New(ioutil.Discard, "\x1b[0;31mERROR:\x1b[0m ", log.Lshortfile) LogToFile = log.New(ioutil.Discard, "", log.Ldate|log.Ltime|log.Lshortfile) log.SetOutput(ioutil.Discard) TermView.SetOutput(ioutil.Discard) } } // randomHex generate len*2 random hex char to have len random bytes func randomHex(len int) string { charNibbles := make([]byte, len*2) for i := 0; i < len*2; i++ { charNibbles[i] = hexChars[Prng.Uint32()%16] } return string(charNibbles) } // fromBase16 is a helper method to use the prime in hex form, inspired from crypto/rsa/rsa_test.go func fromBase16(base16 string) *big.Int { i, ok := new(big.Int).SetString(base16, 16) if !ok { log.Fatalln("trying to convert from base16 a bad number: " + base16) } return i } // DisableLogFile reset the different log to output only on Stdout/Stderr and // disable the verbose LogToFile, with a mere 100ns overhead (according to // https://gist.github.com/Avinash-Bhat/48c4f06b0cc840d9fd6c) func DisableLogFile() { // we disable the LogToFile completely LogToFile.SetFlags(0) LogToFile.SetOutput(ioutil.Discard) // we reset the other logs to output on the Std outputs LogError.SetOutput(os.Stderr) LogWarning.SetOutput(os.Stdout) LogSuccess.SetOutput(os.Stdout) LogInfo.SetOutput(os.Stdout) log.SetOutput(os.Stdout) } // this is a trick from https://github.com/golang/go/blob/master/src/os/exec/exec_test.go#L32-L44 // which allows us to mimick the exec package in test files! var execCommand = exec.Command // runProg is a helper function allowing to run the program with specific arguments func runProg(prog, runID string, args []string) (string, error) { LogToFile.Println(strings.Join(append([]string{"Batch#", runID, "Attempting :", prog}, args...), " ")) var cmd *exec.Cmd cmd = execCommand(prog, args...) // we link Stdout and Stderr to alternative bytes.Buffer to control the outputs var out, outerr bytes.Buffer cmd.Stdout = &out cmd.Stderr = &outerr err := cmd.Start() if err != nil { LogError.Fatalln("Could not start exec Cmd:", err) } //out, err := cmd.CombinedOutput() timer := time.AfterFunc(time.Duration(Config.Timeout)*time.Second, func() { cmd.Process.Kill() }) err = cmd.Wait() if err != nil { LogToFile.Println("Error on batch#", runID, "with", prog) LogToFile.Println("Program returned:", out.String()+outerr.String()) } else { LogToFile.Println("Batch#", runID, prog, "runned successfully, it returned: ", out.String()) } if !timer.Stop() { return "", fmt.Errorf("Cmd timed out! STOP") } return strings.ToLower(strings.TrimSpace(out.String() + outerr.String())), err } // runOrExitOnErr invokes runProg and if we encounter an error // exits by invoking log.Fatal with the error. func runOrExitOnErr(prog, id string, args ...string) string { outStr, err := runProg(prog, id, args) if err != nil { fmt.Printf("\nExit on: %s\n", outStr) LogError.Println(append([]string{"Failed after running:", prog}, args...)) log.Fatalln(err) } return outStr } // bigSqrt is computing the integer square-root of x, for x a big integer func bigSqrt(x *big.Int) (kx *big.Int) { switch x.Sign() { case -1: panic(-1) case 0: return big.NewInt(0) } var px, xk1 big.Int kx = big.NewInt(0) kx.SetBit(kx, x.BitLen()/2+1, 1) for { // we applied the iterative formula found on Wikipedia xk1.Rsh(xk1.Add(kx, xk1.Div(x, kx)), 1) if xk1.Cmp(kx) == 0 || xk1.Cmp(&px) == 0 { break } px.Set(kx) kx.Set(&xk1) } return } // Int64ToSort let us fullfill the Sort interface for slices of int64 type Int64ToSort []int64 func (s Int64ToSort) Len() int { return len(s) } func (s Int64ToSort) Less(i, j int) bool { return s[i] < s[j] } func (s Int64ToSort) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // for dudect func percentile(x []int64, perc float64) int64 { val := int(perc * float64(len(x))) if len(x) <= val || 0 >= val { log.Fatalln("Error, percentile should be smaller than 1 and bigger than 0. Got:\n", val, len(x), perc) } sort.Sort(Int64ToSort(x)) return x[val] } // encryptRSA func encryptRSA(c *big.Int, pub *rsa.PublicKey, m *big.Int) []byte { e := big.NewInt(int64(pub.E)) c.Exp(m, e, pub.N) return c.Bytes() } // leftPad returns a new slice of length size. The contents of input are right // aligned in the new slice and its left part is zero initialised as per Go spec. func leftPad(input []byte, size int) (out []byte) { n := len(input) if n > size { n = size } out = make([]byte, size) copy(out[len(out)-n:], input) return } ================================================ FILE: cdf-lib/utils_test.go ================================================ package cdf import ( "fmt" "io/ioutil" "log" "math/rand" "os" "os/exec" "testing" ) var execCounter int func TestHelperProcess(t *testing.T) { if os.Getenv("GO_WANT_HELPER_PROCESS") == "" { return } defer os.Exit(0) logFile, err := os.OpenFile("/tmp/test_logs.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { t.Fatalf("Failed to open test_logs.txt file:", err) } defer logFile.Close() LogToFile = log.New(logFile, "", log.Ldate|log.Ltime|log.Lshortfile) args := os.Args for len(args) > 0 { if args[0] == "--" { args = args[1:] break } args = args[1:] } if len(args) == 0 { fmt.Fprintf(os.Stderr, "No command\n") os.Exit(2) } switch os.Getenv("GO_WANT_HELPER_PROCESS") { case "ENC": testsForEnc(args) case "ECDSA": ExampleECDSA(args) case "DSA": ExampleDSA(args) default: return } LogToFile = log.New(ioutil.Discard, "", log.Ldate|log.Ltime|log.Lshortfile) } // fakeExecCommand is a trick from the test of the os/exec package to be able to test it. func fakeExecCommand(currentTest string) func(command string, args ...string) *exec.Cmd { return func(command string, args ...string) *exec.Cmd { execCounter++ cs := []string{"-test.run=TestHelperProcess", "--", command} cs = append(cs, args...) cmd := exec.Command(os.Args[0], cs...) // Let us tell the TestHelperProcess that we are running it from fakeExecCommand: cmd.Env = []string{fmt.Sprintf("GO_WANT_HELPER_PROCESS=%s", currentTest)} return cmd } } func initForTesting(currentTest string) { // disabling log: InitLog(nil) // disabling exec: execCommand = fakeExecCommand(currentTest) execCounter = 0 // setting some default test parameters: Config.MinKeyLen = 1 Config.MaxKeyLen = 2 Config.MinMsgLen = 1 Config.MaxMsgLen = 2 Config.IncrementKey = 1 Config.IncrementMsg = 1 Config.Seed = 0 // a random RSA key Config.RsaP = "D29BB20DAE71CA8EA2988DBC5629CA4C830A7F39D031DC45D064F6F8463ACA73E59F999FA1DC5F01199B2EB949EAA08D8277337027C77317B159B96975A86B57" Config.RsaQ = "D09CCF3050C82108220DA39DEBA7446758D0061CC046C52C52370A81C7358571E8F1494F49D82B7CB31293FE0E0F15B8200B1EADD1364A5CE60A97ABF3D41D33" Config.RsaN = "AB9F81FF42B280FE2F2F6A9D167C27247A450241D082B955F7F444789687B805D6F06811B6D09B9B661670F1E4B205753E9167A072F0B8442848F291E0D139D2403F2E1C6F23380C03058D99176CF8A6C7AAAAAF5822FA2B82E9A29888A39FDBA9B3B13DEB47DB15A3731F825454636729DCC6A655C4563C6F1B33CFFDC23D55" Config.RsaE = "10001" Config.RsaD = "60AD8C17754504F12B3774C165072F2D974B04887AA309306A6B499EFC7D1BA6FE7B92C457CD8FBAAC797BCA67DFF8BF212DDBC840B765B5CF53B88180B99BEDEE66F23EA3A03297E138EAC7E2A0DFDB1E07B4E21C27D3AF2996D16A5050897C9FA32DC0C6ABFFBC6919E8B9D80A6478FCBC71E4D70E70C632B82D64995DE309" // ECDSA key for P256 Config.EcdsaX = "3bac7e95a003264cc075a2ba8d4e949862acd755d49094ad8d28bd0d56299dc6" Config.EcdsaY = "5c6a5b3810181d82f5eb1be32c9cd8d6c387fcb06fed530d749e3997eb22bd8c" Config.EcdsaD = "8964e19c5ae38669db3047f6b460863f5dc6c4510d3427e33545caf9527aafcf" // DSA key Config.DsaP = "A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF" Config.DsaQ = "E1D3391245933D68A0714ED34BBCB7A1F422B9C1" Config.DsaG = "634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA" Config.DsaY = "32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2" Config.DsaX = "5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A" // General settings Config.Timeout = 5 Config.Concurrency = 3 Config.VerboseLog = false // let us set the PRNG using the seed: Prng = rand.New(rand.NewSource(Config.Seed)) // Finally we setup the flags: TestTimings = new(int) TestHashes = new(bool) } ================================================ FILE: cdf-lib/xof.go ================================================ package cdf import ( "errors" "fmt" ) // TestXof will generate a random message and test the range from MinMsgLen to // MaxMsgLen with IncrementMsg bytes increment. It checks for duplicate results // and compare both implementation against each other. Its return value is // an error or nil on success. func TestXof() error { LogInfo.Print("testing xof") failed := false msg := randomHex(Config.MaxMsgLen) // list of hashes hashes := make(map[string]int) LogInfo.Println("testing message lengths") for i := Config.MinMsgLen; i <= Config.MaxMsgLen; i += Config.IncrementMsg { TermPrintInline(1, "%d / %d", i, Config.MaxMsgLen) id := fmt.Sprintf("xof#msglen#%d", i) // get the first i bytes, ie first i*2 nibbles outStr1 := runOrExitOnErr(Prog1, id, msg[:(i*2)]) outStr2 := runOrExitOnErr(Prog2, id, msg[:(i*2)]) if length, ok := hashes[outStr1]; ok { fmt.Print("\n") LogWarning.Printf("same hash for %d and %d", length, i) failed = true } else { hashes[outStr1] = i } if outStr1 != outStr2 { fmt.Print("\n") LogWarning.Printf("mismatch on length %d\nGot:\n\t%s\n\t%s", i, outStr1, outStr2) failed = true if length, ok := hashes[outStr2]; ok { LogWarning.Printf("same hash for %d and %d", length, i) failed = true } else { hashes[outStr2] = i } } } if failed { fmt.Print("\n") return errors.New("one of more tests failed") } fmt.Print("\n") return nil } ================================================ FILE: config.json ================================================ { "seed": 5 , "minMsgLen": 2 , "maxMsgLen": 214 , "incrementMsg": 2 , "minKeyLen": 16 , "maxKeyLen": 32 , "incrementKey": 8 , "rsaP":"e999d9abbcf3ae2e3261957863bea74f4182cf27e22e4faff461c96ef19a65bf8e85aca934e18a745e64f7f2be9e150f562dda16e52e0504e4ab53f70c12ebec2ccf4e4c628356c4ebdab3398dfef6274b4c3f5b14531e4499acd0d59c5da3a03991cf8debb05799d9156ee807c6d3088e0d01d98ab45800d1b0e94712f38575" , "rsaQ":"ec244a18729e63a990ddcd414d0066af68c31343bd6ac03a189baa98783436d19c455fd494f5ab10ccd9ab9d18550eed6c2929ac0465165349c175a81eaa24da2c47de1a2dbe88eb4434e7b68b32b89fc2aec6433046713a048d54b5b86766333d540b965c5bac6e4a971d7b804a5f39c8f7aae6f301468857d15fdf3d4c4fdb" , "rsaN":"d77af1e9b6464e634834e85e48969f5d649eb89fa16566a54daa95135b4b3ad8be44bf8c0c1454575059627c34ddd460b4424080e87c0c816550e54f9f68b6a1daeeab2d4b6da896544a3630e044f30d640830a9ab01c5ca2d77840d534a51147b6aba70a07b3a75f76962052f2769989dc4abd6ee12eb19dc62273bddf483793cd0af625f54db606fb205e2ffa3ed8d2300b0fc6b3e63b061fa7c7d487c960f58edfce17b0ee8c14693b3a1ace8412c09ae77592b572e2bff4fffa4e40805574704f16ab1aa7e66ed3d67e76a101dae09f504c1c607c1345ab17d7c16884cf80ebff2f3702d6d81472ed378f8137c2dda5a5556c81aa5c8c31ed1a9dc3e4617" , "rsaE":"11" , "rsaD":"1c76beff6efefbd2fe2d8f80f64d7d6802b94ad91d826e40a26ec5c190f26cb1a23f812107ac07f883159511331a657fb25cc391290370e037a759bbca06f6929b33de9a75398c5cc62e42dd81c0b84783d5c135d9d3526643d38d59350227c569dcf57d92b0607d7c5b1061e81c747453306f77896374ead8afb4de6e29480da8b1df30a2b59a39aeb04c8118f3b2cc47f4bf1581245e8cdb687dd0b15c768de4ce74d2c86ab16f3cf08d9d6f7b8619cb9a7a8790377d55d6600f9714836db6ad90379d35d10e5c4cc552d1ad28be125bef5b081fe449246c612299dbc64f24ccfde6158d5bdc43c8748b5f08b82db1bc478ce408c538b398a68293e2f035" , "ecdsaX":"3bac7e95a003264cc075a2ba8d4e949862acd755d49094ad8d28bd0d56299dc6" , "ecdsaY":"5c6a5b3810181d82f5eb1be32c9cd8d6c387fcb06fed530d749e3997eb22bd8c" , "ecdsaD":"8964e19c5ae38669db3047f6b460863f5dc6c4510d3427e33545caf9527aafcf" , "dsaP" : "A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF" , "dsaQ" : "E1D3391245933D68A0714ED34BBCB7A1F422B9C1" , "dsaG" : "634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA" , "dsaY" : "32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2" , "dsaX" : "5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A" , "concurrency":5 , "timeout":5 , "verboseLog": false } ================================================ FILE: config.json.enc ================================================ { "seed": 42 , "minMsgLen": 1 , "maxMsgLen": 512 , "incrementMsg": 1 , "minKeyLen": 1 , "maxKeyLen": 64 , "incrementKey": 1 , "rsaP":"e999d9abbcf3ae2e3261957863bea74f4182cf27e22e4faff461c96ef19a65bf8e85aca934e18a745e64f7f2be9e150f562dda16e52e0504e4ab53f70c12ebec2ccf4e4c628356c4ebdab3398dfef6274b4c3f5b14531e4499acd0d59c5da3a03991cf8debb05799d9156ee807c6d3088e0d01d98ab45800d1b0e94712f38575" , "rsaQ":"ec244a18729e63a990ddcd414d0066af68c31343bd6ac03a189baa98783436d19c455fd494f5ab10ccd9ab9d18550eed6c2929ac0465165349c175a81eaa24da2c47de1a2dbe88eb4434e7b68b32b89fc2aec6433046713a048d54b5b86766333d540b965c5bac6e4a971d7b804a5f39c8f7aae6f301468857d15fdf3d4c4fdb" , "rsaN":"d77af1e9b6464e634834e85e48969f5d649eb89fa16566a54daa95135b4b3ad8be44bf8c0c1454575059627c34ddd460b4424080e87c0c816550e54f9f68b6a1daeeab2d4b6da896544a3630e044f30d640830a9ab01c5ca2d77840d534a51147b6aba70a07b3a75f76962052f2769989dc4abd6ee12eb19dc62273bddf483793cd0af625f54db606fb205e2ffa3ed8d2300b0fc6b3e63b061fa7c7d487c960f58edfce17b0ee8c14693b3a1ace8412c09ae77592b572e2bff4fffa4e40805574704f16ab1aa7e66ed3d67e76a101dae09f504c1c607c1345ab17d7c16884cf80ebff2f3702d6d81472ed378f8137c2dda5a5556c81aa5c8c31ed1a9dc3e4617" , "rsaE":"11" , "rsaD":"1c76beff6efefbd2fe2d8f80f64d7d6802b94ad91d826e40a26ec5c190f26cb1a23f812107ac07f883159511331a657fb25cc391290370e037a759bbca06f6929b33de9a75398c5cc62e42dd81c0b84783d5c135d9d3526643d38d59350227c569dcf57d92b0607d7c5b1061e81c747453306f77896374ead8afb4de6e29480da8b1df30a2b59a39aeb04c8118f3b2cc47f4bf1581245e8cdb687dd0b15c768de4ce74d2c86ab16f3cf08d9d6f7b8619cb9a7a8790377d55d6600f9714836db6ad90379d35d10e5c4cc552d1ad28be125bef5b081fe449246c612299dbc64f24ccfde6158d5bdc43c8748b5f08b82db1bc478ce408c538b398a68293e2f035" , "ecdsaX":"3bac7e95a003264cc075a2ba8d4e949862acd755d49094ad8d28bd0d56299dc6" , "ecdsaY":"5c6a5b3810181d82f5eb1be32c9cd8d6c387fcb06fed530d749e3997eb22bd8c" , "ecdsaD":"8964e19c5ae38669db3047f6b460863f5dc6c4510d3427e33545caf9527aafcf" , "concurrency":5 , "timeout":5 , "verboseLog": true } ================================================ FILE: config.json.oaep ================================================ { "seed": 5 , "minMsgLen": 2 , "maxMsgLen": 214 , "incrementMsg": 2 , "minKeyLen": 16 , "maxKeyLen": 32 , "incrementKey": 8 , "rsaP":"e999d9abbcf3ae2e3261957863bea74f4182cf27e22e4faff461c96ef19a65bf8e85aca934e18a745e64f7f2be9e150f562dda16e52e0504e4ab53f70c12ebec2ccf4e4c628356c4ebdab3398dfef6274b4c3f5b14531e4499acd0d59c5da3a03991cf8debb05799d9156ee807c6d3088e0d01d98ab45800d1b0e94712f38575" , "rsaQ":"ec244a18729e63a990ddcd414d0066af68c31343bd6ac03a189baa98783436d19c455fd494f5ab10ccd9ab9d18550eed6c2929ac0465165349c175a81eaa24da2c47de1a2dbe88eb4434e7b68b32b89fc2aec6433046713a048d54b5b86766333d540b965c5bac6e4a971d7b804a5f39c8f7aae6f301468857d15fdf3d4c4fdb" , "rsaN":"d77af1e9b6464e634834e85e48969f5d649eb89fa16566a54daa95135b4b3ad8be44bf8c0c1454575059627c34ddd460b4424080e87c0c816550e54f9f68b6a1daeeab2d4b6da896544a3630e044f30d640830a9ab01c5ca2d77840d534a51147b6aba70a07b3a75f76962052f2769989dc4abd6ee12eb19dc62273bddf483793cd0af625f54db606fb205e2ffa3ed8d2300b0fc6b3e63b061fa7c7d487c960f58edfce17b0ee8c14693b3a1ace8412c09ae77592b572e2bff4fffa4e40805574704f16ab1aa7e66ed3d67e76a101dae09f504c1c607c1345ab17d7c16884cf80ebff2f3702d6d81472ed378f8137c2dda5a5556c81aa5c8c31ed1a9dc3e4617" , "rsaE":"11" , "rsaD":"1c76beff6efefbd2fe2d8f80f64d7d6802b94ad91d826e40a26ec5c190f26cb1a23f812107ac07f883159511331a657fb25cc391290370e037a759bbca06f6929b33de9a75398c5cc62e42dd81c0b84783d5c135d9d3526643d38d59350227c569dcf57d92b0607d7c5b1061e81c747453306f77896374ead8afb4de6e29480da8b1df30a2b59a39aeb04c8118f3b2cc47f4bf1581245e8cdb687dd0b15c768de4ce74d2c86ab16f3cf08d9d6f7b8619cb9a7a8790377d55d6600f9714836db6ad90379d35d10e5c4cc552d1ad28be125bef5b081fe449246c612299dbc64f24ccfde6158d5bdc43c8748b5f08b82db1bc478ce408c538b398a68293e2f035" , "ecdsaX":"3bac7e95a003264cc075a2ba8d4e949862acd755d49094ad8d28bd0d56299dc6" , "ecdsaY":"5c6a5b3810181d82f5eb1be32c9cd8d6c387fcb06fed530d749e3997eb22bd8c" , "ecdsaD":"8964e19c5ae38669db3047f6b460863f5dc6c4510d3427e33545caf9527aafcf" , "concurrency":5 , "verboseLog": false } ================================================ FILE: config.json.prf ================================================ { "seed": 42 , "minMsgLen": 1 , "maxMsgLen": 512 , "incrementMsg": 1 , "minKeyLen": 1 , "maxKeyLen": 64 , "incrementKey": 1 , "rsaP":"e999d9abbcf3ae2e3261957863bea74f4182cf27e22e4faff461c96ef19a65bf8e85aca934e18a745e64f7f2be9e150f562dda16e52e0504e4ab53f70c12ebec2ccf4e4c628356c4ebdab3398dfef6274b4c3f5b14531e4499acd0d59c5da3a03991cf8debb05799d9156ee807c6d3088e0d01d98ab45800d1b0e94712f38575" , "rsaQ":"ec244a18729e63a990ddcd414d0066af68c31343bd6ac03a189baa98783436d19c455fd494f5ab10ccd9ab9d18550eed6c2929ac0465165349c175a81eaa24da2c47de1a2dbe88eb4434e7b68b32b89fc2aec6433046713a048d54b5b86766333d540b965c5bac6e4a971d7b804a5f39c8f7aae6f301468857d15fdf3d4c4fdb" , "rsaN":"d77af1e9b6464e634834e85e48969f5d649eb89fa16566a54daa95135b4b3ad8be44bf8c0c1454575059627c34ddd460b4424080e87c0c816550e54f9f68b6a1daeeab2d4b6da896544a3630e044f30d640830a9ab01c5ca2d77840d534a51147b6aba70a07b3a75f76962052f2769989dc4abd6ee12eb19dc62273bddf483793cd0af625f54db606fb205e2ffa3ed8d2300b0fc6b3e63b061fa7c7d487c960f58edfce17b0ee8c14693b3a1ace8412c09ae77592b572e2bff4fffa4e40805574704f16ab1aa7e66ed3d67e76a101dae09f504c1c607c1345ab17d7c16884cf80ebff2f3702d6d81472ed378f8137c2dda5a5556c81aa5c8c31ed1a9dc3e4617" , "rsaE":"11" , "rsaD":"1c76beff6efefbd2fe2d8f80f64d7d6802b94ad91d826e40a26ec5c190f26cb1a23f812107ac07f883159511331a657fb25cc391290370e037a759bbca06f6929b33de9a75398c5cc62e42dd81c0b84783d5c135d9d3526643d38d59350227c569dcf57d92b0607d7c5b1061e81c747453306f77896374ead8afb4de6e29480da8b1df30a2b59a39aeb04c8118f3b2cc47f4bf1581245e8cdb687dd0b15c768de4ce74d2c86ab16f3cf08d9d6f7b8619cb9a7a8790377d55d6600f9714836db6ad90379d35d10e5c4cc552d1ad28be125bef5b081fe449246c612299dbc64f24ccfde6158d5bdc43c8748b5f08b82db1bc478ce408c538b398a68293e2f035" , "ecdsaX":"3bac7e95a003264cc075a2ba8d4e949862acd755d49094ad8d28bd0d56299dc6" , "ecdsaY":"5c6a5b3810181d82f5eb1be32c9cd8d6c387fcb06fed530d749e3997eb22bd8c" , "ecdsaD":"8964e19c5ae38669db3047f6b460863f5dc6c4510d3427e33545caf9527aafcf" , "concurrency":5 , "verboseLog": false } ================================================ FILE: examples/.gitignore ================================================ * !*.c !*.cpp !*.go !*.java !*.py !.gitignore ================================================ FILE: examples/blake2new.py ================================================ # encoding: utf-8 import struct, binascii, copy from ctypes import * MASK8BITS = 0xff MASK16BITS = 0xffff MASK32BITS = 0xffffffff MASK48BITS = 0xffffffffffff MASK64BITS = 0xffffffffffffffff #--------------------------------------------------------------- class BLAKE2(object): """ BLAKE2 is a base class for BLAKE2b and BLAKE2s """ sigma = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3] ] # only 1st 10 rows are used by BLAKE2s # - - - - - - - - - - - - - - - - - - - - - - - - - - - def __init__(self, digest_size=0, **args): print(""" *********************************************** * You just instantiated a base class. Please * * instantiate either BLAKE2b or BLAKE2s. * *********************************************** """) raise Exception('base class instantiation') # - - - - - - - - - - - - - - - - - - - - - - - - - - - def _init(self, key=b''): assert len(key) <= self.KEYBYTES # load parameters P = self.PARAMS() P.F.digest_size = self.digest_size P.F.key_length = len(key) P.F.fanout = self.fanout P.F.depth = self.depth P.F.leaf_size = self.leaf_size P.F.node_offset_lo = self.node_offset & MASK32BITS P.F.node_offset_hi = self.node_offset >> 32 P.F.node_depth = self.node_depth P.F.inner_size = self.inner_size # P.F.reserved is not defined in BLAKE2s so we cannot init it # to zeros for both BLAKE2s and BLAKE2b here. Fortunately ctypes # initializes to zeros so we don't have to. :-)) # P.F.reserved = chr(0) * 14 P.F.salt = (self.salt + (chr(0).encode()) * (self.SALTBYTES - len(self.salt))) P.F.person = (self.person + (chr(0).encode()) * (self.PERSONALBYTES - len(self.person))) self.h = [self.IV[i] ^ P.W[i] for i in range(8)] self.totbytes = 0 self.t = [0] * 2 self.f = [0] * 2 self.buflen = 0 self.buf = b'' self.finalized = False self.block_size = self.BLOCKBYTES if key: block = key + (chr(0).encode()) * (self.BLOCKBYTES - len(key)) self.update(block) if self.data: self.update(self.data) # - - - - - - - - - - - - - - - - - - - - - - - - - - - def _compress(self, block): # Dereference these for [very small] speed improvement. # Perhaps more than anything, this makes the code # easier to read. MASKBITS = self.MASKBITS WORDBITS = self.WORDBITS WORDBYTES = self.WORDBYTES IV = self.IV sigma = self.sigma ROT1 = self.ROT1 ROT2 = self.ROT2 ROT3 = self.ROT3 ROT4 = self.ROT4 WB_ROT1 = WORDBITS - ROT1 WB_ROT2 = WORDBITS - ROT2 WB_ROT3 = WORDBITS - ROT3 WB_ROT4 = WORDBITS - ROT4 # convert block (bytes) into 16 LE words m = struct.unpack_from('<16%s' % self.WORDFMT, bytes(block)) v = [0] * 16 v[0:8] = self.h v[8:12] = IV[:4] v[12] = self.t[0] ^ IV[4] v[13] = self.t[1] ^ IV[5] v[14] = self.f[0] ^ IV[6] v[15] = self.f[1] ^ IV[7] # Within the confines of the Python language, this is a # highly optimized version of G(). It differs some from # the formal specification and reference implementation. def G(a, b, c, d): # dereference v[] for another small speed improvement va = v[a] vb = v[b] vc = v[c] vd = v[d] va = (va + vb + msri2) & MASKBITS w = vd ^ va vd = (w >> ROT1) | (w << (WB_ROT1)) & MASKBITS vc = (vc + vd) & MASKBITS w = vb ^ vc vb = (w >> ROT2) | (w << (WB_ROT2)) & MASKBITS va = (va + vb + msri21) & MASKBITS w = vd ^ va vd = (w >> ROT3) | (w << (WB_ROT3)) & MASKBITS vc = (vc + vd) & MASKBITS w = vb ^ vc vb = (w >> ROT4) | (w << (WB_ROT4)) & MASKBITS # re-reference v[] v[a] = va v[b] = vb v[c] = vc v[d] = vd # time to ChaCha for r in range(self.ROUNDS): # resolve as much as possible outside G() and # don't pass as argument, let scope do its job. # Result is a 50% speed increase, but sadly, # "slow" divided by 1.5 is still "slow". :-/ sr = sigma[r] msri2 = m[sr[0]] msri21 = m[sr[1]] G(0, 4, 8, 12) msri2 = m[sr[2]] msri21 = m[sr[3]] G(1, 5, 9, 13) msri2 = m[sr[4]] msri21 = m[sr[5]] G(2, 6, 10, 14) msri2 = m[sr[6]] msri21 = m[sr[7]] G(3, 7, 11, 15) msri2 = m[sr[8]] msri21 = m[sr[9]] G(0, 5, 10, 15) msri2 = m[sr[10]] msri21 = m[sr[11]] G(1, 6, 11, 12) msri2 = m[sr[12]] msri21 = m[sr[13]] G(2, 7, 8, 13) msri2 = m[sr[14]] msri21 = m[sr[15]] G(3, 4, 9, 14) self.h = [self.h[i] ^ v[i] ^ v[i + 8] for i in range(8)] # - - - - - - - - - - - - - - - - - - - - - - - - - - - def update(self, data): assert self.finalized == False BLOCKBYTES = self.BLOCKBYTES datalen = len(data) dataptr = 0 while True: if len(self.buf) >= BLOCKBYTES: self._increment_counter(BLOCKBYTES) self._compress(self.buf[:BLOCKBYTES]) self.buf = self.buf[BLOCKBYTES:] if dataptr < datalen: self.buf += data[dataptr:dataptr + BLOCKBYTES] dataptr += BLOCKBYTES else: break # - - - - - - - - - - - - - - - - - - - - - - - - - - - def final(self): # is there any residue remaining to be processed? if not self.finalized and len(self.buf): self._increment_counter(len(self.buf)) self._set_lastblock() # add padding self.buf += (chr(0).encode()) * (self.BLOCKBYTES - len(self.buf)) # final compress self._compress(self.buf) self.buf = b'' # nothing more (no residue) # convert 8 LE words into digest (bytestring) self.digest_ = struct.pack('<8%s' % self.WORDFMT, *tuple(self.h)) self.finalized = True return self.digest_[:self.digest_size] digest = final def hexdigest(self): return binascii.hexlify(self.final()).decode() # - - - - - - - - - - - - - - - - - - - - - - - - - - - # f0 = 0 if NOT last block, 0xffffffff... if last block # f1 = 0 if sequential mode or (tree mode and NOT last # node), 0xffffffff... if tree mode AND last node def _set_lastblock(self): if self.last_node: self.f[1] = self.MASKBITS self.f[0] = self.MASKBITS def _increment_counter(self, numbytes): self.totbytes += numbytes self.t[0] = self.totbytes & self.MASKBITS self.t[1] = self.totbytes >> self.WORDBITS # - - - - - - - - - - - - - - - - - - - - - - - - - - - # common utility functions def copy(self): return copy.deepcopy(self) #--------------------------------------------------------------- class BLAKE2b(BLAKE2): WORDBITS = 64 WORDBYTES = 8 MASKBITS = MASK64BITS WORDFMT = 'Q' # used in _compress() and final() ROUNDS = 12 BLOCKBYTES = 128 OUTBYTES = 64 KEYBYTES = 64 SALTBYTES = 16 # see also hardcoded value in ParamFields64 PERSONALBYTES = 16 # see also hardcoded value in ParamFields64 IV = [ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 ] ROT1 = 32 ROT2 = 24 ROT3 = 16 ROT4 = 63 # - - - - - - - - - - - - - - - - - - - - - - - - - - - def __init__(self, data=b'', digest_size=64, key=b'', salt=b'', person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, node_depth=0, inner_size=0, last_node=False): assert 1 <= digest_size <= self.OUTBYTES assert len(key) <= self.KEYBYTES assert len(salt) <= self.SALTBYTES assert len(person) <= self.PERSONALBYTES assert 0 <= fanout <= MASK8BITS assert 0 <= depth <= MASK8BITS assert 0 <= leaf_size <= MASK32BITS assert 0 <= node_offset <= MASK64BITS assert 0 <= node_depth <= MASK8BITS assert 0 <= inner_size <= MASK8BITS # - - - - - - - - - - - - - - - - - - - - - - - - - # use ctypes LittleEndianStructure and Union as a # convenient way to organize complex structs, convert # to little endian, and access by words class ParamFields64(LittleEndianStructure): _fields_ = [ ("digest_size", c_ubyte), ("key_length", c_ubyte), ("fanout", c_ubyte), ("depth", c_ubyte), ("leaf_size", c_uint32), ("node_offset_lo", c_uint32), ("node_offset_hi", c_uint32), ("node_depth", c_ubyte), ("inner_size", c_ubyte), ("reserved", c_char * 14), ("salt", c_char * 16), ("person", c_char * 16), ] class Params64(Union): _fields_ = [ ("F", ParamFields64), ("W", c_uint64 * 8), ] # this next makes PARAMS a 'proper' instance variable self.PARAMS = Params64 # key is passed as an argument; all other variables are # defined as instance variables self.digest_size = digest_size self.data = data self.salt = salt self.person = person self.fanout = fanout self.depth = depth self.leaf_size = leaf_size self.node_offset = node_offset self.node_depth = node_depth self.inner_size = inner_size self.last_node = last_node # now call init routine common to BLAKE2b and BLAKE2s self._init(key=key) #--------------------------------------------------------------- class BLAKE2s(BLAKE2): WORDBITS = 32 WORDBYTES = 4 MASKBITS = MASK32BITS WORDFMT = 'L' # used in _compress() and final() ROUNDS = 10 BLOCKBYTES = 64 OUTBYTES = 32 KEYBYTES = 32 SALTBYTES = 8 PERSONALBYTES = 8 IV = [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ] ROT1 = 16 ROT2 = 12 ROT3 = 8 ROT4 = 7 # - - - - - - - - - - - - - - - - - - - - - - - - - - - def __init__(self, data=b'', digest_size=32, key=b'', salt=b'', person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, node_depth=0, inner_size=0, last_node=False): assert 1 <= digest_size <= self.OUTBYTES assert len(key) <= self.KEYBYTES assert len(salt) <= self.SALTBYTES assert len(person) <= self.PERSONALBYTES assert 0 <= fanout <= MASK8BITS assert 0 <= depth <= MASK8BITS assert 0 <= leaf_size <= MASK32BITS assert 0 <= node_offset <= MASK48BITS assert 0 <= node_depth <= MASK8BITS assert 0 <= inner_size <= MASK8BITS # there is a circular class relationship having # to do with defining the values of SALTBYTES and # PERSONALBYTES. By creating an empty class and # loading its contents individually, we get access # to the parent block's scope and have to define the # field's values only once. ...but this can look # confusing. Perhaps it is better to define the # values 16 and 8 twice and annotate the second # occurance. It's not like the values will be # changing often. Which is better? BLAKE2b is # defined twice and BLAKE2s uses the empty class # approach. class ParamFields32(LittleEndianStructure): pass ParamFields32.SALTBYTES = self.SALTBYTES ParamFields32.PERSONALBYTES = self.PERSONALBYTES ParamFields32._fields_ = [ ("digest_size", c_ubyte), ("key_length", c_ubyte), ("fanout", c_ubyte), ("depth", c_ubyte), ("leaf_size", c_uint32), ("node_offset_lo", c_uint32), ("node_offset_hi", c_uint16), ("node_depth", c_ubyte), ("inner_size", c_ubyte), ("salt", c_char * self.SALTBYTES), ("person", c_char * self.PERSONALBYTES), ] class Params32(Union): _fields_ = [ ("F", ParamFields32), ("W", c_uint32 * 8), ] # this next makes PARAMS union a 'proper' instance variable self.PARAMS = Params32 # key is passed as an argument; all other variables are # defined as instance variables self.digest_size = digest_size self.data = data self.salt = salt self.person = person self.fanout = fanout self.depth = depth self.leaf_size = leaf_size self.node_offset = node_offset self.node_depth = node_depth self.inner_size = inner_size self.last_node = last_node # now call init routine common to BLAKE2b and BLAKE2s self._init(key=key) #--------------------------------------------------------------- #--------------------------------------------------------------- #--------------------------------------------------------------- ================================================ FILE: examples/blake2ref.py ================================================ # encoding: utf-8 import struct, binascii, copy from ctypes import * MASK8BITS = 0xff MASK16BITS = 0xffff MASK32BITS = 0xffffffff MASK48BITS = 0xffffffffffff MASK64BITS = 0xffffffffffffffff #--------------------------------------------------------------- class BLAKE2(object): """ BLAKE2 is a base class for BLAKE2b and BLAKE2s """ sigma = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3] ] # only 1st 10 rows are used by BLAKE2s # - - - - - - - - - - - - - - - - - - - - - - - - - - - def __init__(self, digest_size=0, **args): print(""" *********************************************** * You just instantiated a base class. Please * * instantiate either BLAKE2b or BLAKE2s. * *********************************************** """) raise Exception('base class instantiation') # - - - - - - - - - - - - - - - - - - - - - - - - - - - def _init(self, key=b''): assert len(key) <= self.KEYBYTES # load parameters P = self.PARAMS() P.F.digest_size = self.digest_size P.F.key_length = len(key) P.F.fanout = self.fanout P.F.depth = self.depth P.F.leaf_size = self.leaf_size P.F.node_offset_lo = self.node_offset & MASK32BITS P.F.node_offset_hi = self.node_offset >> 32 P.F.node_depth = self.node_depth P.F.inner_size = self.inner_size # P.F.reserved is not defined in BLAKE2s so we cannot init it # to zeros for both BLAKE2s and BLAKE2b here. Fortunately ctypes # initializes to zeros so we don't have to. :-)) # P.F.reserved = chr(0) * 14 P.F.salt = (self.salt + (chr(0).encode()) * (self.SALTBYTES - len(self.salt))) P.F.person = (self.person + (chr(0).encode()) * (self.PERSONALBYTES - len(self.person))) self.h = [self.IV[i] ^ P.W[i] for i in range(8)] self.totbytes = 0 self.t = [0] * 2 self.f = [0] * 2 self.buflen = 0 self.buf = b'' self.finalized = False self.block_size = self.BLOCKBYTES if key: block = key + (chr(0).encode()) * (self.BLOCKBYTES - len(key)) self.update(block) if self.data: self.update(self.data) # - - - - - - - - - - - - - - - - - - - - - - - - - - - def _compress(self, block): # Dereference these for [very small] speed improvement. # Perhaps more than anything, this makes the code # easier to read. MASKBITS = self.MASKBITS WORDBITS = self.WORDBITS WORDBYTES = self.WORDBYTES IV = self.IV sigma = self.sigma ROT1 = self.ROT1 ROT2 = self.ROT2 ROT3 = self.ROT3 ROT4 = self.ROT4 WB_ROT1 = WORDBITS - ROT1 WB_ROT2 = WORDBITS - ROT2 WB_ROT3 = WORDBITS - ROT3 WB_ROT4 = WORDBITS - ROT4 # convert block (bytes) into 16 LE words m = struct.unpack_from('<16%s' % self.WORDFMT, bytes(block)) v = [0] * 16 v[0:8] = self.h v[8:12] = IV[:4] v[12] = self.t[0] ^ IV[4] v[13] = self.t[1] ^ IV[5] v[14] = self.f[0] ^ IV[6] v[15] = self.f[1] ^ IV[7] # Within the confines of the Python language, this is a # highly optimized version of G(). It differs some from # the formal specification and reference implementation. def G(a, b, c, d): # dereference v[] for another small speed improvement va = v[a] vb = v[b] vc = v[c] vd = v[d] va = (va + vb + msri2) & MASKBITS w = vd ^ va vd = (w >> ROT1) | (w << (WB_ROT1)) & MASKBITS vc = (vc + vd) & MASKBITS w = vb ^ vc vb = (w >> ROT2) | (w << (WB_ROT2)) & MASKBITS va = (va + vb + msri21) & MASKBITS w = vd ^ va vd = (w >> ROT3) | (w << (WB_ROT3)) & MASKBITS vc = (vc + vd) & MASKBITS w = vb ^ vc vb = (w >> ROT4) | (w << (WB_ROT4)) & MASKBITS # re-reference v[] v[a] = va v[b] = vb v[c] = vc v[d] = vd # time to ChaCha for r in range(self.ROUNDS): # resolve as much as possible outside G() and # don't pass as argument, let scope do its job. # Result is a 50% speed increase, but sadly, # "slow" divided by 1.5 is still "slow". :-/ sr = sigma[r] msri2 = m[sr[0]] msri21 = m[sr[1]] G(0, 4, 8, 12) msri2 = m[sr[2]] msri21 = m[sr[3]] G(1, 5, 9, 13) msri2 = m[sr[4]] msri21 = m[sr[5]] G(2, 6, 10, 14) msri2 = m[sr[6]] msri21 = m[sr[7]] G(3, 7, 11, 15) msri2 = m[sr[8]] msri21 = m[sr[9]] G(0, 5, 10, 15) msri2 = m[sr[10]] msri21 = m[sr[11]] G(1, 6, 11, 12) msri2 = m[sr[12]] msri21 = m[sr[13]] G(2, 7, 8, 13) msri2 = m[sr[14]] msri21 = m[sr[15]] G(3, 4, 9, 14) self.h = [self.h[i] ^ v[i] ^ v[i + 8] for i in range(8)] # - - - - - - - - - - - - - - - - - - - - - - - - - - - def update(self, data): assert self.finalized == False BLOCKBYTES = self.BLOCKBYTES datalen = len(data) dataptr = 0 while True: if len(self.buf) > BLOCKBYTES: self._increment_counter(BLOCKBYTES) self._compress(self.buf[:BLOCKBYTES]) self.buf = self.buf[BLOCKBYTES:] if dataptr < datalen: self.buf += data[dataptr:dataptr + BLOCKBYTES] dataptr += BLOCKBYTES else: break # - - - - - - - - - - - - - - - - - - - - - - - - - - - def final(self): # is there any residue remaining to be processed? if not self.finalized and len(self.buf): self._increment_counter(len(self.buf)) self._set_lastblock() # add padding self.buf += (chr(0).encode()) * (self.BLOCKBYTES - len(self.buf)) # final compress self._compress(self.buf) self.buf = b'' # nothing more (no residue) # convert 8 LE words into digest (bytestring) self.digest_ = struct.pack('<8%s' % self.WORDFMT, *tuple(self.h)) self.finalized = True return self.digest_[:self.digest_size] digest = final def hexdigest(self): return binascii.hexlify(self.final()).decode() # - - - - - - - - - - - - - - - - - - - - - - - - - - - # f0 = 0 if NOT last block, 0xffffffff... if last block # f1 = 0 if sequential mode or (tree mode and NOT last # node), 0xffffffff... if tree mode AND last node def _set_lastblock(self): if self.last_node: self.f[1] = self.MASKBITS self.f[0] = self.MASKBITS def _increment_counter(self, numbytes): self.totbytes += numbytes self.t[0] = self.totbytes & self.MASKBITS self.t[1] = self.totbytes >> self.WORDBITS # - - - - - - - - - - - - - - - - - - - - - - - - - - - # common utility functions def copy(self): return copy.deepcopy(self) #--------------------------------------------------------------- class BLAKE2b(BLAKE2): WORDBITS = 64 WORDBYTES = 8 MASKBITS = MASK64BITS WORDFMT = 'Q' # used in _compress() and final() ROUNDS = 12 BLOCKBYTES = 128 OUTBYTES = 64 KEYBYTES = 64 SALTBYTES = 16 # see also hardcoded value in ParamFields64 PERSONALBYTES = 16 # see also hardcoded value in ParamFields64 IV = [ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 ] ROT1 = 32 ROT2 = 24 ROT3 = 16 ROT4 = 63 # - - - - - - - - - - - - - - - - - - - - - - - - - - - def __init__(self, data=b'', digest_size=64, key=b'', salt=b'', person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, node_depth=0, inner_size=0, last_node=False): assert 1 <= digest_size <= self.OUTBYTES assert len(key) <= self.KEYBYTES assert len(salt) <= self.SALTBYTES assert len(person) <= self.PERSONALBYTES assert 0 <= fanout <= MASK8BITS assert 0 <= depth <= MASK8BITS assert 0 <= leaf_size <= MASK32BITS assert 0 <= node_offset <= MASK64BITS assert 0 <= node_depth <= MASK8BITS assert 0 <= inner_size <= MASK8BITS # - - - - - - - - - - - - - - - - - - - - - - - - - # use ctypes LittleEndianStructure and Union as a # convenient way to organize complex structs, convert # to little endian, and access by words class ParamFields64(LittleEndianStructure): _fields_ = [ ("digest_size", c_ubyte), ("key_length", c_ubyte), ("fanout", c_ubyte), ("depth", c_ubyte), ("leaf_size", c_uint32), ("node_offset_lo", c_uint32), ("node_offset_hi", c_uint32), ("node_depth", c_ubyte), ("inner_size", c_ubyte), ("reserved", c_char * 14), ("salt", c_char * 16), ("person", c_char * 16), ] class Params64(Union): _fields_ = [ ("F", ParamFields64), ("W", c_uint64 * 8), ] # this next makes PARAMS a 'proper' instance variable self.PARAMS = Params64 # key is passed as an argument; all other variables are # defined as instance variables self.digest_size = digest_size self.data = data self.salt = salt self.person = person self.fanout = fanout self.depth = depth self.leaf_size = leaf_size self.node_offset = node_offset self.node_depth = node_depth self.inner_size = inner_size self.last_node = last_node # now call init routine common to BLAKE2b and BLAKE2s self._init(key=key) #--------------------------------------------------------------- class BLAKE2s(BLAKE2): WORDBITS = 32 WORDBYTES = 4 MASKBITS = MASK32BITS WORDFMT = 'L' # used in _compress() and final() ROUNDS = 10 BLOCKBYTES = 64 OUTBYTES = 32 KEYBYTES = 32 SALTBYTES = 8 PERSONALBYTES = 8 IV = [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ] ROT1 = 16 ROT2 = 12 ROT3 = 8 ROT4 = 7 # - - - - - - - - - - - - - - - - - - - - - - - - - - - def __init__(self, data=b'', digest_size=32, key=b'', salt=b'', person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, node_depth=0, inner_size=0, last_node=False): assert 1 <= digest_size <= self.OUTBYTES assert len(key) <= self.KEYBYTES assert len(salt) <= self.SALTBYTES assert len(person) <= self.PERSONALBYTES assert 0 <= fanout <= MASK8BITS assert 0 <= depth <= MASK8BITS assert 0 <= leaf_size <= MASK32BITS assert 0 <= node_offset <= MASK48BITS assert 0 <= node_depth <= MASK8BITS assert 0 <= inner_size <= MASK8BITS # there is a circular class relationship having # to do with defining the values of SALTBYTES and # PERSONALBYTES. By creating an empty class and # loading its contents individually, we get access # to the parent block's scope and have to define the # field's values only once. ...but this can look # confusing. Perhaps it is better to define the # values 16 and 8 twice and annotate the second # occurance. It's not like the values will be # changing often. Which is better? BLAKE2b is # defined twice and BLAKE2s uses the empty class # approach. class ParamFields32(LittleEndianStructure): pass ParamFields32.SALTBYTES = self.SALTBYTES ParamFields32.PERSONALBYTES = self.PERSONALBYTES ParamFields32._fields_ = [ ("digest_size", c_ubyte), ("key_length", c_ubyte), ("fanout", c_ubyte), ("depth", c_ubyte), ("leaf_size", c_uint32), ("node_offset_lo", c_uint32), ("node_offset_hi", c_uint16), ("node_depth", c_ubyte), ("inner_size", c_ubyte), ("salt", c_char * self.SALTBYTES), ("person", c_char * self.PERSONALBYTES), ] class Params32(Union): _fields_ = [ ("F", ParamFields32), ("W", c_uint32 * 8), ] # this next makes PARAMS union a 'proper' instance variable self.PARAMS = Params32 # key is passed as an argument; all other variables are # defined as instance variables self.digest_size = digest_size self.data = data self.salt = salt self.person = person self.fanout = fanout self.depth = depth self.leaf_size = leaf_size self.node_offset = node_offset self.node_depth = node_depth self.inner_size = inner_size self.last_node = last_node # now call init routine common to BLAKE2b and BLAKE2s self._init(key=key) #--------------------------------------------------------------- #--------------------------------------------------------------- #--------------------------------------------------------------- ================================================ FILE: examples/dsa_sha256_cryptopp.cpp ================================================ #include #include #include #include #include #include #include #include #include #include using std::cout; using std::cerr; using std::endl; using CryptoPP::Integer; using CryptoPP::DSA2; using CryptoPP::SHA256; using CryptoPP::StringSource; using CryptoPP::StringSink; using CryptoPP::SignerFilter; using CryptoPP::SignatureVerificationFilter; using CryptoPP::HexEncoder; using CryptoPP::HexDecoder; using CryptoPP::Redirector; using CryptoPP::ArraySink; typedef DSA2 DSA; //typedef DSA2 DSA0; // in order to implement the -h flag later. It appears finally NullHash is not the identity function, TODO: look into another solution #include using std::string; // for optget: #include bool signing; int main(int argc, char* argv[]) { // Our args int optind = 1; /* string hash; int hash_provided = 0; // To handle the flags: int c; extern char* optarg; extern int optind, optopt, opterr; while ((c = getopt(argc, argv, ":h:")) != -1) { switch (c) { case 'h': StringSource(string(optarg), true, new HexDecoder( new StringSink(hash))); hash_provided = 1; break; case ':': // -h without hash printf("-h without blen"); return 1; break; case '?': printf("unknown arg %c\n", optopt); return 1; break; } } */ if (argc - optind == 6) { signing = 1; } else if (argc - optind == 7) { signing = 0; } else { cout << "usage: \t" << argv[0] << " P, Q, G, Y, X, Msg\nor \t" << argv[0] << " P, Q, G, Y, R, S, Msg\n" << endl; return 1; } try { const Integer P(string(argv[optind]).append("h").c_str()); const Integer Q(string(argv[optind + 1]).append("h").c_str()); const Integer G(string(argv[optind + 2]).append("h").c_str()); const Integer Y(string(argv[optind + 3]).append("h").c_str()); string message; StringSource(string(argv[argc - 1]), true, new HexDecoder( new StringSink(message))); string signature; DSA::PrivateKey privateKey; DSA::PublicKey publicKey; CryptoPP::AutoSeededRandomPool rng; privateKey.Initialize(rng, P, Q, G); publicKey.AssignFrom(privateKey); publicKey.SetPublicElement(Y); if (signing) { const Integer X(string(argv[optind + 4]).append("h").c_str()); privateKey.SetPrivateExponent(X); if (!privateKey.Validate(rng, 3)) { cerr << "DSA privateKey key validation failed after setting private parameter." << endl; return 1; } DSA::Signer signer(privateKey); StringSource ss1(message, true, new SignerFilter(rng, signer, new HexEncoder(new StringSink(signature), false)) // SignerFilter ); // StringSource int slen = signature.length() / 2; // Transorming from IEEE P1363 format into r and s: cout << signature.substr(0, slen) << "\n" << signature.substr(slen, slen) << endl; } else { if (!publicKey.Validate(rng, 3)) { cerr << "DSA publicKey key validation failed" << endl; return 1; } // Transorming into IEEE P1363 format: StringSource(string(argv[optind + 4]) + string(argv[optind + 5]), true, new HexDecoder( new StringSink(signature))); DSA::Verifier verifier(publicKey); bool result = false; StringSource ss(message + signature, true, new SignatureVerificationFilter( verifier, new ArraySink( (byte*)&result, sizeof(result)), SignatureVerificationFilter::PUT_RESULT | SignatureVerificationFilter::SIGNATURE_AT_END)); if (true == result) { cout << "true" << endl; } else { cout << "false" << endl; } } } catch (CryptoPP::Exception& e) { cout << "ERROR" << endl; cerr << e.what() << endl; return 1; } return 0; } ================================================ FILE: examples/dsa_sha256_go.go ================================================ package main import ( "crypto/dsa" "crypto/rand" "crypto/sha256" "encoding/hex" "flag" "fmt" "hash" "log" "math/big" "strings" ) var custom_hash = flag.String("h", "", "If one want to specifiy the hash directly") // fromBase16 is a helper method to use the prime in hex form, inspired from crypto/rsa/rsa_test.go func fromBase16(base16 string) *big.Int { i, ok := new(big.Int).SetString(base16, 16) if !ok { log.Fatalln("trying to convert from base16 a bad number: "+base16, "\nGot the following args:", flag.Args()) } return i } func main() { flag.Parse() // The hash used var h hash.Hash h = sha256.New() var signing bool switch { case len(flag.Args()) == 7: signing = false case len(flag.Args()) == 6: signing = true default: log.Fatal("Please provide P, Q, G, Y, X, Msg or P, Q, G, Y, R, S, Msg as arguments in order to respectively sign Msg or verify a signature for Msg.") } // Key instanciation privatekey := new(dsa.PrivateKey) pubkey := new(dsa.PublicKey) pubkey.P = fromBase16(flag.Arg(0)) pubkey.Q = fromBase16(flag.Arg(1)) pubkey.G = fromBase16(flag.Arg(2)) pubkey.Y = fromBase16(flag.Arg(3)) // we need the byte length of the subgroup to comply to FIPS 186-3 sec. 4.6 // recommended truncation. hlen := (pubkey.Q.BitLen() + 7) / 8 // msg is always in latest position // we are decoding from hex to have truly random messages msg, err := hex.DecodeString(flag.Arg(len(flag.Args()) - 1)) if err != nil { panic(err) } r := big.NewInt(0) s := big.NewInt(0) // We handle the hashing of the data: h.Write(msg) var signhash []byte if *custom_hash == "" { // if the flag -h is not set, its default is "" and we hash the message signhash = h.Sum(nil) } else { var err error signhash, err = hex.DecodeString(*custom_hash) if err != nil { panic(err) } } if signing { // private key instanciation: privatekey.PublicKey = *pubkey privatekey.X = fromBase16(flag.Arg(4)) // If signhash is longer than the byte-length of the subgroup, it should // be truncated to that length as per FIPS 186-3 sec. 4.6, but Sign does // not handle this directly. It returns the signature as a pair of big integers. r, s, serr := dsa.Sign(rand.Reader, privatekey, signhash[:hlen]) if serr != nil { log.Fatalln(serr) } // We first output R, then S with a newline in between as required by // the ECDSA interface answerR := leftPad(r.Text(16), 20) answerS := leftPad(s.Text(16), 20) fmt.Printf("%s\n%s\n", answerR, answerS) } else { // if we are not signing, we are verifying : r = fromBase16(flag.Arg(4)) s = fromBase16(flag.Arg(5)) verifystatus := dsa.Verify(pubkey, signhash[:hlen], r, s) fmt.Println(verifystatus) } } // leftPad will ensure the string are in hexadecimal form and satisfy with the // DSA signature length of 160bits. func leftPad(text string, size int) string { n := len(text) size = 2 * size if n > size { n = size } return strings.Repeat("0", size-n) + text } ================================================ FILE: examples/dsa_sha256_java.java ================================================ // Please, note that you will need to add a folder called libs here and put // the bouncycastle file bcprov-jdk15on-155.jar in it. // Otherwise the wrapper and the makefile won't work. import java.security.PrivateKey; import java.security.PublicKey; import java.security.KeyFactory; import java.security.SecureRandom; import java.security.Security; import java.math.BigInteger; import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.crypto.Cipher; import javax.xml.bind.DatatypeConverter; import java.security.KeyPairGenerator; import java.security.KeyPair; import java.security.Signature; import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPublicKey; import java.security.spec.DSAPrivateKeySpec; import java.security.spec.DSAPublicKeySpec; import org.bouncycastle.crypto.params.DSAKeyParameters; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.DSAParameters; import java.util.Arrays; import org.bouncycastle.crypto.params.DSAKeyGenerationParameters; import org.bouncycastle.crypto.generators.DSAKeyPairGenerator; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; public class dsa_sha256_java { public static byte[] toByteArray(String s) { return DatatypeConverter.parseHexBinary(s); } private static BigInteger extractR(byte[] signature) throws Exception { int lengthR = signature[3]; return new BigInteger(Arrays.copyOfRange(signature, 4, 4 + lengthR)); } private static BigInteger extractS(byte[] signature) throws Exception { int lengthR = signature[3]; int startS = 4 + lengthR; int lengthS = signature[startS + 1]; return new BigInteger(Arrays.copyOfRange(signature, startS + 2, startS + 2 + lengthS)); } public static void main(String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); SecureRandom random = new SecureRandom(); if (args.length != 7 && args.length != 6) { System.out.println(args.length); throw new Exception("Wrong args length"); } // Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC"); // KeyFactory kf = KeyFactory.getInstance("RSA"); byte[] input = toByteArray(args[args.length-1]); BigInteger p = new BigInteger(args[0], 16); BigInteger q = new BigInteger(args[1], 16); BigInteger g = new BigInteger(args[2], 16); KeyFactory kf = KeyFactory.getInstance("DSA"); Signature signer = Signature.getInstance("SHA256WITHDSA"); if (args.length == 6) { BigInteger y = new BigInteger(args[3], 16); BigInteger x = new BigInteger(args[4], 16); DSAPrivateKey priv = (DSAPrivateKey) kf.generatePrivate(new DSAPrivateKeySpec(x, p, q, g)); // DSAParameters paramdsa = new DSAParameters(p, q, g) ; // DSAKeyGenerationParameters test = new DSAKeyGenerationParameters(new SecureRandom(),paramdsa); // DSAKeyPairGenerator gen = new DSAKeyPairGenerator(); // gen.init(test); // AsymmetricCipherKeyPair testGenKey = (AsymmetricCipherKeyPair) gen.generateKeyPair(); // DSAKeyParameters testKey = (DSAKeyParameters) testGenKey.getPublic(); // System.out.println(testKey.getParameters().getG()); signer.initSign(priv); // generate a signature signer.update(input); byte[] signature = signer.sign(); String r = String.format("%040x", (extractR(signature))); String s = String.format("%040x", (extractS(signature))); System.out.println(r); System.out.println(s); } else { BigInteger y = new BigInteger(args[3], 16); BigInteger r = new BigInteger(args[4], 16); BigInteger s = new BigInteger(args[5], 16); DSAPublicKey pubKey = (DSAPublicKey) kf.generatePublic(new DSAPublicKeySpec(y, p, q, g)); // verify a signature signer.initVerify(pubKey); signer.update(input); // need to change that to use our values // convert (r, s) to ASN.1 DER encoding // assuming you have r and s as !!positive!! BigIntegers byte[] rb = r.toByteArray(); byte[] sb = s.toByteArray(); // sign-padded if necessary // these lines are more verbose than necessary to show the structure // compiler will fold or you can do so yourself int off = (2 + 2) + rb.length; int tot = off + (2 - 2) + sb.length; byte[] der = new byte[tot + 2]; der[0] = 0x30; der[1] = (byte) (tot & 0xff); der[2 + 0] = 0x02; der[2 + 1] = (byte) (rb.length & 0xff); System.arraycopy(rb, 0, der, 2 + 2, rb.length); der[off + 0] = 0x02; der[off + 1] = (byte) (sb.length & 0xff); System.arraycopy(sb, 0, der, off + 2, sb.length); if (signer.verify(der)) { System.out.println("true"); } else { System.out.println("false"); } } } } ================================================ FILE: examples/dsa_sha256_java_wrapper.go ================================================ // Please, note that you will need to add a folder called libs here and put // the bouncycastle file bcprov-jdk15on-156.jar in it. // Otherwise the wrapper and the makefile won't work. package main import ( "fmt" "log" "os" "os/exec" "strings" ) func main() { arg := []string{"-cp", "./:./examples/:./examples/libs/bcprov-jdk15on-156.jar:./libs/bcprov-jdk15on-156.jar", "dsa_sha256_java"} arg = append(arg, os.Args[1:]...) cmd := exec.Command("java", arg...) out, err := cmd.CombinedOutput() if err != nil { fmt.Println(strings.TrimSpace(string(out))) log.Fatal(err) } fmt.Println(strings.TrimSpace(string(out))) } ================================================ FILE: examples/dsa_sha256_openssl.c ================================================ #include #include #include #include #include #include "openssl/bn.h" #include "openssl/dsa.h" #include "openssl/engine.h" #include "openssl/sha.h" #define HASH_SIZE 32 void unhex(char* hex, unsigned char* in, size_t ilen) { for (size_t i = 0; i < ilen; ++i) { sscanf(hex, "%2hhx", &in[i]); hex += 2; } } void printBN(BIGNUM *r) { char* out = BN_bn2hex(r); const char *padding="00000000000000000000000000000000000000000"; int padLen1 = 40 - strlen(out); if(padLen1 < 0) padLen1 = 0; printf("%*.*s%s\n", padLen1, padLen1, padding, out); OPENSSL_free(out); } int main(int argc, char* argv[]) { // Our args size_t blen = 0; int success = 0; uint8_t* hash; int signing; int hash_provided = 0; // To handle the flags: int c; extern char* optarg; extern int optind, optopt, opterr; while ((c = getopt(argc, argv, ":h:")) != -1) { switch (c) { case 'h': hash = (uint8_t*)malloc(strlen(optarg) / 2); blen = strlen(optarg) / 2; unhex(optarg, hash, blen); // unsafe for the memory, if optarg is bigger than hash! hash_provided = 1; break; case ':': // -h without hash printf("-h without hash"); success = -1; break; case '?': printf("unknown arg %c\n", optopt); success = -1; break; } } if (argc - optind == 6) { signing = 1; } else if (argc - optind == 7) { signing = 0; } else { printf("usage: \t%s P, Q, G, Y, X, Msg\nor \t%s P, Q, G, Y, R, S, Msg\n", argv[0], argv[0]); return -1; } // Handle the hash value if (hash_provided != 1) { // then we must hash our message, flag -h not provided size_t tlen = strlen(argv[argc - 1]) / 2; // since it is an hexa string uint8_t* nhex = (uint8_t*)malloc(tlen); unhex(argv[argc - 1], nhex, tlen); // we convert from hex to bin hash = (uint8_t*)malloc(HASH_SIZE); SHA256(nhex, tlen, hash); free(nhex); blen = HASH_SIZE; } // OpenSSL stuff: int ret; DSA_SIG* sig; DSA* key = DSA_new(); BIGNUM* x = BN_new(); BIGNUM* y = BN_new(); BIGNUM* p = BN_new(); BIGNUM* q = BN_new(); BIGNUM* g = BN_new(); if (!BN_hex2bn(&p, argv[optind])) { printf("Problem while decoding p:\n%s\n", argv[optind]); return -1; } if (!BN_hex2bn(&q, argv[optind + 1])) { printf("Problem while decoding q:\n%s\n", argv[optind + 1]); return -1; } if (!BN_hex2bn(&g, argv[optind + 2])) { printf("Problem while decoding g:\n%s\n", argv[optind + 2]); return -1; } if (!BN_hex2bn(&y, argv[optind + 3])) { printf("Problem while decoding y:\n%s\n", argv[optind + 3]); return -1; } key->p = BN_dup(p); key->q = BN_dup(q); key->g = BN_dup(g); key->pub_key = BN_dup(y); if (signing) { if (!BN_hex2bn(&x, argv[optind + 4])) { printf("Problem while decoding x:\n%s\n", argv[optind + 4]); return -1; } key->priv_key = BN_dup(x); sig = DSA_do_sign(hash, blen, key); if (sig == NULL) { printf("Failed to sign with those args.\n"); return -1; } printBN(sig->r); printBN(sig->s); } else { sig = DSA_SIG_new(); if (!BN_hex2bn(&sig->r, argv[optind + 4])) { printf("Problem while decoding r:\n%s\n", argv[optind + 4]); return -1; } if (!BN_hex2bn(&sig->s, argv[optind + 5])) { printf("Problem while decoding s:\n%s\n", argv[optind + 5]); return -1; } key->priv_key = NULL; // since we are verifying ret = DSA_do_verify(hash, blen, sig, key); if (ret == -1) { /* error */ printf(" failure DSA_do_verify returned -1"); success = -1; } else if (ret == 0) /* then the signature is wrong */ { printf("False\n"); } else /* ret == 1, so signature is okay */ { printf("True\n"); } } DSA_SIG_free(sig); DSA_free(key); BN_free(x); BN_free(y); BN_free(p); BN_free(q); BN_free(g); free(hash); return success; } ================================================ FILE: examples/dsa_sha256_pycrypto.py ================================================ #!/usr/bin/env python3 from Crypto.Random import random from Crypto.PublicKey import DSA from Crypto.Hash import SHA256 import sys import binascii if len(sys.argv) == 8: signing = False elif len(sys.argv) == 7: signing = True else: print("Please provide P, Q, G, Y, X, Msg or P, Q, G, Y, R, S, Msg as arguments", len(sys.argv)) sys.exit(1) q = int(sys.argv[2], 16) p = int(sys.argv[1], 16) g =int(sys.argv[3], 16) pub_k = int(sys.argv[4], 16) message = binascii.unhexlify(sys.argv.pop()) if signing: priv_k = int(sys.argv[5], 16) params = ( pub_k, g, p, q, priv_k) else: params = ( pub_k, g, p, q ) r = int(sys.argv[5], 16) s = int(sys.argv[6], 16) signature = (r, s) key = DSA.construct(params) hashed = SHA256.new(message).digest() hlen = int((q.bit_length() + 7) / 8) k = random.StrongRandom().randint(1,key.q-1) if signing: sign = key.sign(hashed[:hlen], k) print(format(sign[0],'x').zfill(40)) print(format(sign[1],'x').zfill(40)) else: if key.verify(hashed[:hlen], signature): print("true") else: print("false") ================================================ FILE: examples/ecdsa_p256_sha256_cryptography.py ================================================ #!/usr/bin/env python3 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric import utils import sys import binascii curve = ec.SECP256R1() algo = ec.ECDSA(hashes.SHA256()) if len(sys.argv) == 6: signing = False elif len(sys.argv) == 5: signing = True else: print("Please provide X, Y, R, S, Msg or X, Y, D, Msg as arguments") sys.exit(1) pubnum = ec.EllipticCurvePublicNumbers( int(sys.argv[1], 16), int(sys.argv[2], 16), curve) # Msg is in last args: data = binascii.unhexlify(sys.argv.pop()) if signing: privateKey = ec.EllipticCurvePrivateNumbers(int( sys.argv[3], 16), pubnum).private_key(default_backend()) signer = privateKey.signer(algo) signer.update(data) signature = signer.finalize() (r, s) = utils.decode_dss_signature(signature) print(format(r, 'x')) print(format(s, 'x')) else: public_key = pubnum.public_key(default_backend()) signature = utils.encode_dss_signature( int(sys.argv[3], 16), int(sys.argv[4], 16)) verifier = public_key.verifier(signature, algo) verifier.update(data) print(verifier.verify()) ================================================ FILE: examples/ecdsa_p256_sha256_cryptopp.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include using std::string; using std::cout; using std::cerr; using std::endl; // for optget: #include #include #include using CryptoPP::AutoSeededRandomPool; using CryptoPP::AES; using CryptoPP::Integer; using CryptoPP::SHA256; using CryptoPP::HexEncoder; using CryptoPP::HexDecoder; using CryptoPP::StringSource; using CryptoPP::StringSink; using CryptoPP::ArraySink; using CryptoPP::SignerFilter; using CryptoPP::SignatureVerificationFilter; using CryptoPP::ECDSA; using CryptoPP::ECP; using CryptoPP::DL_GroupParameters_EC; using CryptoPP::OID; bool signing; using namespace CryptoPP; // from https://stackoverflow.com/a/45195519/2757014 template class IdentityHash : public HashTransformation { public: CRYPTOPP_CONSTANT(DIGESTSIZE = HASH_SIZE) static const char * StaticAlgorithmName() { return "IdentityHash"; } IdentityHash() : m_digest(HASH_SIZE), m_idx(0), m_size(0) {} virtual unsigned int DigestSize() const { return HASH_SIZE; } virtual void Update(const byte *input, size_t length) { size_t sz = STDMIN(HASH_SIZE, SaturatingSubtract(length, m_size)); ::memcpy(&m_digest[m_idx], input, sz); m_idx += sz; m_size += sz; } virtual void TruncatedFinal(byte *digest, size_t digestSize) { if (m_size != HASH_SIZE) Exception(Exception::OTHER_ERROR, "Input size must be " + IntToString(HASH_SIZE)); ThrowIfInvalidTruncatedSize(digestSize); ::memcpy(digest, m_digest, digestSize); } private: SecByteBlock m_digest; size_t m_idx, m_size; }; int main(int argc, char* argv[]) { // Our args int c; string custom_hash; extern char* optarg; extern int optind, optopt, opterr; while ((c = getopt(argc, argv, ":h:")) != -1) { switch (c) { case 'h': StringSource(string(optarg), true, new HexDecoder( new StringSink(custom_hash))); break; case ':': // -h without hash length printf("-h without hash"); break; case '?': printf("unknown arg %c\n", optopt); return -1; } } if (argc - optind == 4) { signing = 1; } else if (argc - optind == 5) { signing = 0; } else { cout << "usage: \t" << argv[0] << " X, Y, D, Msg\nor \t" << argv[0] << " X, Y, R, S, Msg\n" << endl; return -1; } try { string message; StringSource(string(argv[argc - 1]), true, new HexDecoder( new StringSink(message))); string signature; ECDSA::PrivateKey* privKey; ECDSA::PublicKey* pubKey; if (custom_hash != ""){ pubKey = new ECDSA >::PublicKey; privKey = new ECDSA >::PrivateKey; } else { pubKey = new ECDSA::PublicKey; privKey = new ECDSA::PrivateKey; } CryptoPP::AutoSeededRandomPool rng; if (signing) { const Integer D(string(argv[optind + 2]).append("h").c_str()); privKey->Initialize(CryptoPP::ASN1::secp256r1(), D); if (!privKey->Validate(rng, 3)) { cerr << "ECDSA privateKey key validation failed after setting private parameter." << endl; return -1; } if (custom_hash != ""){ ECDSA >::Signer signer(*privKey); StringSource ss1(custom_hash, true, new SignerFilter(rng, signer, new HexEncoder(new StringSink(signature), false)) // SignerFilter ); // StringSource } else { ECDSA::Signer signer(*privKey); StringSource ss1(message, true, new SignerFilter(rng, signer, new HexEncoder(new StringSink(signature), false)) // SignerFilter ); // StringSource } int slen = signature.length() / 2; // Transorming from IEEE P1363 format into r and s: cout << signature.substr(0, slen) << "\n" << signature.substr(slen, slen) << endl; } else { const Integer X(string(argv[optind]).append("h").c_str()); const Integer Y(string(argv[optind + 1]).append("h").c_str()); ECP::Point pt(X,Y); pubKey->Initialize(CryptoPP::ASN1::secp256r1(), pt); if (!pubKey->Validate(rng, 3)) { cerr << "ECDSA publicKey key validation failed" << endl; return -1; } // Transorming into IEEE P1363 format: StringSource(string(argv[optind + 2]) + string(argv[optind + 3]), true, new HexDecoder( new StringSink(signature))); bool result = false; if (custom_hash != ""){ ECDSA >::Verifier verifier(*pubKey); StringSource ss(custom_hash + signature, true, new SignatureVerificationFilter( verifier, new ArraySink( (byte*)&result, sizeof(result) ), //ArraySink SignatureVerificationFilter::PUT_RESULT | SignatureVerificationFilter::SIGNATURE_AT_END) );// StringSource } else { ECDSA::Verifier verifier(*pubKey); StringSource ss(message + signature, true, new SignatureVerificationFilter( verifier, new ArraySink( (byte*)&result, sizeof(result) ), //ArraySink SignatureVerificationFilter::PUT_RESULT | SignatureVerificationFilter::SIGNATURE_AT_END) );// StringSource } if (true == result) { cout << "true" << endl; } else { cout << "false" << endl; } } } catch (CryptoPP::Exception& e) { cout << "ERROR" << endl; cerr << e.what() << endl; return -1; } return 0; } ================================================ FILE: examples/ecdsa_p256_sha256_go.go ================================================ package main import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" "encoding/hex" "flag" "fmt" "hash" "log" "math/big" "strings" ) var custom_hash = flag.String("h", "", "If one want to specifiy the hash directly") // fromBase16 is a helper method to use the prime in hex form, inspired from crypto/rsa/rsa_test.go func fromBase16(base16 string) *big.Int { i, ok := new(big.Int).SetString(base16, 16) if !ok { log.Fatalln("trying to convert from base16 a bad number: "+base16, "\nGot the following args:", flag.Args()) } return i } func main() { flag.Parse() // The curve used and the hash used pubkeyCurve := elliptic.P256() var h hash.Hash h = sha256.New() var signing bool switch { case len(flag.Args()) == 5: signing = false case len(flag.Args()) == 4: signing = true default: log.Fatal("Please provide X, Y, Sign or X, Y, D, Msg as arguments") } // Key instanciation privatekey := new(ecdsa.PrivateKey) pubkey := new(ecdsa.PublicKey) pubkey.Curve = pubkeyCurve pubkey.X = fromBase16(flag.Arg(0)) pubkey.Y = fromBase16(flag.Arg(1)) // msg is always in latest position // we are decoding from hex to have truly random messages msg, err := hex.DecodeString(flag.Arg(len(flag.Args()) - 1)) if err != nil { panic(err) } r := big.NewInt(0) s := big.NewInt(0) h.Write(msg) var signhash []byte if *custom_hash == "" { // if the flag -h is not set, its default is "" and we hash the message signhash = h.Sum(nil) } else { // even if specifying the hash is discutably useful in the non-deterministic ECDSA case var err error signhash, err = hex.DecodeString(*custom_hash) if err != nil { panic(err) } } if signing { // private key instanciation: privatekey.PublicKey = *pubkey privatekey.D = fromBase16(flag.Arg(2)) // If signhash is longer than the bit-length of the private key's curve // order, signhash will be truncated to that length. It returns the // signature as a pair of big integers. r, s, serr := ecdsa.Sign(rand.Reader, privatekey, signhash) if serr != nil { log.Fatalln(serr) } // we first output R, then S with a newline in between as required by // the ECDSA interface. TODO: check if it needs leftpadding or not. fmt.Printf("%s\n%s\n", leftPad(r.Text(16), 32), leftPad(s.Text(16), 32)) } else { // if we are not signing, we are verifying : r = fromBase16(flag.Arg(2)) s = fromBase16(flag.Arg(3)) verifystatus := ecdsa.Verify(pubkey, signhash, r, s) fmt.Println(verifystatus) } } // leftPad will ensure the string are in hexadecimal form and satisfy with the // ECDSA signature length. func leftPad(text string, size int) string { n := len(text) size = 2 * size if n > size { n = size } return strings.Repeat("0", size-n) + text } ================================================ FILE: examples/ecdsa_p256_sha256_java.java ================================================ // Please, note that you will need to add a folder called libs here and put // the bouncycastle file bcprov-jdk15on-155.jar in it. // Otherwise the wrapper and the makefile won't work. import java.security.PrivateKey; import java.security.PublicKey; import java.security.KeyFactory; import java.security.SecureRandom; import java.security.Security; import java.math.BigInteger; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.MessageDigest; import java.security.Signature; import java.security.SignatureException; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; import java.security.spec.ECPublicKeySpec; import java.security.spec.ECPrivateKeySpec; import org.bouncycastle.jce.ECNamedCurveTable; import java.util.Arrays; import javax.xml.bind.DatatypeConverter; import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.bouncycastle.jce.spec.ECNamedCurveSpec; public class ecdsa_p256_sha256_java { public static byte[] toByteArray(String s) { return DatatypeConverter.parseHexBinary(s); } // using Wycheproof code, since if it exists, don't reinvent it. public static BigInteger extractR(byte[] signature) throws Exception { int startR = (signature[1] & 0x80) != 0 ? 3 : 2; int lengthR = signature[startR + 1]; return new BigInteger(Arrays.copyOfRange(signature, startR + 2, startR + 2 + lengthR)); } // using Wycheproof code, since if it exists, don't reinvent it. public static BigInteger extractS(byte[] signature) throws Exception { int startR = (signature[1] & 0x80) != 0 ? 3 : 2; int lengthR = signature[startR + 1]; int startS = startR + 2 + lengthR; int lengthS = signature[startS + 1]; return new BigInteger(Arrays.copyOfRange(signature, startS + 2, startS + 2 + lengthS)); } public static void main(String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); SecureRandom random = new SecureRandom(); if (args.length != 5 && args.length != 4) { System.out.println(args.length); throw new Exception("Wrong args length"); } byte[] input = toByteArray(args[args.length-1]); KeyFactory kf = KeyFactory.getInstance("ECDSA","BC"); Signature signer = Signature.getInstance("SHA256withECDSA","BC"); String name = "secp256r1"; // inspired from https://stackoverflow.com/questions/33218674/how-to-make-a-bouncy-castle-ecpublickey ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(name); ECParameterSpec params = new ECNamedCurveSpec(name, parameterSpec.getCurve(),parameterSpec.getG(), parameterSpec.getN(), parameterSpec.getH(), parameterSpec.getSeed()); if (args.length == 4) { ECPrivateKey priKey = (ECPrivateKey) kf.generatePrivate( new ECPrivateKeySpec( new BigInteger(args[2],16), params) ); signer.initSign(priKey); // generate a signature signer.update(input); byte[] signature = signer.sign(); String r = String.format("%064x", (extractR(signature))); String s = String.format("%064x", (extractS(signature))); System.out.println(r); System.out.println(s); } else { BigInteger r = new BigInteger(args[2], 16); BigInteger s = new BigInteger(args[3], 16); ECPoint point = new ECPoint( new BigInteger(args[0], 16), new BigInteger(args[1], 16) ); ECPublicKey pubKey = (ECPublicKey) kf.generatePublic(new ECPublicKeySpec(point, params)); // verify a signature signer.initVerify(pubKey); signer.update(input); // using Wycheproof code, since if it exists, don't reinvent it. byte[] rb = r.toByteArray(); byte[] sb = s.toByteArray(); int off = (2 + 2) + rb.length; int tot = off + (2 - 2) + sb.length; byte[] der = new byte[tot + 2]; der[0] = 0x30; der[1] = (byte) (tot & 0xff); der[2 + 0] = 0x02; der[2 + 1] = (byte) (rb.length & 0xff); System.arraycopy(rb, 0, der, 2 + 2, rb.length); der[off + 0] = 0x02; der[off + 1] = (byte) (sb.length & 0xff); System.arraycopy(sb, 0, der, off + 2, sb.length); if (signer.verify(der)) { System.out.println("true"); } else { System.out.println("false"); } } } } ================================================ FILE: examples/ecdsa_p256_sha256_java_wrapper.go ================================================ // Please, note that you will need to add a folder called libs here and put // the bouncycastle file bcprov-jdk15on-156.jar in it. // Otherwise the wrapper and the makefile won't work. package main import ( "fmt" "log" "os" "os/exec" "strings" ) func main() { arg := []string{"-cp", "./:./examples/:./examples/libs/bcprov-jdk15on-156.jar:./libs/bcprov-jdk15on-156.jar", "ecdsa_p256_sha256_java"} arg = append(arg, os.Args[1:]...) cmd := exec.Command("java", arg...) out, err := cmd.CombinedOutput() if err != nil { fmt.Println(strings.TrimSpace(string(out))) log.Fatal(err) } fmt.Println(strings.TrimSpace(string(out))) } ================================================ FILE: examples/ecdsa_p256_sha256_mbedtls.c ================================================ #include "ecdsa_p256_sha256_mbedtls.h" #define ECPARAMS MBEDTLS_ECP_DP_SECP256R1 #define HASH_TYPE MBEDTLS_MD_SHA256 int main(int argc, char* argv[]) { // Parsing argument: int c; int blen_tested = 0; int hash_provided = 0; unsigned char hash[MBEDTLS_MD_MAX_SIZE]; memset(hash, 0, sizeof(hash)); extern char* optarg; extern int optind, optopt, opterr; while ((c = getopt(argc, argv, ":h:")) != -1) { switch (c) { case 'h': unhex(hash, optarg); // unsafe for the memory, if optarg is bigger than hash! blen_tested = strlen(optarg) / 2; hash_provided = 1; break; case ':': // -h without hash length printf("-h without hash"); break; case '?': printf("unknown arg %c\n", optopt); return -1; } } int ret = 1; int signing = 0; if (argc - optind == 4) { signing = 1; } else if (argc - optind == 5) { signing = 0; } else { printf("usage: \t%s X, Y, D, M\nor \t%s X, Y, R, S, M\n", argv[0], argv[0]); return -1; } // the MbedTLS variables: mbedtls_ecdsa_context signing_ctx; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; const char* pers = "ecdsa"; ((void)argv); // we must unhexlify the data: const char* str = argv[argc - 1]; unsigned char* msg = (unsigned char*)malloc(strlen(str) / 2 * sizeof(unsigned char)); size_t mlen; mlen = unhex(msg, str); // We initialize all the variables: mbedtls_ecdsa_init(&signing_ctx); mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_mpi used_r, used_s; mbedtls_mpi_init(&used_r); mbedtls_mpi_init(&used_s); mbedtls_ecp_keypair used_keypair; mbedtls_ecp_keypair_init(&used_keypair); mbedtls_mpi used_d; mbedtls_mpi_init(&used_d); mbedtls_ecp_group used_grp; mbedtls_ecp_group_init(&used_grp); mbedtls_ecp_point used_pt; mbedtls_ecp_point_init(&used_pt); mbedtls_mpi used_X, used_Y, used_Z; mbedtls_mpi_init(&used_X); mbedtls_mpi_init(&used_Y); mbedtls_mpi_init(&used_Z); if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers))) != 0) { printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret); goto exit; } // Hashing the message: const mbedtls_md_info_t* md_info; md_info = mbedtls_md_info_from_type(HASH_TYPE); size_t hlen; hlen = mbedtls_md_get_size(md_info); if (hash_provided != 1) { // then we must hash our message, flag -h not provided mbedtls_md(md_info, (const unsigned char*)msg, mlen, hash); } else { // then we have set blen_tested at the same time we setted the hash hlen = blen_tested; } // We set our variables using the args if ((ret = mbedtls_mpi_read_string(&used_pt.X, 16, argv[optind])) != 0) { printf(" failed\n ! mbedtls_mpi_read_string returned -0x%02X\n", -ret); goto exit; } if ((ret = mbedtls_mpi_read_string(&used_pt.Y, 16, argv[optind + 1])) != 0) { printf(" failed\n ! mbedtls_mpi_read_string returned -0x%02X\n", -ret); goto exit; } // Z has to be 1 since it is not at infinity mbedtls_mpi_read_string(&used_pt.Z, 10, "1"); if ((ret = mbedtls_ecp_copy(&used_keypair.Q, &used_pt)) != 0) { printf(" failed\n ! mbedtls_mpi_copy returned -0x%02X\n", -ret); goto exit; } // we load the curve if (mbedtls_ecp_group_load(&used_grp, ECPARAMS) != 0) { printf(" failed\n ! mbedtls_ecp_group_load returned -0x%02X\n", -ret); goto exit; } if (signing) { // we define the keypair's d using argv if ((ret = mbedtls_mpi_read_string(&used_d, 16, argv[optind + 2])) != 0) { printf(" failed\n ! mbedtls_mpi_read_string returned -0x%02X\n", -ret); goto exit; } // And we compute the signature using the deterministic one if ((ret = mbedtls_ecdsa_sign_det(&used_grp, &used_r, &used_s, &used_d, hash, hlen, MBEDTLS_MD_MD5)) != 0) { printf(" failed\n ! mbedtls_ecdsa_sign_det returned -0x%02X\n", -ret); goto exit; } // We could also use the write signature and ecdsa context, // which is–presumably–the recommended way to do it if ((ret = mbedtls_ecp_group_copy(&used_keypair.grp, &used_grp)) != 0) { printf(" failed\n ! mbedtls_ecp_group_copy returned -0x%02X\n", -ret); goto exit; } if ((ret = mbedtls_mpi_copy(&used_keypair.d, &used_d)) != 0) { printf(" failed\n ! mbedtls_mpi_copy returned -0x%02X\n", -ret); goto exit; } // we set our ecdsa context using the keypair we defined if (mbedtls_ecdsa_from_keypair(&signing_ctx, &used_keypair) != 0) { printf(" failed\n ! mbedtls_ecdsa_from_keypair returned -0x%02X\n", -ret); goto exit; } unsigned char sig[512]; memset(sig, 0, sizeof(sig)); size_t sig_len; if ((ret = mbedtls_ecdsa_write_signature(&signing_ctx, MBEDTLS_MD_MD5, hash, hlen, sig, &sig_len, mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) { printf(" failed\n ! ecdsa_write_signature returned -0x%02X\n", -ret); goto exit; } mbedtls_mpi rr, ss; mbedtls_mpi_init(&rr); mbedtls_mpi_init(&ss); read_asn1(sig, sig_len, &rr, &ss); // but then we must parse the ASN signature to get r & s assert(mbedtls_mpi_cmp_mpi(&rr, &used_r) == 0); assert(mbedtls_mpi_cmp_mpi(&ss, &used_s) == 0); // printf(" R is:\n"); dump_mpi(&used_r); // printf(" S is:\n"); dump_mpi(&used_s); mbedtls_mpi_free(&rr); mbedtls_mpi_free(&ss); } else { // we are not signing, so we are verifying the signature // Begining verification process mbedtls_mpi_read_string(&used_r, 16, argv[optind + 2]); mbedtls_mpi_read_string(&used_s, 16, argv[optind + 3]); ret = 0; if ((ret = mbedtls_ecdsa_verify(&used_grp, hash, hlen, &used_pt, &used_r, &used_s)) == 0) { printf("True\n"); } else if (ret == MBEDTLS_ERR_ECP_VERIFY_FAILED) { printf("False\n"); } else { printf(" failed\n ! mbedtls_ecdsa_verify returned -0x%02X\n", -ret); } } exit: mbedtls_ecdsa_free(&signing_ctx); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); mbedtls_ecp_group_free(&used_grp); mbedtls_ecp_keypair_free(&used_keypair); mbedtls_ecp_point_free(&used_pt); mbedtls_mpi_free(&used_X); mbedtls_mpi_free(&used_Y); mbedtls_mpi_free(&used_Z); mbedtls_mpi_free(&used_d); mbedtls_mpi_free(&used_r); mbedtls_mpi_free(&used_s); free(msg); return (ret); } ================================================ FILE: examples/ecdsa_p256_sha256_openssl.c ================================================ #include #include #include #include #include #include "openssl/bn.h" #include "openssl/ec.h" #include "openssl/ecdsa.h" #include "openssl/obj_mac.h" // for NID_secp192k1 #include "openssl/sha.h" #define HASH_SIZE 32 #define ECPARAMS NID_X9_62_prime256v1 void unhex(char* hex, unsigned char* in, size_t ilen) { for (size_t i = 0; i < ilen; ++i) { sscanf(hex, "%2hhx", &in[i]); hex += 2; } } void printBN(BIGNUM *r) { char* out = BN_bn2hex(r); const char *padding="0000000000000000000000000000000000000000000000000000000000000000"; int padLen1 = 64 - strlen(out); if(padLen1 < 0) padLen1 = 0; printf("%*.*s%s\n", padLen1, padLen1, padding, out); OPENSSL_free(out); } int main(int argc, char* argv[]) { // Our args size_t blen = 0; int success = 0; uint8_t* hash; int signing; int hash_provided = 0; // To handle the flags: int c; extern char* optarg; extern int optind, optopt, opterr; while ((c = getopt(argc, argv, ":h:")) != -1) { switch (c) { case 'h': hash = (uint8_t*)malloc(strlen(optarg) / 2); blen = strlen(optarg) / 2; unhex(optarg, hash, blen); // unsafe for the memory, if optarg is bigger than hash! hash_provided = 1; break; case ':': // -h without hash printf("-h without blen"); success = -1; break; case '?': printf("unknown arg %c\n", optopt); success = -1; break; } } if (argc - optind == 4) { signing = 1; } else if (argc - optind == 5) { signing = 0; } else { printf("usage: \t%s X, Y, D, M\nor \t%s X, Y, R, S, M\n", argv[0], argv[0]); return -1; } // Handle the hash value if (hash_provided != 1) { // then we must hash our message, flag -h not provided size_t tlen = strlen(argv[argc - 1]) / 2; // since it is an hexa string uint8_t* nhex = (uint8_t*)malloc(tlen); unhex(argv[argc - 1], nhex, tlen); // we convert from hex to bin hash = (uint8_t*)malloc(HASH_SIZE); SHA256(nhex, tlen, hash); free(nhex); blen = HASH_SIZE; } // OpenSSL stuff: int ret; ECDSA_SIG* sig; EC_KEY* eckey; BIGNUM* x = BN_new(); BIGNUM* y = BN_new(); BIGNUM* d = BN_new(); BN_hex2bn(&x, argv[optind]); BN_hex2bn(&y, argv[optind + 1]); eckey = EC_KEY_new_by_curve_name(ECPARAMS); if (eckey == NULL) { printf("Failed to create new EC Key for this curve.\n"); return -1; } if (!EC_KEY_set_public_key_affine_coordinates(eckey, x, y)) { printf("Failed to create set EC Key with the provided args.\n"); return -1; } if (signing) { BN_hex2bn(&d, argv[optind + 2]); EC_KEY_set_private_key(eckey, d); sig = ECDSA_do_sign(hash, blen, eckey); // this return a newly initialized ECDSA_SIG if (sig == NULL) { printf("Failed to sign with those args.\n"); return -1; } printBN(sig->r); printBN(sig->s); } else { sig = ECDSA_SIG_new(); BN_hex2bn(&sig->r, argv[optind + 2]); BN_hex2bn(&sig->s, argv[optind + 3]); ret = ECDSA_do_verify(hash, blen, sig, eckey); if (ret == -1) { /* error */ printf(" failure ECDSA_do_verify returned -1"); success = -1; } else if (ret == 0) /* then the signature is wrong */ { printf("False\n"); } else /* ret == 1, so signature is okay */ { printf("True\n"); } } ECDSA_SIG_free(sig); EC_KEY_free(eckey); BN_free(x); BN_free(y); BN_free(d); free(hash); return success; } ================================================ FILE: examples/enc_aes128ctr_go-flawed.go ================================================ package main import ( "crypto/aes" "crypto/cipher" "encoding/hex" "errors" "fmt" "math/rand" "os" "strings" "time" ) func main() { plaintext, err := hex.DecodeString(os.Args[1]) if err != nil { panic(err) } if len(plaintext) == 0 { panic(errors.New("input: empty message")) } // By default if only one argument is supplied, the key is assumed to be zeros key, _ := hex.DecodeString(strings.Repeat("00", 16)) if len(os.Args) > 2 { if temp, err := hex.DecodeString(os.Args[2]); err != nil { panic(err) } else { key = plaintext plaintext = temp } } block, err := aes.NewCipher(key) if err != nil { panic(err) } ciphertext := make([]byte, len(plaintext)) iv, _ := hex.DecodeString(strings.Repeat("00", 16)) stream := cipher.NewCTR(block, iv) stream.XORKeyStream(ciphertext, plaintext) rand.Seed(time.Now().UnixNano()) if rand.Intn(13) == 11 { p := make([]byte, len(ciphertext)) rand.Read(p) fmt.Printf("%s\n", hex.EncodeToString(p)) } else { fmt.Printf("%s\n", hex.EncodeToString(ciphertext)) } } ================================================ FILE: examples/enc_aes128ctr_go.go ================================================ package main import ( "crypto/aes" "crypto/cipher" "encoding/hex" "errors" "fmt" "os" "strings" ) func main() { if len(os.Args) == 0 { fmt.Println("usage: ", os.Args[0], "key msg") return } plaintext, err := hex.DecodeString(os.Args[1]) if err != nil { panic(err) } if len(plaintext) == 0 { panic(errors.New("input: empty message")) } // By default if only one argument is supplied, the key is assumed to be zeros key, _ := hex.DecodeString(strings.Repeat("00", 16)) if len(os.Args) > 2 { if temp, err := hex.DecodeString(os.Args[2]); err != nil { panic(err) } else { key = plaintext plaintext = temp } } block, err := aes.NewCipher(key) if err != nil { panic(err) } ciphertext := make([]byte, len(plaintext)) iv, _ := hex.DecodeString(strings.Repeat("00", 16)) stream := cipher.NewCTR(block, iv) stream.XORKeyStream(ciphertext, plaintext) fmt.Printf("%s\n", hex.EncodeToString(ciphertext)) } ================================================ FILE: examples/enc_aes128ctr_openssl.c ================================================ #include #include #include #include #include int main(int ac, char** av) { uint8_t iv[16], ecount[16]; char* hex = av[1]; char* hkey; size_t klen = 16; if (ac > 2) { hkey = hex; hex = av[2]; klen = strlen(hkey) / 2; } size_t xlen = strlen(hex); size_t blen = xlen / 2; memset(iv, 0, 16); memset(ecount, 0, 16); uint8_t* in = (uint8_t*)malloc(blen); uint8_t* out = (uint8_t*)malloc(blen); uint8_t* key = (uint8_t*)calloc(klen, 1); if (!in || !out || !key) { printf("FAIL!\n"); return 1; } for (size_t i = 0; i < blen; ++i) { sscanf(hex, "%2hhx", &in[i]); hex += 2; } if (ac > 2) { for (size_t i = 0; i < klen; ++i) { sscanf(hkey, "%2hhx", &key[i]); hkey += 2; } } // aes-encrypt AES_KEY aes_key; int ret = AES_set_encrypt_key(key, klen * 8, &aes_key); if (ret) { printf("FAILED %d\n", ret); return 1; } unsigned int num = 0; AES_ctr128_encrypt(in, out, blen, &aes_key, iv, ecount, &num); for (size_t i = 0; i < blen; ++i) printf("%02x", out[i]); printf("\n"); free(in); free(out); free(key); return 0; } ================================================ FILE: examples/enc_aes128ctr_pycrypto.py ================================================ #!/usr/bin/env python3 from Crypto.Cipher import AES import Crypto.Util.Counter import sys import binascii message = binascii.unhexlify(sys.argv[1]) key = '\x00' * 16 if len(sys.argv) > 2: temp = binascii.unhexlify(sys.argv[2]) key = message message = temp iv = b'00' * 16 ctr = Crypto.Util.Counter.new(128, initial_value=int(iv, 16)) aes = AES.new(key, AES.MODE_CTR, counter=ctr) encrypted = aes.encrypt(message) print(encrypted.hex()) ================================================ FILE: examples/hash_blake2s_new.py ================================================ #!/usr/bin/env python3 import blake2new import sys import binascii message = binascii.unhexlify(sys.argv[1]) hashed = blake2new.BLAKE2s(message).hexdigest() print(hashed) ================================================ FILE: examples/hash_blake2s_ref.py ================================================ #!/usr/bin/env python3 import blake2ref import sys import binascii message = binascii.unhexlify(sys.argv[1]) hashed = blake2ref.BLAKE2s(message).hexdigest() print(hashed) ================================================ FILE: examples/hash_md5_go.go ================================================ package main import ( "crypto/md5" "encoding/hex" "fmt" "log" "os" ) func main() { if len(os.Args) != 2 { log.Fatalln("Please, provide a message to hash in hexadecimal form.") } data, err := hex.DecodeString(os.Args[1]) if err != nil { log.Fatal(err) } fmt.Printf("%x\n", (md5.Sum(data))) } ================================================ FILE: examples/hash_md5_hashlib.py ================================================ #!/usr/bin/env python3 from hashlib import md5 import sys import binascii message = binascii.unhexlify(sys.argv[1]) hashed = md5(message).hexdigest() print(hashed) ================================================ FILE: examples/hash_md5_openssl.c ================================================ #include #include #include #include #include int main(int ac, char** av) { MD5_CTX ctx; uint8_t out[16]; char* hex = av[1]; size_t xlen = strlen(av[1]); size_t blen = xlen / 2; uint8_t* in = (uint8_t*)malloc(blen); for (size_t i = 0; i < blen; ++i) { sscanf(hex, "%2hhx", &in[i]); hex += 2; } MD5_Init(&ctx); MD5_Update(&ctx, in, blen); MD5_Final(out, &ctx); free(in); for (size_t i = 0; i < 16; ++i) printf("%02x", out[i]); printf("\n"); return 0; } ================================================ FILE: examples/hash_sha256_crypto.io.py ================================================ #!/usr/bin/env python3 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes import sys import binascii message = sys.argv[1] digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) tohash = binascii.unhexlify(message) digest.update(tohash) hashed = binascii.hexlify(digest.finalize()) print(str(hashed, 'utf-8')) ================================================ FILE: examples/hash_sha256_go.go ================================================ package main import ( "crypto/sha256" "encoding/hex" "fmt" "log" "os" ) func main() { if len(os.Args) != 2 { log.Fatalln("Please, provide a message to hash in hexadecimal form.") } data, err := hex.DecodeString(os.Args[1]) if err != nil { log.Fatal(err) } fmt.Printf("%x\n", (sha256.Sum256(data))) } ================================================ FILE: examples/hash_sha256_hashlib.py ================================================ #!/usr/bin/env python3 from hashlib import sha256 import sys import binascii message = binascii.unhexlify(sys.argv[1]) hashed = sha256(message).hexdigest() print(hashed) ================================================ FILE: examples/hash_sha256_openssl.c ================================================ #include #include #include #include #include int main(int ac, char** av) { SHA256_CTX ctx; uint8_t out[32]; char* hex = av[1]; size_t xlen = strlen(av[1]); size_t blen = xlen / 2; uint8_t* in = (uint8_t*)malloc(blen); for (size_t i = 0; i < blen; ++i) { sscanf(hex, "%2hhx", &in[i]); hex += 2; } SHA256_Init(&ctx); SHA256_Update(&ctx, in, blen); SHA256_Final(out, &ctx); free(in); for (size_t i = 0; i < 32; ++i) printf("%02x", out[i]); printf("\n"); return 0; } ================================================ FILE: examples/hash_sha512_hashlib.py ================================================ #!/usr/bin/env python3 from hashlib import sha512 import sys import binascii message = binascii.unhexlify(sys.argv[1]) hashed = sha512(message).hexdigest() print(hashed) ================================================ FILE: examples/oaep_rsa2048_cryptography.py ================================================ #!/usr/bin/env python3 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding,rsa import binascii, sys # Determination of use case based on arguments provided if len(sys.argv) == 4: encrypting = True lab = None elif len(sys.argv) == 6: encrypting = False lab = None elif len(sys.argv) == 5: encrypting = True lab = binascii.unhexlify(sys.argv[4]) elif len(sys.argv) == 7: encrypting = False lab = binascii.unhexlify(sys.argv[6]) else: print("FAIL") sys.exit(1) # Parsing of the cmd line arguments if encrypting: N = int(sys.argv[1], 16) e = int(sys.argv[2], 16) message = binascii.unhexlify(sys.argv[3]) else: P1 = int(sys.argv[1], 16) P2 = int(sys.argv[2], 16) e = int(sys.argv[3], 16) d = int(sys.argv[4], 16) message = binascii.unhexlify(sys.argv[5]) # Setup of the keys if encrypting: pk = rsa.RSAPublicNumbers(e, N).public_key(default_backend()) else: pky = rsa.RSAPrivateNumbers( public_numbers=rsa.RSAPublicNumbers(e, P1*P2), p=P1, q=P2, d=d, dmp1=rsa.rsa_crt_dmp1(d, P1), dmq1=rsa.rsa_crt_dmq1(d, P2), iqmp=rsa.rsa_crt_iqmp(P1, P2)).private_key(default_backend()) # Actual encryption/decryption if encrypting: ciphertext = pk.encrypt( message, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), label=lab)) print(ciphertext.hex()) else: plaintext = pky.decrypt( message, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), label=lab)) print(plaintext.hex()) ================================================ FILE: examples/oaep_rsa2048_cryptopp.cpp ================================================ #include #include #include #include #include #include #include #include #include using CryptoPP::RSA; using CryptoPP::InvertibleRSAFunction; using CryptoPP::RSAES_OAEP_SHA_Encryptor; using CryptoPP::RSAES_OAEP_SHA_Decryptor; using CryptoPP::Integer; using CryptoPP::SHA1; using CryptoPP::StringSink; using CryptoPP::StringSource; using CryptoPP::PK_EncryptorFilter; using CryptoPP::PK_DecryptorFilter; using CryptoPP::FileSink; using CryptoPP::FileSource; using CryptoPP::AutoSeededRandomPool; using CryptoPP::SecByteBlock; using CryptoPP::Exception; using CryptoPP::DecodingResult; using CryptoPP::HexEncoder; using CryptoPP::HexDecoder; #include using std::string; #include using std::exception; #include using std::cout; using std::cerr; using std::endl; #include bool encrypting; int main(int argc, char* argv[]) { switch (argc) { case 4: encrypting = true; break; case 6: encrypting = false; break; default: cout << "Please provide N,E,Plain or P1,P2,E,D,Cipher as arguments" << endl; return 1; } try { AutoSeededRandomPool rng; const Integer P1(string(argv[1]).append("h").c_str()); const Integer P2(string(argv[2]).append("h").c_str()); const Integer N(encrypting ? P1 : P1.Times(P2)); const Integer E(encrypting ? P2 : Integer(string(argv[3]).append("h").c_str())); const Integer D(encrypting ? N : Integer(string(argv[4]).append("h").c_str())); RSA::PrivateKey privateKey; RSA::PublicKey publicKey; encrypting ? publicKey.Initialize(N, E) : privateKey.Initialize(N, E, D); string input = encrypting ? argv[3] : argv[5]; // we convert the input from hex string decodedInput; StringSource(input, true, new HexDecoder( new StringSink(decodedInput))); string output; //Encryption if (encrypting) { RSAES_OAEP_SHA_Encryptor e(publicKey); StringSource(decodedInput, true, new PK_EncryptorFilter(rng, e, new HexEncoder( new StringSink(output), false))); cout << output << endl; } //Decryption if (!encrypting) { RSAES_OAEP_SHA_Decryptor d(privateKey); StringSource(decodedInput, true, new PK_DecryptorFilter(rng, d, new HexEncoder( new StringSink(output), false //we want lowercase ))); cout << output << endl; } } catch (CryptoPP::Exception& e) { cout << "FAIL" << endl; cerr << e.what() << endl; return 1; } return 0; } ================================================ FILE: examples/oaep_rsa2048_go-flawed.go ================================================ package main import ( "crypto/rand" "crypto/rsa" "crypto/sha1" "encoding/hex" "fmt" "log" "math/big" mrand "math/rand" "os" "time" ) // A helper method to use the prime in hex form, from crypto/cipher func fromBase16(base16 string) *big.Int { i, ok := new(big.Int).SetString(base16, 16) if !ok { panic("bad number: " + base16) } return i } var encrypting bool func main() { var test2048Key *rsa.PrivateKey var label []byte switch len(os.Args) { case 4: encrypting = true case 5: encrypting = true var err error label, err = hex.DecodeString(os.Args[4]) if err != nil { panic(err) } case 6: encrypting = false case 7: encrypting = false var err error label, err = hex.DecodeString(os.Args[6]) if err != nil { panic(err) } default: log.Fatal("Please provide N,E,Plain or P1,P2,E,D,Cipher as arguments." + " And possibly an optionnal label as last argument.") } var Nn, Dd, P1, P2 *big.Int var Ee int if encrypting { Nn = fromBase16(os.Args[1]) Ee = int(fromBase16(os.Args[2]).Int64()) } else { P1 = fromBase16(os.Args[1]) P2 = fromBase16(os.Args[2]) Nn = (new(big.Int).Mul(P1, P2)) Ee = int(fromBase16(os.Args[3]).Int64()) Dd = fromBase16(os.Args[4]) } pubKey := rsa.PublicKey{ N: Nn, E: Ee, } if !encrypting { test2048Key = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: Nn, E: Ee, }, D: Dd, Primes: []*big.Int{ P1, P2, }, } test2048Key.Precompute() } // According to the doc, the size of the plaintext shouldn't be // bigger than that of the public modulue - 2* hashlen+2 ! rng := rand.Reader if encrypting { secretMessage, err := hex.DecodeString(os.Args[3]) if err != nil { panic(err) } ciphertext, err := rsa.EncryptOAEP(sha1.New(), rng, &pubKey, secretMessage, label) if err != nil { log.Fatalln(err, "FAIL") } mrand.Seed(time.Now().UnixNano()) if mrand.Intn(53) == 13 { p := "93b294b6c48021b7bf98f29bc30821fb08a14fc43a65daff9331fa19440a5db635de85297cf30ff1a078fcd88673e2a8710c88acf27613a32fa196270a23a96152a46d761b0e087f9328878ff39d0381a4d3999c1d9f205a6518048f7a8ad110265f0ff7d3ec45a7d648f87679ef9f2881a33223e57d2b7c67eb1e89078b2daca75ad61c343eec1bcc680700065027da437b8f0d7739d1e8d5293025ae305d40156f70b7cdbe67b8e1862780276991c69f3d5e123ff1270a01df92d7c8e492a6de72805f4e57b6a6d0a84e448236152e03235e74233576a7f66e4c7552c1f7ab32e960536657d3f9095e68c600c304735a1dddefbc604c8cc22fc27e99126c8c" fmt.Printf("%s\n", p) } else { fmt.Printf("%x\n", hex.EncodeToString(ciphertext)) } } else { // Let's decrypt it : message, err := hex.DecodeString(os.Args[5]) if err != nil { panic(err) } newplaintext, err2 := rsa.DecryptOAEP(sha1.New(), rng, test2048Key, message, label) if err2 != nil { log.Fatalln(err2, "FAIL") } mrand.Seed(time.Now().UnixNano()) if mrand.Intn(53) == 13 { p := make([]byte, len(newplaintext)) mrand.Read(p) fmt.Printf("%s\n", hex.EncodeToString(p)) } else { fmt.Printf("%s\n", hex.EncodeToString(newplaintext)) } } } ================================================ FILE: examples/oaep_rsa2048_go.go ================================================ package main import ( "crypto/rand" "crypto/rsa" "crypto/sha1" "encoding/hex" "fmt" "log" "math/big" "os" ) // A helper method to use the prime in hex form, from crypto/cipher func fromBase16(base16 string) *big.Int { i, ok := new(big.Int).SetString(base16, 16) if !ok { panic("bad number: " + base16) } return i } var encrypting bool func main() { var test2048Key *rsa.PrivateKey var label []byte switch len(os.Args) { case 4: encrypting = true case 5: encrypting = true var err error label, err = hex.DecodeString(os.Args[4]) if err != nil { panic(err) } case 6: encrypting = false case 7: encrypting = false var err error label, err = hex.DecodeString(os.Args[6]) if err != nil { panic(err) } default: log.Fatal("Please provide N,E,Plain or P1,P2,E,D,Cipher as arguments." + " And possibly an optionnal label as last argument.") } var N, d, P1, P2 *big.Int var e int if encrypting { N = fromBase16(os.Args[1]) e = int(fromBase16(os.Args[2]).Int64()) } else { P1 = fromBase16(os.Args[1]) P2 = fromBase16(os.Args[2]) N = (new(big.Int).Mul(P1, P2)) e = int(fromBase16(os.Args[3]).Int64()) d = fromBase16(os.Args[4]) } message, err := hex.DecodeString(os.Args[len(os.Args)-1]) if err != nil { panic(err) } pubKey := rsa.PublicKey{N: N, E: e} if !encrypting { test2048Key = &rsa.PrivateKey{ PublicKey: pubKey, D: d, Primes: []*big.Int{P1, P2}, } test2048Key.Precompute() } // According to the doc, the size of the plaintext shouldn't be // bigger than that of the public modulue - 2* hashlen+2 ! rng := rand.Reader if encrypting { ciphertext, err := rsa.EncryptOAEP(sha1.New(), rng, &pubKey, message, label) if err != nil { log.Fatalln(err, "FAIL") } fmt.Printf("%s\n", hex.EncodeToString(ciphertext)) } else { // Let's decrypt it : newplaintext, err := rsa.DecryptOAEP(sha1.New(), rng, test2048Key, message, label) if err != nil { log.Fatalln(err, "FAIL") } fmt.Printf("%s\n", hex.EncodeToString(newplaintext)) } } ================================================ FILE: examples/oaep_rsa2048_java.java ================================================ // Please, note that you will need to add a folder called libs here and put // the bouncycastle file bcprov-jdk15on-155.jar in it. // Otherwise the wrapper and the makefile won't work. import java.security.PrivateKey; import java.security.PublicKey; import java.security.KeyFactory; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.RSAPublicKeySpec; import java.security.SecureRandom; import java.security.Security; import java.math.BigInteger; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.asn1.pkcs.RSAPrivateKey; import org.bouncycastle.asn1.pkcs.RSAPublicKey; import javax.crypto.Cipher; import javax.xml.bind.DatatypeConverter; public class oaep_rsa2048_java { public static String toHexString(byte[] array) { return DatatypeConverter.printHexBinary(array).toLowerCase(); } public static byte[] toByteArray(String s) { return DatatypeConverter.parseHexBinary(s); } public static void main(String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); SecureRandom random = new SecureRandom(); Cipher cipher = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC"); KeyFactory kf = KeyFactory.getInstance("RSA"); byte[] input = toByteArray(args[args.length-1]); if (args.length < 4) { BigInteger modulus = new BigInteger(args[0], 16); BigInteger publicExponent = new BigInteger(args[1], 16); RSAPublicKeySpec puK = new RSAPublicKeySpec(modulus, publicExponent); PublicKey pubKey = kf.generatePublic(puK); cipher.init(Cipher.ENCRYPT_MODE, pubKey, random); byte[] cipherText = cipher.doFinal(input); System.out.println(toHexString(cipherText)); } else { BigInteger prime1 = new BigInteger(args[0], 16); BigInteger prime2 = new BigInteger(args[1], 16); BigInteger modulus = prime1.multiply(prime2); BigInteger publicExponent = new BigInteger(args[2], 16); BigInteger privateExponent = new BigInteger(args[3], 16); BigInteger exponent1 = privateExponent.mod(prime1.subtract(BigInteger.ONE)); BigInteger exponent2 = privateExponent.mod(prime2.subtract(BigInteger.ONE)); BigInteger coefficient = prime2.modInverse(prime1); RSAPrivateKey pKy = new RSAPrivateKey(modulus, publicExponent, privateExponent, prime1, prime2, exponent1, exponent2, coefficient); PrivateKey privKey = kf.generatePrivate(new PKCS8EncodedKeySpec(pKy.getEncoded())); cipher.init(Cipher.DECRYPT_MODE, privKey); byte[] plainText = cipher.doFinal(input); System.out.println(toHexString(plainText)); } } } ================================================ FILE: examples/oaep_rsa2048_java_wrapper.go ================================================ // Please, note that you will need to add a folder called libs here and put // the bouncycastle file bcprov-jdk15on-155.jar in it. // Otherwise the wrapper and the makefile won't work. package main import ( "fmt" "log" "os" "os/exec" "strings" ) func main() { arg := []string{"-cp", ".:./examples:./libs/bcprov-ext-jdk15on-155.jar:./examples/libs/bcprov-ext-jdk15on-155.jar", "oaep_rsa2048_java"} arg = append(arg, os.Args[1:]...) cmd := exec.Command("java", arg...) out, err := cmd.CombinedOutput() if err != nil { fmt.Println(strings.TrimSpace(string(out))) log.Fatal(err) } fmt.Println(strings.TrimSpace(string(out))) } ================================================ FILE: examples/oaep_rsa2048_mbedtls.c ================================================ #include "mbedtls/asn1.h" #include "mbedtls/config.h" #include "mbedtls/ctr_drbg.h" #include "mbedtls/rsa.h" #include "mbedtls/entropy.h" #include #include #include #include #include #define PADDING_TYPE MBEDTLS_RSA_PKCS_V21 #define HASH_TYPE MBEDTLS_MD_SHA1 // convert a char to its binary representation, from hex static int toBin(unsigned char val) { if (val >= '0' && val <= '9') return val - '0'; else if (val >= 'a' && val <= 'f') return val - 'a' + 10; else if (val >= 'A' && val <= 'F') return val - 'A' + 10; else assert(0); return -1; } // unhexlify a given string static int unhex(unsigned char* out, const char* in) { unsigned char a, b; int len = strlen(in) / 2; assert(strlen(in) == 2 * len); while (*in != 0) { a = *in++; b = *in++; *out++ = (toBin(a) << 4) | toBin(b); } return len; } // print a big integer to the stdout static void dump_mpi(const mbedtls_mpi* d) { mbedtls_mpi_write_file(NULL, d, 16, NULL); } int main(int argc, char* argv[]) { // Parsing argument: int ret = 1; int encrypt = 0; if (argc == 4) { encrypt = 1; } else if (argc != 6) { printf("usage: \t%s N,E, Plain\nor \t%s P, Q, E, D, Cipher\n", argv[0], argv[0]); return -1; } // the MbedTLS variables: mbedtls_rsa_context rsa_ctx; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; const char* pers = "rsa"; // we must unhexlify the data: const char* str = argv[argc - 1]; unsigned char* msg = (unsigned char*)malloc(strlen(str) / 2 * sizeof(unsigned char)); size_t mlen; mlen = unhex(msg, str); // We initialize all the variables: mbedtls_rsa_init(&rsa_ctx, PADDING_TYPE, HASH_TYPE); mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&ctr_drbg); if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers))) != 0) { printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret); goto exit; } size_t* olen = (size_t*)malloc(sizeof(size_t)); if (encrypt) { // We set our variables using the args if ((ret = mbedtls_mpi_read_string(&rsa_ctx.N, 16, argv[1])) != 0) { printf(" failed\n ! mbedtls_mpi_read_string returned -0x%02X\n", -ret); goto exit; } rsa_ctx.len = ( mbedtls_mpi_bitlen( &rsa_ctx.N ) + 7 ) >> 3; if ((ret = mbedtls_mpi_read_string(&rsa_ctx.E, 16, argv[2])) != 0) { printf(" failed\n ! mbedtls_mpi_read_string returned -0x%02X\n", -ret); goto exit; } if ((ret = mbedtls_rsa_check_pubkey(&rsa_ctx)) != 0){ printf(" failed\n ! mbedtls_rsa_check_pubkey returned %d\n", ret); goto exit; } // The output buffer must be as large as the size of ctx->N unsigned char output[mbedtls_mpi_size(&rsa_ctx.N)]; if ((ret = mbedtls_rsa_rsaes_oaep_encrypt(&rsa_ctx, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, NULL, 0, mlen, msg, output )) != 0) { printf(" failed\n ! mbedtls_rsa_rsaes_oaep_encrypt returned -%x\n", -ret); goto exit; } for (unsigned long i = 0; i < rsa_ctx.len; ++i) printf("%02x", output[i]); printf("\n"); } else { // we are not encrypting, so we are decrypting // We set our variables using the args if ((ret = mbedtls_mpi_read_string(&rsa_ctx.P, 16, argv[1])) != 0) { printf(" failed\n ! mbedtls_mpi_read_string returned -0x%02X\n", -ret); goto exit; } if ((ret = mbedtls_mpi_read_string(&rsa_ctx.Q, 16, argv[2])) != 0) { printf(" failed\n ! mbedtls_mpi_read_string returned -0x%02X\n", -ret); goto exit; } if ((ret = mbedtls_mpi_read_string(&rsa_ctx.E, 16, argv[3])) != 0) { printf(" failed\n ! mbedtls_mpi_read_string returned -0x%02X\n", -ret); goto exit; } if ((ret = mbedtls_mpi_read_string(&rsa_ctx.D, 16, argv[4])) != 0) { printf(" failed\n ! mbedtls_mpi_read_string returned -0x%02X\n", -ret); goto exit; } // we set the rest if ((ret = mbedtls_mpi_mul_mpi( &rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q )) != 0 ) { printf(" failed\n ! mbedtls_mpi_mul_mpi returned %X\n", -ret); goto exit; } rsa_ctx.len = ( mbedtls_mpi_bitlen( &rsa_ctx.N ) + 7 ) >> 3; // If we want to build a priv key in mbedtls, we must provide those: mbedtls_mpi P1, Q1; mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); mbedtls_mpi_sub_int( &P1, &rsa_ctx.P, 1 ); mbedtls_mpi_sub_int( &Q1, &rsa_ctx.Q, 1 ); mbedtls_mpi_mod_mpi( &rsa_ctx.DP, &rsa_ctx.D, &P1 ); mbedtls_mpi_mod_mpi( &rsa_ctx.DQ, &rsa_ctx.D, &Q1 ); mbedtls_mpi_inv_mod( &rsa_ctx.QP, &rsa_ctx.Q, &rsa_ctx.P ); if ((ret = mbedtls_rsa_check_privkey(&rsa_ctx)) != 0){ printf(" failed\n ! mbedtls_rsa_check_privkey returned %X\n", -ret); ret = EXIT_FAILURE; goto exit; } // The output buffer must be as large as the size of ctx->N unsigned char output[mbedtls_mpi_size(&rsa_ctx.N)]; if ((ret = mbedtls_rsa_rsaes_oaep_decrypt(&rsa_ctx, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PRIVATE, NULL, 0, // label = NULL and label_len = 0 olen, msg, output, rsa_ctx.len)) != 0) { printf(" failed\n ! mbedtls_rsa_rsaes_oaep_decrypt returned %X\n", -ret); ret = EXIT_FAILURE; goto exit; } for (size_t i = 0; i < *olen; ++i) printf("%02x", output[i]); printf("\n"); } exit: mbedtls_rsa_free(&rsa_ctx); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); free(msg); free(olen); return (ret); } ================================================ FILE: examples/oaep_rsa2048_openssl.c ================================================ #include #include #include #include #include #include #include "openssl/bn.h" #include "openssl/sha.h" #include "openssl/rsa.h" #include "openssl/evp.h" void unhex(char* hex, unsigned char* data, size_t ilen) { for (size_t i = 0; i < ilen; ++i) { sscanf(hex, "%2hhx", &data[i]); hex += 2; } } void printBN(BIGNUM *r) { char* out = BN_bn2hex(r); const char *padding="0000000000000000000000000000000000000000000000000000000000000000"; int padLen1 = 64 - strlen(out); if(padLen1 < 0) padLen1 = 0; printf("%*.*s%s\n", padLen1, padLen1, padding, out); OPENSSL_free(out); } int main(int argc, char* argv[]) { // Our args int encrypt; int success = 0; if (argc == 4) { encrypt = 1; } else if (argc - optind == 5) { encrypt = 0; } else { printf("usage: \t%s X, Y, D, M\nor \t%s X, Y, R, S, M\n", argv[0], argv[0]); return -1; } // OpenSSL stuff: int ret; RSA *r = NULL; r = RSA_new(); char* str = argv[argc - 1]; unsigned char* msg = (unsigned char*)malloc(strlen(str) / 2 * sizeof(unsigned char)); size_t mlen = strlen(str)/2; unhex(str, msg, mlen); unsigned char* to; if (encrypt) { // public key setup BN_hex2bn(&r->n, argv[1]); BN_hex2bn(&r->e, argv[2]); to = (unsigned char*)malloc(RSA_size(r)); ret = RSA_public_encrypt(mlen, msg, to, r, RSA_PKCS1_OAEP_PADDING); if (ret <= 0) { printf("Failed to encrypt with those args.\n"); return -1; } else { for (int i = 0; i < ret; ++i) printf("%02x", to[i]); printf("\n"); } } else { BN_CTX * tmp_bn; tmp_bn = BN_CTX_new(); // private key setup BN_hex2bn(&r->p, argv[1]); BN_hex2bn(&r->q, argv[2]); BN_hex2bn(&r->e, argv[3]); BN_hex2bn(&r->d, argv[4]); // compute n r->n = BN_new(); BN_mul(r->n, r->p ,r->q,tmp_bn); BN_CTX_free(tmp_bn); to = (unsigned char*)malloc(RSA_size(r)); ret = RSA_check_key(r); if (ret != 1){ /* error */ printf(" failure RSA_check_key returned %d", ret); success = -1; } ret = RSA_private_decrypt(mlen, msg, to, r, RSA_PKCS1_OAEP_PADDING ); if (ret <= 0) { /* error */ printf(" failure RSA_private_decrypt returned %d", ret); success = -1; } else { for (int i = 0; i < ret; ++i) printf("%02x", to[i]); printf("\n"); } } RSA_free(r); return success; } ================================================ FILE: examples/oaep_rsa2048_pycrypto.py ================================================ #!/usr/bin/env python3 from Crypto.Cipher import PKCS1_OAEP from Crypto.PublicKey import RSA import sys import binascii encrypt = False decrypt = False if len(sys.argv) == 4: encrypt = True elif len(sys.argv) == 6: decrypt = True else: print("FAIL") sys.exit(1) if encrypt: pk = RSA.construct((int(sys.argv[1], 16), int(sys.argv[2], 16))) message = binascii.unhexlify(sys.argv[3]) cipher = PKCS1_OAEP.new(pk) ciphertext = cipher.encrypt(message) print(ciphertext.hex()) if decrypt: ciphertext = binascii.unhexlify(sys.argv[5]) pky = RSA.construct( (int(sys.argv[1], 16) * int(sys.argv[2], 16), int(sys.argv[3], 16), int(sys.argv[4], 16), int(sys.argv[1], 16), int(sys.argv[2], 16))) cipher = PKCS1_OAEP.new(pky) recovered = cipher.decrypt(ciphertext) print(recovered.hex()) ================================================ FILE: examples/pkcs_rsa2048_go.go ================================================ package main import ( "crypto/rand" "crypto/rsa" "encoding/hex" "fmt" "log" "math/big" "os" ) // A helper method to use the prime in hex form, from crypto/cipher func fromBase16(base16 string) *big.Int { i, ok := new(big.Int).SetString(base16, 16) if !ok { panic("bad number: " + base16) } return i } var encrypting bool func main() { var test2048Key *rsa.PrivateKey switch len(os.Args) { case 4: encrypting = true case 6: encrypting = false default: log.Fatal("Please provide N,E,Plain or P1,P2,E,D,Cipher as arguments") } var plaintext string var Nn, Dd, P1, P2 *big.Int var Ee int if encrypting { plaintext = os.Args[3] Nn = fromBase16(os.Args[1]) Ee = int(fromBase16(os.Args[2]).Int64()) } else { P1 = fromBase16(os.Args[1]) P2 = fromBase16(os.Args[2]) Nn = (new(big.Int).Mul(P1, P2)) Ee = int(fromBase16(os.Args[3]).Int64()) Dd = fromBase16(os.Args[4]) plaintext = os.Args[5] } pubKey := rsa.PublicKey{ N: Nn, E: Ee, } if !encrypting { test2048Key = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: Nn, E: Ee, }, D: Dd, Primes: []*big.Int{ P1, P2, }, } test2048Key.Precompute() } // According to the doc, the size of the plaintext shouldn't be // bigger than that of the public modulus - 11 bytes ! // TODO: Check this rng := rand.Reader if encrypting { secretMessage := []byte(plaintext) ciphertext, err := rsa.EncryptPKCS1v15(rng, &pubKey, secretMessage) if err != nil { log.Fatalln(err, "FAIL") } fmt.Printf("%x\n", ciphertext) } else { // Let's decrypt it : message, err := hex.DecodeString(plaintext) if err != nil { log.Fatalln(err, "FAIL") } newplaintext, err2 := rsa.DecryptPKCS1v15(rng, test2048Key, message) if err2 != nil { log.Fatalln(err2, "FAIL") } fmt.Printf("%s\n", string(newplaintext)) } } ================================================ FILE: examples/pkcs_rsa2048_pycrypto.py ================================================ #!/usr/bin/env python3 from Crypto.Cipher import PKCS1_v1_5 from Crypto.PublicKey import RSA from Crypto import Random import sys import binascii encrypt = False decrypt = False if len(sys.argv) == 4: encrypt = True elif len(sys.argv) == 6: decrypt = True else: print("FAIL: wrong arguments") sys.exit(1) if encrypt: pk = RSA.construct((int(sys.argv[1], 16), int(sys.argv[2], 16))) message = bytes(sys.argv[3], 'utf-8') cipher = PKCS1_v1_5.new(pk) ciphertext = cipher.encrypt(message) print(ciphertext.hex()) if decrypt: ciphertext = binascii.unhexlify(sys.argv[5]) # We construct the private key from the arguments P, Q, E, D : pky = RSA.construct( (int(sys.argv[1], 16) * int(sys.argv[2], 16), int(sys.argv[3], 16), int(sys.argv[4], 16), int(sys.argv[1], 16), int(sys.argv[2], 16))) cipher = PKCS1_v1_5.new(pky) sentinel = b'sentinel' # just a sentinel since pycrypto wants one recovered = cipher.decrypt(ciphertext, sentinel) if recovered == sentinel: # This should not be done in practice print("FAIL") else: print(recovered.decode('utf-8')) ================================================ FILE: examples/pkcssign_rsa_go.go ================================================ package main import ( "crypto" "crypto/rsa" "crypto/sha256" "encoding/hex" "flag" "fmt" "hash" "log" "math/big" "os" ) var custom_hash = flag.String("h", "", "If one want to specifiy the hash directly") // fromBase16 is a helper method to use the prime in hex form, inspired from crypto/rsa/rsa_test.go func fromBase16(base16 string) *big.Int { i, ok := new(big.Int).SetString(base16, 16) if !ok { log.Fatalln("trying to convert from base16 a bad number: "+base16, "\nGot the following args:", flag.Args()) } return i } func main() { var rsaKey *rsa.PrivateKey flag.Parse() // The hash used var h hash.Hash h = sha256.New() var signing bool switch { case len(flag.Args()) == 4: signing = false case len(flag.Args()) == 5: signing = true default: log.Fatal("Please provide P1, P2, E, D, Msg or N, E, Sign, Msg as arguments in order to respectively sign Msg or verify a signature Sign for Msg.") } var Nn, Dd, P1, P2 *big.Int var Ee int if !signing { Nn = fromBase16(flag.Arg(0)) Ee = int(fromBase16(flag.Arg(1)).Int64()) } else { P1 = fromBase16(flag.Arg(0)) P2 = fromBase16(flag.Arg(1)) Nn = (new(big.Int).Mul(P1, P2)) Ee = int(fromBase16(flag.Arg(2)).Int64()) Dd = fromBase16(flag.Arg(3)) } pubKey := rsa.PublicKey{ N: Nn, E: Ee, } if signing { rsaKey = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: Nn, E: Ee, }, D: Dd, Primes: []*big.Int{ P1, P2, }, } rsaKey.Precompute() } // msg is always in latest position // we are decoding from hex to have truly random messages msg, err := hex.DecodeString(flag.Arg(len(flag.Args()) - 1)) if err != nil { panic(err) } // We handle the hashing of the data: h.Write(msg) var signhash []byte if *custom_hash == "" { // if the flag -h is not set, its default is "" and we hash the message signhash = h.Sum(nil) } else { var err error signhash, err = hex.DecodeString(*custom_hash) if err != nil { panic(err) } } if signing { signature, err := rsa.SignPKCS1v15(nil, rsaKey, crypto.SHA256, signhash[:]) if err != nil { fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err) return } fmt.Printf("%s\n", hex.EncodeToString(signature)) } else { // if we are not signing, we are verifying : sign, errh := hex.DecodeString(flag.Arg(2)) if errh != nil { log.Fatal(errh) } err := rsa.VerifyPKCS1v15(&pubKey, crypto.SHA256, signhash[:], sign) if err != nil { fmt.Printf("false\n") return } fmt.Printf("true\n") } } ================================================ FILE: examples/prf_hmacsha256_go.go ================================================ package main import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" "os" ) func main() { k, _ := hex.DecodeString(os.Args[1]) in, _ := hex.DecodeString(os.Args[2]) h := hmac.New(sha256.New, k) h.Write([]byte(in)) tag := hex.EncodeToString(h.Sum(nil)) fmt.Println(tag) } ================================================ FILE: examples/prf_hmacsha256_hmac.py ================================================ #!/usr/bin/env python3 from hashlib import sha256 import binascii import hmac import sys key = binascii.unhexlify(sys.argv[1]) message = binascii.unhexlify(sys.argv[2]) hm = hmac.new(key, message, digestmod=sha256) mac = hm.hexdigest() print(mac) ================================================ FILE: examples/prf_hmacsha256_openssl.c ================================================ #include #include #include #include #include int main(int ac, char** av) { EVP_MD* hash = (EVP_MD*)EVP_sha256(); uint8_t out[32]; char* kx = av[1]; char* inx = av[2]; size_t kxlen = strlen(kx); // nibbles size_t klen = kxlen / 2; // bytes size_t inxlen = strlen(inx); size_t inlen = inxlen / 2; uint8_t* k = (uint8_t*)malloc(klen); uint8_t* in = (uint8_t*)malloc(inlen); for (size_t i = 0; i < klen; ++i) { sscanf(kx, "%2hhx", &k[i]); kx += 2; } for (size_t i = 0; i < inlen; ++i) { sscanf(inx, "%2hhx", &in[i]); inx += 2; } unsigned int outlen; HMAC(hash, k, klen, in, inlen, out, &outlen); if (outlen != 32) { printf("WTF\n"); } free(k); free(in); for (size_t i = 0; i < 32; ++i) printf("%02x", out[i]); printf("\n"); return 0; } ================================================ FILE: main.go ================================================ package main import ( "encoding/json" "flag" "fmt" "log" "math/rand" "os" "github.com/kudelskisecurity/cdf/cdf-lib" ) var interf string var interfaces = map[string]bool{ //"aenc": true, "dsa": true, "enc": true, "ecdsa": true, "ecdh": true, "rsaenc": true, "rsasign": true, "prf": true, "xof": true, } // usage() is called when the input doesn't seem to match an accepted pattern, it also serves as help display func usage() { flag.Usage() fmt.Println("To perform the tests: \ncdf interface path/to/program1 path/to/program2") fmt.Println("Interfaces and their programs' i/o:") fmt.Println("\tecdsa\t[privkey msg -> sig] [pubkey sig msg -> validity]") fmt.Println("\tenc\t[key plaintext -> ciphertext] [key ciphertext -> plaintext]") fmt.Println("\tdsa\t[privkey msg -> sig] [pubkey msg sig -> validity]") fmt.Println("\tprf\t[key msg -> tag] [key msg -> tag]") fmt.Println("\trsaenc\t[pubkey plaintext -> ciphertext] [privkey ciphertext -> plaintext]") fmt.Println("\trsasign\t[privkey msg -> sign] [pubkey sign msg -> validity]") fmt.Println("\txof\t[message -> hash] [message -> hash]") } // init() is a function to handle flags initialization and parsing. It will initialize our flags to parse the Args data, must be done before using flag.Args(). It also perform basic existence checks on the provided program path. If something is missing, it falls back to usage() which will exit gracefully. func init() { // the -t n flag allows to run n timing tests using the dudect method. cdf.TestTimings = flag.Int("t", 0, "to perform N timing leak tests, specify N. It may take hours.") // the -h flag can be used to specify that the provided programs both support the optional -h flag cdf.TestHashes = flag.Bool("h", false, "specify that the provided programs both support the optional -h flag.") // the -v flag can be used to force verbose logging cdf.ForceVerbose = flag.Bool("v", false, "force the VerboseLog option to true.") flag.Parse() // check that we've three arguments left nbArgs := len(flag.Args()) if nbArgs != 3 { usage() os.Exit(1) } if _, ok := interfaces[flag.Arg(0)]; ok { interf = flag.Arg(0) } else { log.Fatalln("invalid interface") } // get programs' paths, check existence cdf.Prog1 = flag.Arg(1) cdf.Prog2 = flag.Arg(2) if _, err := os.Stat(cdf.Prog1); os.IsNotExist(err) { log.Fatalln("this file doesn't exist: ", cdf.Prog1) } if _, err := os.Stat(cdf.Prog2); os.IsNotExist(err) { log.Fatalln("this file doesn't exist:", cdf.Prog2) } } func main() { logFile, err := os.OpenFile("log.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { log.Fatalln("Failed to open log file:", err) } // close logFile on exit checking for its error to ensure everything get written. defer func() { if err := logFile.Close(); err != nil { panic(err) } }() cdf.InitLog(logFile) // clear the screen since we are not in usage mode cdf.TermClear() cdf.LogInfo.Println("Running CDF:") // get config and show configFile, err := os.Open("config.json") if err != nil { log.Fatalln(err) } // close configFile on exit checking for its error: defer func() { if err := configFile.Close(); err != nil { panic(err) } }() if err := json.NewDecoder(configFile).Decode(&cdf.Config); err != nil { log.Fatalln(err) } if cdf.Config.Timeout == 0 { // we specify a default timeout cdf.Config.Timeout = 10 } cdf.LogInfo.Printf("config: %+v", cdf.Config) // disable logging if the setting is not set if !cdf.Config.VerboseLog && !*cdf.ForceVerbose { cdf.DisableLogFile() } // init prng var src = rand.NewSource(cdf.Config.Seed) cdf.Prng = rand.New(src) // depending on the selected interface, we run the according test function switch interf { case "dsa": err = cdf.TestDsa() break case "ecdsa": err = cdf.TestEcdsa() break case "enc": err = cdf.TestEnc() break case "rsaenc": err = cdf.TestRSAenc() break case "rsasign": err = cdf.TestRSAsign() break case "prf": err = cdf.TestPrf() break case "xof": err = cdf.TestXof() break } if err == nil { cdf.LogSuccess.Println("test completed without error!") } else { cdf.LogWarning.Println(err) } cdf.LogInfo.Println("exiting") } ================================================ FILE: makefile ================================================ BIN = cdf SRC = main.go .DEFAULT_GOAL = build .PHONY: clean format examples build: $(SRC) go build -o $(BIN) $^ run: $(SRC) go run $^ examples-go: $(SRC) cd examples/; make go examples-all: $(SRC) cd examples/; make format: $(SRC) $(foreach f, $(SRC), gofmt -w $(f)) test: go test -v ./cdf-lib clean: rm -f $(BIN); cd examples/; make clean