From 125fcf26017d959ff428d31b0209508877fb1df2 Mon Sep 17 00:00:00 2001 From: "J. Ayo Akinyele" Date: Wed, 25 Apr 2018 03:50:53 -0400 Subject: [PATCH] Initial commit --- CONTRIBUTORS | 13 + LICENSE | 661 +++++ Makefile | 58 + Makefile.common | 161 ++ README.md | 232 ++ VERSION | 1 + cli/Makefile | 39 + cli/README.md | 200 ++ cli/common.cpp | 177 ++ cli/common.h | 100 + cli/decrypt.cpp | 298 ++ cli/encrypt.cpp | 270 ++ cli/fuzzTest.sh | 192 ++ cli/keygen.cpp | 222 ++ cli/runBasicTest.sh | 137 + cli/runComplexTest.sh | 141 + cli/runTest.sh | 144 + cli/setup.cpp | 143 + deps/Makefile | 17 + deps/gtest/Makefile | 26 + deps/gtest/download_gtest.sh | 14 + deps/install_pkgs.sh | 354 +++ deps/openssl/Makefile | 30 + deps/openssl/download_openssl.sh | 43 + deps/relic/Makefile | 61 + deps/relic/download_relic.sh | 40 + deps/relic/run_install_clean.sh | 66 + env | 59 + examples/Makefile | 30 + examples/README.md | 5 + examples/test_cp.cpp | 65 + examples/test_km.cpp | 101 + examples/test_kp.cpp | 65 + examples/test_pk.cpp | 63 + platforms/android.sh | 300 ++ src/Makefile | 140 + src/Makefile.inc | 10 + src/abe/zcontextabe.cpp | 408 +++ src/abe/zcontextcca.cpp | 894 ++++++ src/abe/zcontextcpwaters.cpp | 396 +++ src/abe/zcontextkpgpsw.cpp | 369 +++ src/bench_libopenabe.cpp | 576 ++++ src/fuzz_attrlist.cpp | 98 + src/fuzz_policy.cpp | 133 + src/include/openabe/keys/zkdf.h | 73 + src/include/openabe/keys/zkey.h | 94 + src/include/openabe/keys/zkeystore.h | 91 + src/include/openabe/keys/zpkey.h | 64 + src/include/openabe/keys/zsymkey.h | 144 + .../openabe/low/abe/zcontextcpwaters.h | 68 + src/include/openabe/low/abe/zcontextkpgpsw.h | 75 + src/include/openabe/low/pke/zcontextpke.h | 135 + src/include/openabe/low/pksig/zcontextpksig.h | 91 + src/include/openabe/low/ske/zcontextske.h | 95 + src/include/openabe/openabe.h | 268 ++ src/include/openabe/openssl_init.h | 56 + src/include/openabe/tools/zlsss.h | 131 + src/include/openabe/tools/zprng.h | 206 ++ src/include/openabe/utils/zandroid.h | 62 + src/include/openabe/utils/zattributelist.h | 87 + src/include/openabe/utils/zbenchmark.h | 86 + src/include/openabe/utils/zbytestring.h | 501 ++++ src/include/openabe/utils/zciphertext.h | 88 + src/include/openabe/utils/zconstants.h | 127 + src/include/openabe/utils/zcontainer.h | 91 + src/include/openabe/utils/zcryptoutils.h | 90 + src/include/openabe/utils/zdriver.h | 205 ++ src/include/openabe/utils/zerror.h | 112 + src/include/openabe/utils/zexception.h | 79 + src/include/openabe/utils/zfunctioninput.h | 92 + src/include/openabe/utils/zinteger.h | 140 + src/include/openabe/utils/zkeymgr.h | 114 + src/include/openabe/utils/zpolicy.h | 198 ++ src/include/openabe/utils/zscanner.h | 91 + src/include/openabe/utils/zx509.h | 194 ++ src/include/openabe/zcontext.h | 78 + src/include/openabe/zcontextabe.h | 116 + src/include/openabe/zcontextcca.h | 192 ++ src/include/openabe/zcrypto_box.h | 202 ++ src/include/openabe/zml/zelement.h | 343 +++ src/include/openabe/zml/zelement_bp.h | 276 ++ src/include/openabe/zml/zelement_ec.h | 177 ++ src/include/openabe/zml/zelliptic.h | 80 + src/include/openabe/zml/zgroup.h | 60 + src/include/openabe/zml/zpairing.h | 87 + src/include/openabe/zobject.h | 81 + src/include/openabe/zsymcrypto.h | 130 + src/keys/zkdf.cpp | 164 ++ src/keys/zkey.cpp | 168 ++ src/keys/zkeystore.cpp | 326 +++ src/keys/zpkey.cpp | 232 ++ src/keys/zsymkey.cpp | 522 ++++ src/openabe.cpp | 485 ++++ src/openssl_init.cpp | 126 + src/pke/zcontextpke.cpp | 725 +++++ src/pksig/zcontextpksig.cpp | 451 ++++ src/profile_libopenabe.cpp | 338 +++ src/ske/zcontextske.cpp | 452 ++++ src/test_abe.cpp | 890 ++++++ src/test_keystore.cpp | 191 ++ src/test_libopenabe.cpp | 2404 +++++++++++++++++ src/test_pke.cpp | 124 + src/test_policy.cpp | 146 + src/test_ske.cpp | 261 ++ src/test_zml.cpp | 487 ++++ src/test_zml1.cpp | 565 ++++ src/test_zml2.cpp | 201 ++ src/test_zsym.cpp | 74 + src/tools/zlsss.cpp | 685 +++++ src/tools/zprng.cpp | 452 ++++ src/utils/zattributelist.cpp | 255 ++ src/utils/zbenchmark.cpp | 209 ++ src/utils/zciphertext.cpp | 217 ++ src/utils/zcontainer.cpp | 278 ++ src/utils/zcryptoutils.cpp | 354 +++ src/utils/zdriver.cpp | 841 ++++++ src/utils/zerror.cpp | 241 ++ src/utils/zfunctioninput.cpp | 107 + src/utils/zkeymgr.cpp | 387 +++ src/utils/zpolicy.cpp | 457 ++++ src/utils/zx509.cpp | 677 +++++ src/zcontext.cpp | 70 + src/zcrypto_box.cpp | 599 ++++ src/zml/zelement.c | 912 +++++++ src/zml/zelement_bp.cpp | 1320 +++++++++ src/zml/zelement_ec.cpp | 536 ++++ src/zml/zelliptic.cpp | 284 ++ src/zml/zgroup.cpp | 67 + src/zml/zpairing.cpp | 370 +++ src/zobject.cpp | 216 ++ src/zparser.yy | 198 ++ src/zscanner.ll | 179 ++ src/zsymcrypto.cpp | 478 ++++ 133 files changed, 33043 insertions(+) create mode 100644 CONTRIBUTORS create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Makefile.common create mode 100644 README.md create mode 100644 VERSION create mode 100644 cli/Makefile create mode 100644 cli/README.md create mode 100644 cli/common.cpp create mode 100644 cli/common.h create mode 100644 cli/decrypt.cpp create mode 100644 cli/encrypt.cpp create mode 100755 cli/fuzzTest.sh create mode 100644 cli/keygen.cpp create mode 100755 cli/runBasicTest.sh create mode 100755 cli/runComplexTest.sh create mode 100755 cli/runTest.sh create mode 100644 cli/setup.cpp create mode 100644 deps/Makefile create mode 100644 deps/gtest/Makefile create mode 100755 deps/gtest/download_gtest.sh create mode 100755 deps/install_pkgs.sh create mode 100644 deps/openssl/Makefile create mode 100755 deps/openssl/download_openssl.sh create mode 100644 deps/relic/Makefile create mode 100755 deps/relic/download_relic.sh create mode 100755 deps/relic/run_install_clean.sh create mode 100755 env create mode 100644 examples/Makefile create mode 100644 examples/README.md create mode 100644 examples/test_cp.cpp create mode 100644 examples/test_km.cpp create mode 100644 examples/test_kp.cpp create mode 100644 examples/test_pk.cpp create mode 100755 platforms/android.sh create mode 100644 src/Makefile create mode 100644 src/Makefile.inc create mode 100644 src/abe/zcontextabe.cpp create mode 100644 src/abe/zcontextcca.cpp create mode 100644 src/abe/zcontextcpwaters.cpp create mode 100644 src/abe/zcontextkpgpsw.cpp create mode 100644 src/bench_libopenabe.cpp create mode 100644 src/fuzz_attrlist.cpp create mode 100644 src/fuzz_policy.cpp create mode 100644 src/include/openabe/keys/zkdf.h create mode 100644 src/include/openabe/keys/zkey.h create mode 100644 src/include/openabe/keys/zkeystore.h create mode 100644 src/include/openabe/keys/zpkey.h create mode 100644 src/include/openabe/keys/zsymkey.h create mode 100644 src/include/openabe/low/abe/zcontextcpwaters.h create mode 100644 src/include/openabe/low/abe/zcontextkpgpsw.h create mode 100644 src/include/openabe/low/pke/zcontextpke.h create mode 100644 src/include/openabe/low/pksig/zcontextpksig.h create mode 100644 src/include/openabe/low/ske/zcontextske.h create mode 100644 src/include/openabe/openabe.h create mode 100644 src/include/openabe/openssl_init.h create mode 100644 src/include/openabe/tools/zlsss.h create mode 100644 src/include/openabe/tools/zprng.h create mode 100644 src/include/openabe/utils/zandroid.h create mode 100644 src/include/openabe/utils/zattributelist.h create mode 100644 src/include/openabe/utils/zbenchmark.h create mode 100644 src/include/openabe/utils/zbytestring.h create mode 100644 src/include/openabe/utils/zciphertext.h create mode 100644 src/include/openabe/utils/zconstants.h create mode 100644 src/include/openabe/utils/zcontainer.h create mode 100644 src/include/openabe/utils/zcryptoutils.h create mode 100644 src/include/openabe/utils/zdriver.h create mode 100644 src/include/openabe/utils/zerror.h create mode 100644 src/include/openabe/utils/zexception.h create mode 100644 src/include/openabe/utils/zfunctioninput.h create mode 100644 src/include/openabe/utils/zinteger.h create mode 100644 src/include/openabe/utils/zkeymgr.h create mode 100644 src/include/openabe/utils/zpolicy.h create mode 100644 src/include/openabe/utils/zscanner.h create mode 100644 src/include/openabe/utils/zx509.h create mode 100644 src/include/openabe/zcontext.h create mode 100644 src/include/openabe/zcontextabe.h create mode 100644 src/include/openabe/zcontextcca.h create mode 100644 src/include/openabe/zcrypto_box.h create mode 100644 src/include/openabe/zml/zelement.h create mode 100644 src/include/openabe/zml/zelement_bp.h create mode 100644 src/include/openabe/zml/zelement_ec.h create mode 100644 src/include/openabe/zml/zelliptic.h create mode 100644 src/include/openabe/zml/zgroup.h create mode 100644 src/include/openabe/zml/zpairing.h create mode 100644 src/include/openabe/zobject.h create mode 100644 src/include/openabe/zsymcrypto.h create mode 100644 src/keys/zkdf.cpp create mode 100644 src/keys/zkey.cpp create mode 100644 src/keys/zkeystore.cpp create mode 100644 src/keys/zpkey.cpp create mode 100644 src/keys/zsymkey.cpp create mode 100644 src/openabe.cpp create mode 100644 src/openssl_init.cpp create mode 100644 src/pke/zcontextpke.cpp create mode 100644 src/pksig/zcontextpksig.cpp create mode 100644 src/profile_libopenabe.cpp create mode 100644 src/ske/zcontextske.cpp create mode 100644 src/test_abe.cpp create mode 100644 src/test_keystore.cpp create mode 100644 src/test_libopenabe.cpp create mode 100644 src/test_pke.cpp create mode 100644 src/test_policy.cpp create mode 100644 src/test_ske.cpp create mode 100644 src/test_zml.cpp create mode 100644 src/test_zml1.cpp create mode 100644 src/test_zml2.cpp create mode 100644 src/test_zsym.cpp create mode 100644 src/tools/zlsss.cpp create mode 100644 src/tools/zprng.cpp create mode 100644 src/utils/zattributelist.cpp create mode 100644 src/utils/zbenchmark.cpp create mode 100644 src/utils/zciphertext.cpp create mode 100644 src/utils/zcontainer.cpp create mode 100644 src/utils/zcryptoutils.cpp create mode 100644 src/utils/zdriver.cpp create mode 100644 src/utils/zerror.cpp create mode 100644 src/utils/zfunctioninput.cpp create mode 100644 src/utils/zkeymgr.cpp create mode 100644 src/utils/zpolicy.cpp create mode 100644 src/utils/zx509.cpp create mode 100644 src/zcontext.cpp create mode 100644 src/zcrypto_box.cpp create mode 100644 src/zml/zelement.c create mode 100644 src/zml/zelement_bp.cpp create mode 100644 src/zml/zelement_ec.cpp create mode 100644 src/zml/zelliptic.cpp create mode 100644 src/zml/zgroup.cpp create mode 100644 src/zml/zpairing.cpp create mode 100644 src/zobject.cpp create mode 100644 src/zparser.yy create mode 100644 src/zscanner.ll create mode 100644 src/zsymcrypto.cpp diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 00000000..43bf75cc --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,13 @@ +Cryptography Design +------------------- +Brent Waters +Matthew Green +Susan Hohenberger Waters +J. Ayo Akinyele + + +Software Design and Development +------------------------------- +J. Ayo Akinyele +Matthew Green +Alan Dunn diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..dbbe3558 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 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 Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are 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. + + 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. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + 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 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 work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero 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 Affero 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 Affero 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 Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + 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 AGPL, see +. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..1e274076 --- /dev/null +++ b/Makefile @@ -0,0 +1,58 @@ +.PHONY: all clean deps src cli examples + +all: check-env deps src cli examples + +check-env: +ifndef ZROOT + $(error ZROOT is undefined. Need to source env file: . ./env) +endif + +INSTALL_PREFIX := /usr/local + +docs: + $(MAKE) -C docs + +deps: + $(MAKE) -C deps + +src: + $(MAKE) -C src + $(MAKE) -C cli + +cli: + $(MAKE) -C cli + +examples: + $(MAKE) -C examples + +install-deps: + mkdir -p $(INSTALL_PREFIX) + cp -r $(ZROOT)/deps/root/lib $(INSTALL_PREFIX) + cp -r $(ZROOT)/deps/root/include $(INSTALL_PREFIX) + cp -r $(ZROOT)/deps/root/bin $(INSTALL_PREFIX) + +install: install-deps + mkdir -p $(INSTALL_PREFIX)/bin + cp -r $(ZROOT)/root/lib $(INSTALL_PREFIX) + cp -r $(ZROOT)/root/include $(INSTALL_PREFIX) + install -m 755 $(ZROOT)/src/bench_libopenabe $(INSTALL_PREFIX)/bin + install -m 755 $(ZROOT)/src/profile_libopenabe $(INSTALL_PREFIX)/bin + install -m 755 $(ZROOT)/cli/oabe_{setup,keygen,enc,dec} $(INSTALL_PREFIX)/bin + +test: + (cd src && ./test_libopenabe) || exit 1 + (cd src && ./test_zml) || exit 1 + (cd src && ./test_abe) || exit 1 + (cd src && ./test_pke) || exit 1 + (cd src && ./test_ske) || exit 1 + (cd src && ./test_zsym) || exit 1 + (cd cli && echo "hello world!" > ./input.txt && ./runTest.sh input.txt) || exit 1 + +clean: + $(MAKE) -C src clean + $(MAKE) -C cli clean + $(MAKE) -C examples clean + $(RM) -r $(ZROOT)/root + +distclean: clean + $(MAKE) -C deps clean diff --git a/Makefile.common b/Makefile.common new file mode 100644 index 00000000..cd95cbf1 --- /dev/null +++ b/Makefile.common @@ -0,0 +1,161 @@ +# Shared Makefile for + +CC = g++ +CXX = g++ +ifndef LDLIBS +LDLIBS := -lgtest -lpthread +endif + +DEPS_INSTALL_ZROOT = $(ZROOT)/deps/root +OABE_LIB_ROOT = $(ZROOT)/root/lib +INCLUDE_ROOT = $(ZROOT)/root/include +LOCAL_LIB_ROOT = /usr/local/lib +LOCAL_INCLUDE = /usr/local/include +LOCAL_INSTALL_BIN = /usr/local/bin + +# Include locations +# Dependencies (C/C++) +CCFLAGS := -I$(DEPS_INSTALL_ZROOT)/include +CXXFLAGS := -I$(DEPS_INSTALL_ZROOT)/include +# Local includes (for generated headers from bison/flex) +CXXFLAGS += -I$(ZROOT)/src +# Common includes (C/C++) +CCFLAGS += -I$(INCLUDE_ROOT) +CXXFLAGS += -I$(INCLUDE_ROOT) + +RELIC_LIB = -lrelic -lrelic_ec +GMP_LIB = -lgmp +SSL_LIB = -lssl +CRYPTO_LIB = -lcrypto +RELIC_G = +# commit: 1e3f62a3823f7e3db9d403f724fd9d66f5b04cf8 (as of 7/18/17) +OPENSSL_VERSION := 1.1.1-dev + +# Set flags for C++ 11 +OLD_GPP = $(shell g++ --version | grep -q 4.6 && echo 1) +ifeq ($(OLD_GPP), 1) + CXX11FLAGS = -std=c++0x + CXXFLAGS += $(CXX11FLAGS) +else + CXX11FLAGS = -std=c++11 + CXXFLAGS += $(CXX11FLAGS) +endif + +# Set shared lib extension for each OS +DEPS_PACKAGES = relic openssl gtest +ADD_CFLAGS := +OS_CXXFLAGS := + +ifeq ($(OS), Windows_NT) + RELIC_OS := WINDOWS + # NOTE: relic build still broken for MINGW + DEPS_PACKAGES = openssl + WITH_BP := "with-bp" + OPENSSL_VERSION := 1.1.1-dev-bp + COMPILER_VARS := -G "MinGW Makefiles" -DSEED=WCGR + CMAKE_VARS := -DCMAKE_MAKE_PROGRAM=/mingw64/bin/mingw32-make -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc.exe -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++.exe CMAKE_INCLUDE_PATH="/usr/local/include" CMAKE_LIBRARY_PATH="/usr/local/lib" + SHLIB := dll + GTESTEXT := $(SHLIB) + CCFLAGS += -I$(LOCAL_INCLUDE) + # No need to set -fPIC for windows as all code is position independent by default. + CXXFLAGS += -DGTEST_USE_OWN_TR1_TUPLE=0 -I/usr/local/include/ -I/usr/include + SHFLAGS := -nostartfiles + OPENSSL_CONFIG := Configure mingw64 shared + # needed for static libs + OS_OBJS += /mingw64/x86_64-w64-mingw32/lib/dllcrt1.o + # for network func + OS_LIBS += -lwsock32 -lws2_32 + #ADD_FLAGS := +else + OS_NAME = $(shell uname -s) + ifeq ($(OS_NAME), Linux) + RELIC_OS = LINUX + SHFLAGS = -shared + SHLIB = so + GTESTEXT = $(SHLIB).0 + ifneq (,$(filter $(OS_FAMILY), fedora redhat)) + OS_CXXFLAGS += -I/usr/include + ifeq ($(OS_FAMILY), redhat) + OS_CXXFLAGS += -DOS_REDHAT_LINUX + else + OS_CXXFLAGS += -DOS_FEDORA_LINUX + endif + endif + CXXFLAGS += -fPIC -DGTEST_USE_OWN_TR1_TUPLE=0 $(OS_CXXFLAGS) + CCFLAGS += -fPIC + OPENSSL_CONFIG = config shared + ADD_CFLAGS += -Wno-implicit-function-declaration + endif + ifeq ($(OS_NAME), Darwin) + RELIC_OS = MACOSX + SHFLAGS = -dynamiclib -current_version 1.0 -compatibility_version 1.0 + SHLIB = dylib + GTESTEXT = 0.$(SHLIB) + # pull in headers installed via brew (for gmp/relic/openssl) + CXXFLAGS += -I$(LOCAL_INCLUDE) + # include the clang C++ standard library (as a result, enable TR1_TUPLE flag) + CXXFLAGS += -stdlib=libc++ -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-deprecated + # (Option to use GMP with OpenSSL?): -DOPENSSL_USE_GMP -lgmp + OPENSSL_CONFIG := Configure darwin64-x86_64-cc shared + ADD_CFLAGS += -Wno-implicit-function-declaration -Wno-macro-redefined + endif + # TODO: add check for ARM, etc +endif + +PTHREAD_LIB = -lpthread + +# Other flags +CXXFLAGS += -pthread +# Warnings/errors, for now turn off one warning as this makes ztk unusable +CXXFLAGS += -Wall +# Avoid integer overflow issues with these flags +# -Wtype-limits +CXXFLAGS += -fstrict-overflow -Wsign-compare + +# Add debug symbols (we must remove these in a production build) +CXXFLAGS += -g -O2 +# uncomment to enable Address sanitizer +#CXXFLAGS += -fsanitize=address -ggdb +# uncomment to switch to afl-fuzz +# CC="afl-gcc" # for linux +# CXX="afl-g++" +# CC="afl-clang" # for mac +# CXX="afl-clang++" + +LDFLAGS += -L$(DEPS_INSTALL_ZROOT)/lib -L$(OABE_LIB_ROOT) -L$(LOCAL_LIB_ROOT) + +# Zeutro Math library config: RELIC vs OPENSSL +# Look for environment variable ZML_LIB=with_openssl +OPENSSL_ZML = -DSSL_LIB_INIT +ifeq ($(ZML_LIB), with_openssl) + # openssl-only build for math ops + OPENSSL_ZML += -DBP_WITH_OPENSSL + CXXFLAGS += $(OPENSSL_ZML) + CCFLAGS += -g -O2 $(OPENSSL_ZML) +else + # relic-only build for math ops + CXXFLAGS += $(OPENSSL_ZML) + CCFLAGS += -g -O2 $(OPENSSL_ZML) $(ADD_CFLAGS) + OABELDLIBS = $(RELIC_LIB) + OABELDSHLIBS = $(RELIC_LIB) +endif +# remaining deps +OABELDLIBS += $(SSL_LIB) $(CRYPTO_LIB) +OABELDSHLIBS += $(SSL_LIB) $(CRYPTO_LIB) + +SHLIB_PATH = $(LDFLAGS) + +.DEFAULT_GOAL = all + +define COMMON_LIB_template +$(1): $(1)($$($(1)_OBJS)) + mkdir -p $(OABE_LIB_ROOT) + cp $$@ $(OABE_LIB_ROOT) + mkdir -p $(INCLUDE_ROOT) + -cp -r include/* $(INCLUDE_ROOT) +endef + +# COMMON_LIBS, and the objects they use must be defined *before* this +# file is included! +$(foreach library, $(COMMON_LIBS), \ + $(eval $(call COMMON_LIB_template,$(library)))) diff --git a/README.md b/README.md new file mode 100644 index 00000000..631ac338 --- /dev/null +++ b/README.md @@ -0,0 +1,232 @@ +# OpenABE + +OpenABE is a cryptographic library that incorporates a variety of attribute-based encryption (ABE) algorithms, industry standard cryptographic functions and tools, and an intuitive application programming interface (API). OpenABE is intended to allow developers to seamlessly incorporate ABE technology into applications that would benefit from ABE to protect and control access to sensitive data. OpenABE is designed to be easy to use and does not require developers to be encryption experts. + +This bundle includes full source code, examples and three main sources of documentation: + +1. OpenABE API Guide Document - explains how to install and use the library. +2. OpenABE Command-Line Utilities Document - shows how to use the included command-line tools, including benchmarking. +3. OpenABE Design Document - explains in detail the functionalities and algorithms implemented. + +For more information, visit . + +## What is Attribute-Based Encryption (ABE)? + +Encryption is a method of encoding data that protects the confidentiality of its contents from unauthorized attackers. Traditionally, encryption was viewed as a tool to enable secure communication between a sender and a targeted recipient of information. For example, one might wish to store a message such that it can only be decrypted by the user bob@xyz.org. + +Attribute-Based Encryption is a more expansive type of public key encryption that allows for flexible policy-based access controls that are cryptographically (that is, mathematically) enforced. Instead of encrypting data to a single user, it is now possible to encrypt it so that the data can be decrypted by anyone with credentials satisfying an arbitrary attribute-based access control policy. + +In OpenABE, any string can potentially serve as an attribute. In addition, attributes can be numeric values and policies can contain ranges over these values. The set of attributes used will depend on the designated application. + +In order to understand the capabilities of ABE, it helps to organize them logically into three variants. + +* **Content-Based Access Control** - for granting selective access later (e.g., cloud, email, big data, subpoenas). + + In an ABE system for content-based access control, attributes are associated with a ciphertext and the private key is associated with a policy over these attributes. (In academic literature, this variant is sometimes referred to as "Key-Policy" ABE.) +For example, a company could automatically encrypt all of its emails with the attributes being some (or all) of the 75 fields in Mail headers and then later the company can distribute a key to an analyst that allows for decryption of all emails that meet the policy of `To:engineering@corporation.com` OR (subject contains `cascade project` AND sent between `Dec 21, 2017` and `Jan 10, 2018`. + +* **Role-based Access Control** - for policies known at the time of encryption (e.g., classified documents, medical records). + + An ABE system for role-based access control "flips" the semantics of content-based access control. In such a system, attributes are associated with a private key and a policy (or boolean formula) is associated with the ciphertext. Here the attributes are often be associated with the credentials of a private key holder. (In academic literature this variant is sometimes referred to as "Ciphertext-Policy" ABE.) For instance, one could restrict a ciphertext only to female employees who have been with the company since 2012 and worked on the "HALE" software project. + + +* **Multi-authority Role-based Access Control** - for operating across organizational boundaries. + + One issue with role-based access control is that in many applications you may need to write access control policies that span across different administrative boundaries. In standard ABE, there is one authority that hands out private keys. However, in some applications, it is natural for different authorities to manage different attributes. A multi-authority ABE system allows one to associate a ciphertext with a policy written across attributes issued by different authorities. These authorities can operate independently and do not have to coordinate (or even be aware of) each other. + + For instance, the government might certify the attributes in a person's +driver's license (such as age), while a credit score company could distribute credentials about a user's credit score and an employer could distribute credentials about its employees. With this type of ABE, one can now send out a special offer +readable by anyone over age 50 with a strong credit score and a job at a local employer. + + +## What cryptographic algorithms are implemented in OpenABE? + +OpenABE is a C/C++ software library offering several attribute-based encryption (ABE) schemes together with other core cryptographic functionalities such as authenticated symmetric-key encryption, public key encryption, digital signatures, X.509 certificate handling, key derivation functions, pseudorandom generators and more. + +For the full cryptographic technical details inside OpenABE, see the included OpenABE Design Document. + +Application developers should not need to be cryptographic experts to use ABE. To make OpenABE as secure and user-friendly as possible, the following features are provided by default: + +1. Collusion-Resistant: Common pitfall in ABE scheme development; Alice and Bob should not be able to combine their private keys to decrypt a ciphertext that neither can decrypt on their own. Note: any attempt to "engineer" ABE from standard public key encryption usually falls to this attack. +2. Chosen Ciphertext Attack (CCA) Secure: Prevents serious and practical tampering attacks; most existing schemes in the academic literature only satisfy a weaker security notion (CPA-security). +3. Unrestricted Attributes: Attributes can be represented by any string (alternative: must enumerate every current and future attribute at system initialization) and can be used an unlimited number of times in a policy. + +OpenABE comes with support for efficient and optimized implementations of content-based and role-based ABE schemes. If your application requires multi-authority ABE (Zeutro's US Patent No. 8516244), that is available as part of a larger library called Zeutro's Toolkit (ZTK) that is available for commercial license. + +OpenABE comes with support for efficiently managing an ABE keystore (e.g., a method for storing and selecting private ABE keys for decryption of ABE ciphertexts), which is an essential part of any practical ABE implementation. See Zeutro's US Patent No. 9209974. + +For the full cryptographic technical details inside OpenABE, see the included OpenABE Design Document. + +## What platforms are supported in OpenABE? + +Currently, OpenABE can be installed in the following environments: +- Debian 7-9 and Ubuntu (12.04+) +- CentOS 6/7 and Red Hat Linux 6/7 +- Mac OS X (10.8+) +- Windows 7+ (via MINGW) +- Android (NDK r10e) + +## Installation + +This section describes the installation of the OpenABE source code (`libopenabe-1.0.0-src.tar.gz`) on various platforms. The OpenABE currently supports several operating systems including multiple versions/distros of Linux, Mac OS X and Windows. + +### Debian/Ubuntu-based Linux + +To compile OpenABE on Ubuntu or Debian Linux-based distro, first run the `deps/install_pkgs.sh` script from the source directory to install the OpenABE system-specific dependencies as follows: + + cd libopenabe-1.0.0/ + sudo ./deps/install_pkgs.sh + +Note that you only have to do this once per system setup. After completion, you can proceed to compile the OpenABE as follows: + + . ./env + make + make test + +All the unit tests should pass at this point and you can proceed to install the OpenABE in a standard location (`/usr/local`) as follows: + + sudo make install + +To change the installation path prefix, modify the `INSTALL_PREFIX` variable in `libopenabe-1.0.0/Makefile`. + +### CentOS and RedHat Linux + +As before, first run the script from the source directory to setup OpenABE dependencies: + + cd libopenabe-1.0.0/ + sudo ./deps/install_pkgs.sh + scl enable devtoolset-3 bash + +Note that you only have to do this once per system setup. After completion, you can proceed to compile the OpenABE as follows: + + . ./env + make + make test + +All the unit tests should pass at this point and you can proceed to install the OpenABE in a standard location (`/usr/local`) as follows: + + sudo make install + +To change the installation path prefix, modify the `INSTALL_PREFIX` variable in `libopenabe-1.0.0/Makefile`. + +### Mac OS X + +Note that for Mac OS X, you will need [homebrew](http://brew.sh/) installed prior to running the `deps/install_pkgs.sh` script. Then, do the following (you may require `sudo` on the second step): + + cd libopenabe-1.0.0/ + ./deps/install_pkgs.sh + +Note that you only have to do this once per system setup. After completion, you can proceed to compile the OpenABE as follows: + + . ./env + make + make test + +All the unit tests should pass at this point and you can proceed to install the OpenABE in a standard location (`/usr/local`) as follows: + + sudo make install + +To change the installation path prefix, modify the `INSTALL_PREFIX` variable in `libopenabe-1.0.0/Makefile`. + +### Windows + +To build OpenABE on Windows 7, 8, and 10, you will need to download and install Mingw-w64, +the GNU toolchain port for building Windows-native binaries. We use the Mingw-w64 port packaged +with Minimal SYStem 2 (MSYS2). MSYS2 is an emulated POSIX-compliant environment for building +software with GNU tooling (e.g., GCC), bash, and package management using Arch Linux's Pacman. +Binaries compiled with these compilers do not require `cygwin.dll` as they are standalone. + +1. Download `msys2-x86_64-latest.exe` and run it. Select `C:\` for the installation directory to avoid `PATH` resolution problems. + +2. Launch the MSYS2 shell and execute the following command: + + update-core + +3. Close the MSYS2 shell and launch the MinGW-w64 Win64 Shell. Note that after starting MSYS2, the prompt will indicate which version you have launched. + +4. Update the pre-installed MSYS2 packages (and install related tooling), close the shell when prompted to, and relaunch the MinGW-w64 Win64 Shell. Execute the following command to start the process: + + pacman -Sy + pacman -Su base-devel unzip git wget mingw-w64-i686-toolchain \ + mingw-w64-x86_64-toolchain mingw-w64-i686-cmake mingw-w64-x86_64-cmake + +5. Install the required third-party libraries by executing the following command: + + pacman -S gmp-devel mingw-w64-i686-boost mingw-w64-x86_64-boost \ + mingw-w64-x86_64-gtest mingw-w64-i686-gtest + +6. In the libopenabe directory, execute the following: + + . ./env + make + make test + +7. If all the unit tests pass, then proceed to install the library in a standard location: + + make install + +### Android + +To build OpenABE for Android, you will need to download and install the Android NDK. The NDK is a toolset that enables cross-compiling C and C++ for ARM and Android-specific libraries and implementations of standard libraries (e.g., GNU STL). We use Android NDK r10e and build on Debian 7. + +Download the Android NDK r10e at the following links: + +1. [For Windows-x86_64](http://dl.google.com/android/repository/android-ndk-r10e-windows-x86_64.zip) +2. [For Darwin/Mac OS X-x86_64](https://dl.google.com/android/repository/android-ndk-r10e-darwin-x86_64.zip) +3. [For Linux-x86_64](http://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip) + +Unzip the NDK to a directory of your choice. We unzip it to `/opt/android-ndk-r10e/` and will refer to this as `$ANDROID_NDK_ROOT` hereafter. + +We build all libraries outside of the OpenABE deps directory. We export the following variables to streamline and contain the build process with a standalone toolchain: + + export TOOLCHAIN_ARCH=arm-linux-androideabi-4.8 + export MIN_PLATFORM=android-14 + export INSTALLDIR=$HOME/android + +With these variables set, you can now make the standalone toolchain: + + $ANDROID_NDK_ROOT/build/tools/make-standalone-toolchain.sh \ + --toolchain=$TOOLCHAIN_ARCH --llvm-version=3.6 \ + --platform=$MIN_PLATFORM --install-dir=$INSTALLDIR + +Note that 32- and 64-bit architectures are supported for any platform API greater than android-14; However, 64-bit is not supported in the RELIC library for ARM-based processors. + +To build for Android, run the following: + + ./platforms/android.sh $ANDROID_NDK_ROOT $INSTALLDIR + +In the libopenabe directory, execute the following: + + . ./env $ANDROID_NDK_ROOT $INSTALLDIR + make src + +## Quick Start + +To compile example C++ apps that use the high-level OpenABE crypto box API, do the following: + + . ./env + make examples + cd examples/ + +Then, execute the test apps for each mode of encryption supported: + + ./test_kp + ./test_cp + ./test_pk + +You can also execute the example that demonstrates use of the keystore with ABE decryption: + + ./test_km + +## Copyright and License + +Copyright (c) 2018 Zeutro, LLC. All rights reserved. + +OpenABE is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +OpenABE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You can be released from the requirements of the GNU Affero General Public License and obtain additional features by purchasing a commercial license. +Buying such a license is mandatory if you engage in commercial activities involving OpenABE that do not comply with the open source requirements of the GNU Affero General Public License. + +For more information on commercial licenses, visit . diff --git a/VERSION b/VERSION new file mode 100644 index 00000000..3eefcb9d --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.0.0 diff --git a/cli/Makefile b/cli/Makefile new file mode 100644 index 00000000..30de4deb --- /dev/null +++ b/cli/Makefile @@ -0,0 +1,39 @@ +include ../src/Makefile.inc +include ../Makefile.common + +CUR_DIR = . +OBJS = common.o +BINOBJS = oabe_setup oabe_keygen oabe_enc oabe_dec +OABE_LIB = $(OABE_LIB_ROOT)/$(OABELIB) + +all: $(BINOBJS) + +clean: + -rm -rf *.o $(TESTOBJS) $(BINOBJS) $(OABELIB) + +install: $(BINOBJS) + for b in $(BINOBJS); do \ + $(INSTALL) -m 0755 $$b $(USERB); \ + done + +# NOTE: order of library matters: libztk first, then relic, then gmp +# if relic goes before ztk, then you'll see a bunch of undefined references to relic symbols! +oabe_setup: $(OBJS) + $(CXX) -o oabe_setup $(OBJS) -I../src/ $(CXXFLAGS) $(LDFLAGS) $(CUR_DIR)/setup.cpp $(OABE_LIB) $(OABELDLIBS) + +oabe_keygen: $(OBJS) + $(CXX) -o oabe_keygen $(OBJS) -I../src/ $(CXXFLAGS) $(LDFLAGS) $(CUR_DIR)/keygen.cpp $(OABE_LIB) $(OABELDLIBS) + +oabe_enc: $(OBJS) + $(CXX) -o oabe_enc $(OBJS) -I../src/ $(CXXFLAGS) $(LDFLAGS) $(CUR_DIR)/encrypt.cpp $(OABE_LIB) $(OABELDLIBS) + +oabe_dec: $(OBJS) + $(CXX) -o oabe_dec $(OBJS) -I../src/ $(CXXFLAGS) $(LDFLAGS) $(CUR_DIR)/decrypt.cpp $(OABE_LIB) $(OABELDLIBS) + +%.o: %.c + $(CC) $(CCFLAGS) -c $< + +%.o: %.cpp + $(CXX) -I../ $(CXXFLAGS) -c $< + +%.h: diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 00000000..e9e4993a --- /dev/null +++ b/cli/README.md @@ -0,0 +1,200 @@ +% OpenABE Command-Line Utilities Documentation +% Version 1.0 + +Introduction +============ + +The OpenABE toolkit is a C++ library that primarily implements different flavors of attribute-based encryption (ABE) algorithms that can be used across a variety of data-at-rest applications. + +The OpenABE command-line utilities provide a set of programs that use the general OpenABE API for implementing ciphertext-policy attribute-based encryption (CP-ABE), key-policy attribute-based encryption (KP-ABE), and public-key encryption (PKEnc). + +The OpenABE incorporates best practices in encryption algorithm design which includes security against chosen ciphertext attacks and performing authenticated encryption of large data objects. Thus, note that the programs (that comprise the OpenABE command-line utilities) use the chosen-ciphertext secure version of each encryption algorithm. + +OpenABE CLI Description +============== + +The OpenABE command-line utilities consists of four command-line tools for performing various operations on each type of encryption algorithm supported in the OpenABE: + +* `oabe_setup`: Generates master public parameters and a master secret key for any one of ABE algorithms supported. + + OpenABE command-line: system setup utility, v1.0 + usage: [ -s scheme ] [ -p prefix ] -v + -v : turn on verbose mode + -s : scheme types are 'CP' or 'KP' + -p : prefix for generated authority public \ + and secret parameter files (optional) + +* `oabe_keygen`: Generates a private key with a given set of attributes if CP-ABE or a given policy formula if KP-ABE. This program also generates a public and private keypair for PKEnc given a user identity string. + + OpenABE command-line: key generation utility, v1.0 + usage: [ -s scheme ] [ -p prefix ] [ -i input ] [ -o output file ] -v + -v : turn on verbosity + -s : scheme types are 'PK', 'CP' or 'KP' + -i : key id for 'PK', attribute list for 'CP' and policy for 'KP' + -o : output file for generated secret key + -p : prefix for generated authority public \ + and secret parameter files (optional) + +* `oabe_enc`: Encrypts a file according to a policy if CP-ABE, or a set of attributes if KP-ABE. Or it can encrypt a file to a specific user identity if public-key encryption. + + OpenABE command-line: encryption utility, v1.0 + usage: [ -s scheme ] [ -p prefix ] [ -e enc input ] \ + [ -i input ] [ -o output ] -v + -v : turn on verbosity + -s : scheme types are 'PK', 'CP' or 'KP' + -e : sender key Id for 'PK', policy for 'CP' \ + or attribute list for 'KP' + -r : recipient key Id for 'PK' + -i : input file + -o : output file for ciphertext + -p : prefix for generated authority public \ + and secret parameter files (optional) + +* `oabe_dec`: Decrypts a file that contains ciphertext using a specified private key. + + OpenABE command-line: decryption utility, v1.0 + usage: [ -s scheme ] [ -p prefix ] [ -k key ] \ + [ -i ciphertext ] [ -o output ] -v + -v : turn on verbosity + -s : scheme types are 'CP' or 'KP' + -k : recipient key Id for 'PK' and secret key file for 'CP'/'KP' + -e : sender key Id for 'PK' + -i : ciphertext file + -o : output file for plaintext + -p : prefix for generated authority public + and secret parameter files (optional) + +By default, the generated master public and secret parameters are stored in and loaded from the current working directory. + +Quick Tutorial +============== + +This section provides a tutorial on how to use each program in the OpenABE command-line utilities for encrypting and decrypting files with attribute-based encryption or public-key encryption: + +## Ciphertext-Policy Attribute-based Encryption (CP-ABE) + +In a CP-ABE system, attributes are associated with users and policies are associated with ciphertexts. A user can decrypt a ciphertext if and only if her attributes satisfy the policy. +For example, Alice has attributes `Female`, `Nurse`, `Floor=3`, `Respiratory-Specialist`. Charlie has attributes `Male`, `Doctor`, `Floor=5`, `Cardiologist`. +Bob encrypts a patient's medical file for staff members matching the policy `(Doctor OR Nurse) AND (Floor <= 3 AND Floor < 5)`. Alice is able to open this patient's file but Charlie cannot. + +This system provides role-based access control and works well when the encryption policies are known beforehand, $e.g.$, technical reports, HR documents, medical records. See the example below: + + # Generate system parameters with file name prefix "org1" + ./oabe_setup -s CP -p org1 + + # Generate key for alice + ./oabe_keygen -s CP -p org1 -i "Female|Nurse|Floor=3|RespSpecialist" \ + -o aliceCP + + # Generate key for charlie + ./oabe_keygen -s CP -p org1 -i "Male|Doctor|Floor=5|Cardiologist" \ + -o charlieCP + + # Encrypt such that alice can decrypt but charlie cannot + # Floor range portion is thesame as (Floor > 2 and Floor < 5) + ./oabe_enc -s CP -p org1 -e "((Doctor or Nurse) and (Floor in (2-5)))" \ + -i input.txt -o input.cpabe + + # Decrypt using charlie's key -- should fail + ./oabe_dec -s CP -p org1 -k charlieCP.key -i input.cpabe \ + -o plainFail.input.txt + + # Decrypt using alice's key -- should pass + ./oabe_dec -s CP -p org1 -k aliceCP.key -i input.cpabe \ + -o plainOK.input.txt + + +## Key-Policy Attribute-based Encryption (KP-ABE) + +In a KP-ABE system, policies are associated with users (that is, their private keys) and attributes are associated with ciphertexts. A user can decrypt a ciphertext if and only if its attributes satisfy her (private key's) policy. + +For example, Company Y maintains a record of its emails, where each email is encrypted with a set of attributes associated with the meta-data of that email, e.g., to, from, subject, date, IP address, etc. Later, it is discovered that sensitive information was leaked by employee Alice during the last week of February 2017 or first two weeks of March 2017. Company Y can generate a key that allows an auditor to open any emails matching the policy `(From:Alice AND (Dated = March 1-14, 2017 OR Dated = February 22-28, 2017))`. This grants an auditor access to the slice of information he needs without allowing him to view the entire email database. + +This system is well-suited for granting access to slices of data (also called content-based access control). For example, releasing information to an analyst or auditor, responding to a subpoena, searching in email, cloud or other big data applications. See the example below: + + # Generate system parameters with file name prefix "org2" + ./oabe_setup -s KP -p org2 + + # Generate key slice for analyst + ./oabe_keygen -s KP -p org2 -i "(From:Alice and (Date = March 1-14, 2017 \ + or Date = February 22-28, 2017))" -o analystKP + + + # Encrypt with metadata from email + ./oabe_enc -s KP -p org2 -e "From:Alice|To:Bob|Date = March 7, 2017" \ + -i input.txt -o input1.kpabe + + ./oabe_enc -s KP -p org2 -e "From:Alice|To:Charlie|Date = March 15, 2017" \ + -i input.txt -o input2.kpabe + + # Decrypt input1.kpabe using analyst key -- should pass + ./oabe_dec -s KP -p org2 -k analystKP.key \ + -i input1.kpabe -o ok.input.txt + + # Decrypt input2.kpabe using analyst key -- should fail + ./oabe_dec -s KP -p org2 -k analystKP.key \ + -i input2.kpabe -o fail.input.txt + + +## Public-key Encryption (PKE) + +For cases where traditional public-key encryption is desired, we provide such an encryption scheme in the OpenABE command-line utilities. This works in the usual way by allowing encryption with individual public keys. See the example below: + + # Generate public and private key for alice (-i denotes the user's identifier) + ./oabe_keygen -s PK -i alice + + # Generate public and private key for bob + ./oabe_keygen -s PK -i bob + + # Generate public and private key for eve + ./oabe_keygen -s PK -i eve + + # Encrypt input.txt from alice to bob + ./oabe_enc -s PK -e alice -r bob -i input.txt -o input.pkenc + + # Note that -e = sender and -r = receiver + # Decrypt as eve -- should fail + ./oabe_dec -s PK -e alice -r eve -i input.pkenc -o fail.input.txt + + # Decrypt as bob -- should pass + ./oabe_dec -s PK -e alice -r bob -i input.pkenc -o ok.input.txt + +Attributes and Data Structures +=============== + +## Attributes + +Attributes can be any alphanumeric string and are not restricted or fixed at system initialization time. Attributes also includes printable symbols/characters such as `$, &, #, %` and so on. We illustrate here our specific approach for representing attributes. In the OpenABE, attributes are in two parts: `{type}: {value}`. An optional $type$ part that indicates the type of attribute being represented and a $value$ part that represents the actual attribute string. This $type$ field serves as a way of capturing namespaces or domains for attributes. For example, `system:attribute1` could indicate that a specific $attribute1$ is a system-only type attribute. Alternatively, the $type$ could be used to encode an authority's identity and domain of attributes (e.g. for Multi-Authority ABE). + +We also represent numbers as attributes. Specifically, to represent the numerical attribute `a = k` for some $n$-bit integer $k$, we convert the comparison into a $binary$ representation which produces $n$ (non-numerical) attributes which specify the value of each bit in $k$ (up to 32-bits). As an optimization, we support specifying how many bits to use when representing the value $k$ with a simple encoding such as `a = k#b`. Here, $b$ denotes the number of bits necessary to represent $k$. Note that we do a sanity check to make sure that all of $k$ can be represented with $b$ bits. + +## Keys and Ciphertexts + +Each OpenABE key and ciphertext structure includes a header that describes some metadata. This metadata includes the encryption scheme identifier, the underlying elliptic curve (or pairing curve) identifier, the OpenABE library version number and a unique 128-bit object identifier. In the case of the ciphertext, the header metadata is protected against tampering attacks along with the ciphertext body. + + +Benchmarking +============ + +The OpenABE is built on top of the abstract Zeutro Math library which supplies all of our elliptic-curve operations. We instantiate our schemes using the state-of-the-art Barreto-Naehrig (BN) curves with the embedding degree `k = 12` (or commonly referred to as `BN-254`). This particular asymmetric curve is known to yield a very efficient pairing implementation and a security level equivalent to `AES-128`. As a result, this boosts the overall performance of ABE scheme implementations over prior efforts. Other benefits of BN curves include the ability to compress the representation of group elements. This directly translates to making ABE ciphertexts more compact which considerably reduces transmission costs. + +We include a benchmark utility for all the ABE schemes provided in the OpenABE: + + Math Library: RELIC + OpenABE benchmark utility, v1.0 + Usage bench_libopenabe: [ scheme => 'CP' or 'KP' ] [ iterations ] \ + [ attributes ] [ 'fixed' or 'range' ] [ 'cpa' or 'cca'] + -scheme: the type of ABE scheme to benchmark + -iterations: the number of iterations per test + -attributes: the number of attributes in the policy or \ + attribute list for encryption + -'fixed' or 'range': run with a fixed number of attributes \ + or as a range from 1 to num. attributes + -'cpa' or 'cca': chosen-plaintext secure vs chosen-ciphertext \ + secure versions + +For example, the command below shows how to benchmark the CCA-secure KP-ABE implementation with 100 attributes for encryption (averaged over 10 iterations). Moreover, the generated decryption key policy will have 100 attributes and each attribute will be involved in the decryption. + + bench_libopenabe KP 10 100 fixed cca + + diff --git a/cli/common.cpp b/cli/common.cpp new file mode 100644 index 00000000..8d5f11e2 --- /dev/null +++ b/cli/common.cpp @@ -0,0 +1,177 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file common.cpp +/// +/// \brief Common routines and shared functionality +/// +/// \author J. Ayo Akinyele +/// + +#include "common.h" + +using namespace std; +using namespace oabe; + +void getFile(std::string &result, const std::string &filename) { + result.clear(); + + fstream fs(filename, fstream::in); + if (fs.fail()) { + string msg = "Could not open file "; + msg += filename; + throw ios_base::failure(msg); + } + + fs.exceptions(fstream::badbit); + while (!fs.eof()) { + char buf[512]; + fs.read(buf, sizeof(buf)); + result.append(buf, fs.gcount()); + } + + fs.close(); +} + + +OpenABE_SCHEME checkForScheme(string type, string &suffix) +{ + suffix.clear(); + if(type == CP_ABE) { + suffix = ".cpabe"; + return OpenABE_SCHEME_CP_WATERS; + } else if(type == KP_ABE) { + suffix = ".kpabe"; + return OpenABE_SCHEME_KP_GPSW; + } else if(type == PK_ENC) { + suffix = ".pkenc"; + return OpenABE_SCHEME_PK_OPDH; + } else { + return OpenABE_SCHEME_NONE; + } +} + +void addNameSeparator(string &prefix) +{ + // check if last character of prefix is a name separator (if not, add it) + if(prefix.size() > 0 && prefix[prefix.size()-1] != NAME_SEP) { + prefix += NAME_SEP; + } + return; +} + +// adds an extension if not present +void addFileExtension(string &filename, string ext) +{ + if(filename.find(ext) == string::npos) { + filename += ext; + } + return; +} + +void WriteToFile(const char* filename, string outputStr) +{ + ofstream file; + file.open(filename); + file << outputStr; + file.close(); +} + +string ReadFile(const char* filename) +{ + ifstream input(filename); + string line = ""; + // read everthing between the headers + if (input.is_open()) { + while(getline(input, line)) { + /* finish this + if(line.compare(begin_header) == 0) + continue; + */ + if(line.find(BLOCK) == std::string::npos) { + break; + } + } + input.close(); + } + + return Base64Decode(line); +} + +string ReadBlockFromFile(const char* begin_header, const char* end_header, const char* filename) +{ + ifstream input(filename); + string block = "", line; + bool found_header = false; + // read everthing between the headers + if(input.is_open()) { + while(getline(input, line)) { + if(line.compare(begin_header) == 0) { + found_header = true; + continue; + } + else if(line.compare(end_header) == 0) { + break; + } + if(found_header) block = line; + } + input.close(); + } + + return Base64Decode(block); +} + +void WriteBinaryFile(const char* filename, string& outputStr) +{ + ofstream file; + file.open(filename, ios::out | ios::binary); + file << outputStr; + file.close(); +} + +void WriteBinaryFile(const char* filename, uint8_t *buf, uint32_t len) +{ + ofstream file; + file.open(filename, ios::out | ios::binary); + // file << outputStr; + file.write((const char *) buf, (int) len); + file.close(); +} + +string ReadBinaryFile(const char* filename) +{ + ifstream input(filename, ios::binary); + string inputBlob = "", line; + // read everthing between the headers + if(input.is_open()) { + while(getline(input, line)) { + inputBlob += line + "\n"; + } + input.close(); + } + + return inputBlob; +} diff --git a/cli/common.h b/cli/common.h new file mode 100644 index 00000000..755eeb74 --- /dev/null +++ b/cli/common.h @@ -0,0 +1,100 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file common.cpp +/// +/// \brief Common routines and shared functionality +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_PARAMETER_STRING DEFAULT_BP_PARAM // "BN_P256" +#define DEFAULT_NIST_PARAM_STRING DEFAULT_EC_PARAM // "NIST_P256" +#define OpenABE_CLI_STRING "OpenABE command-line: " + +//#define DEFAULT_SECURITY_LEVEL 128 +//#define SYM_KEY_BYTES 16 +#define MAX_FILE_SIZE ULONG_MAX /* up to 4GB (or 2^32-1 bytes) */ +#define PK_ENC "PK" +#define CP_ABE "CP" +#define KP_ABE "KP" + +#define MPK_ID "mpk" +#define MSK_ID "msk" +#define SK_ID "decKey" + +#define MPK_FILENAME "mpk.cpabe" +#define MSK_FILENAME "msk.cpabe" +#define NAME_SEP '.' +#define KEY_SUFFIX ".key" + +#define BLOCK "BLOCK" +/* encloses mpk */ +#define NL "\n" + +#define MPK_BEGIN_HEADER "-----BEGIN MASTER PUBLIC KEY BLOCK-----\n" +#define MPK_END_HEADER "\n-----END MASTER PUBLIC KEY BLOCK-----\n" +/* encloses msk */ +#define MSK_BEGIN_HEADER "-----BEGIN MASTER SECRET KEY BLOCK-----\n" +#define MSK_END_HEADER "\n-----END MASTER SECRET KEY BLOCK-----\n" +/* encloses pk */ +#define PK_BEGIN_HEADER "-----BEGIN USER PUBLIC KEY BLOCK-----\n" +#define PK_END_HEADER "\n-----END USER PUBLIC KEY BLOCK-----\n" +/* encloses sk */ +#define SK_BEGIN_HEADER "-----BEGIN USER PRIVATE KEY BLOCK-----\n" +#define SK_END_HEADER "\n-----END USER PRIVATE KEY BLOCK-----\n" +/* encloses the abe ciphertext */ +#define CT1_BEGIN_HEADER "-----BEGIN ABE CIPHERTEXT BLOCK-----" +#define CT1_END_HEADER "-----END ABE CIPHERTEXT BLOCK-----" +/* encloses the ciphertext for symmetric key encryption portion */ +#define CT2_BEGIN_HEADER "-----BEGIN CIPHERTEXT BLOCK-----" +#define CT2_END_HEADER "-----END CIPHERTEXT BLOCK-----" + +void getFile(std::string &result, const std::string &filename); +std::string ReadFile(const char* filename); +std::string ReadBlockFromFile(const char* begin_header, const char* end_header, const char* filename); +std::string ReadBinaryFile(const char* filename); +void WriteToFile(const char* filename, std::string outputStr); +void WriteBinaryFile(const char* filename, std::string& outputStr); +void WriteBinaryFile(const char* filename, uint8_t *buf, uint32_t len); + +OpenABE_SCHEME checkForScheme(std::string type, std::string &suffix); +void addNameSeparator(std::string &prefix); +void addFileExtension(std::string &filename, std::string ext); + +#endif /* common header */ diff --git a/cli/decrypt.cpp b/cli/decrypt.cpp new file mode 100644 index 00000000..b0cf8caa --- /dev/null +++ b/cli/decrypt.cpp @@ -0,0 +1,298 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file decrypt.cpp +/// +/// \brief OpenABE decryption utility +/// +/// \author J. Ayo Akinyele +/// + +#include "common.h" + +using namespace std; +using namespace oabe; + +#define USAGE \ + "usage: [ -s scheme ] [ -p prefix ] [ -k key ] [ -i ciphertext ] [ -o output ] -v\n\n" \ + "\t-v : turn on verbosity\n" \ + "\t-s : scheme types are 'PK', 'CP' or 'KP'\n" \ + "\t-k : recipient key Id for 'PK' and secret key file for 'CP'/'KP'\n" \ + "\t-e : sender key Id for 'PK'\n" \ + "\t-i : ciphertext file \n" \ + "\t-o : output file for plaintext\n" \ + "\t-p : prefix for generated authority public and secret parameter files (optional)\n\n" \ + +bool getPublicKey(OpenABEByteString& publicKey, string& id, string& suffix) { + const string pubKeyFile = id + ".pk" + suffix; + publicKey = ReadFile(pubKeyFile.c_str()); + if (publicKey.size() == 0) { + cerr << "public key file not encoded properly in: " << pubKeyFile << endl; + return false; + } + return true; +} + +bool getPrivateKey(OpenABEByteString& privateKey, string& id, string& suffix) { + const string privKeyFile = id + ".sk" + suffix; + privateKey = ReadFile(privKeyFile.c_str()); + if (privateKey.size() == 0) { + cerr << "private key file not encoded properly in: " << privKeyFile << endl; + return false; + } + return true; +} + + +int runPkDecrypt(string& suffix, string& sender_id, string& recipient_id, + string& ciphertextFile, string& outputFile, bool verbose) { + OpenABE_ERROR result = OpenABE_NOERROR; + int err_code = 0; + // load public key file for the recipient + OpenABEByteString send_PublicKey, recp_PrivateKey, ctBlob; + string plaintext; + try { + if (!getPublicKey(send_PublicKey, sender_id, suffix)) { + cerr << "unable to load the public key: " << sender_id << endl; + return -1; + } + if (!getPrivateKey(recp_PrivateKey, recipient_id, suffix)) { + cerr << "unable to load the private key: " << recipient_id << endl; + return -1; + } + + ctBlob = ReadBlockFromFile(CT2_BEGIN_HEADER, CT2_END_HEADER, ciphertextFile.c_str()); + if (ctBlob.size() == 0) { + cerr << "ciphertext not encoded properly." << endl; + return -1; + } + + unique_ptr schemeContext = OpenABE_createContextPKESchemeCCA(OpenABE_SCHEME_PK_OPDH); + if (schemeContext == nullptr) { + cerr << "unable to create a new context" << endl; + return -1; + } + + // Generate a set of parameters for an ABE authority + if ( (result = schemeContext->generateParams(DEFAULT_NIST_PARAM_STRING)) != OpenABE_NOERROR) { + cerr << "unable to generate curve parameters: " << DEFAULT_NIST_PARAM_STRING << endl; + throw result; + } + + string sen_pkID = "public_" + sender_id; + string rec_skID = "private_" + recipient_id; + if ((result = schemeContext->loadPublicKey(sen_pkID, send_PublicKey)) != OpenABE_NOERROR) { + cerr << "unable to load the sender's public key: " << sen_pkID << endl; + throw result; + } + + if ((result = schemeContext->loadPrivateKey(rec_skID, recp_PrivateKey)) != OpenABE_NOERROR) { + cerr << "unable to load the recipient's private key: " << rec_skID << endl; + throw result; + } + + unique_ptr ciphertext(new OpenABECiphertext); + ciphertext->loadFromBytes(ctBlob); + if ((result = schemeContext->decrypt(sen_pkID, rec_skID, plaintext, ciphertext.get())) != OpenABE_NOERROR) { + cerr << "error while decrypting PK-encrypted object: " << ciphertextFile << endl; + throw result; + } + + err_code = 0; + if(verbose) { + cout << "writing " << plaintext.size() << " bytes to " << outputFile << endl; + } + WriteBinaryFile(outputFile.c_str(), (uint8_t *) plaintext.c_str(), plaintext.size()); + + } catch (OpenABE_ERROR & error) { + cout << "caught exception: " << OpenABE_errorToString(error) << endl; + err_code = error; + } + + return err_code; +} + +int runAbeDecrypt(OpenABE_SCHEME scheme_type, string& prefix, string& suffix, + string& skFile, string& ciphertextFile, string& outputFile, bool verbose) +{ + OpenABE_ERROR result = OpenABE_NOERROR; + std::unique_ptr schemeContext = nullptr; + std::unique_ptr ciphertext1 = nullptr, ciphertext2 = nullptr; + + int err_code = 0; + string mpkID = MPK_ID, skID = skFile; + string mpkFile = MPK_ID + suffix; + if(prefix != "") { + mpkFile = prefix + mpkFile; + } + // read the file + OpenABEByteString mpkBlob, skBlob, ct1Blob, ct2Blob; + string plaintext; + + try { + // Initialize a OpenABEContext structure + schemeContext = OpenABE_createContextABESchemeCCA(scheme_type); + if (schemeContext == nullptr) { + cerr << "unable to create a new context" << endl; + return -1; + } + + // load KP/CP public params + mpkBlob = ReadFile(mpkFile.c_str()); + if (mpkBlob.size() == 0) { + cerr << "master public parameters not encoded properly." << endl; + return -1; + } + + if ((result = schemeContext->loadMasterPublicParams(mpkID, mpkBlob)) != OpenABE_NOERROR) { + cerr << "unable to load the master public parameters" << endl; + throw result; + } + + skBlob = ReadFile(skFile.c_str()); + if (skBlob.size() == 0) { + cerr << "secret key not encoded properly." << endl; + return -1; + } + + ct1Blob = ReadBlockFromFile(CT1_BEGIN_HEADER, CT1_END_HEADER, ciphertextFile.c_str()); + if (ct1Blob.size() == 0) { + cerr << "ABE ciphertext not encoded properly." << endl; + return -1; + } + + // Load the ciphertext components + ciphertext1.reset(new OpenABECiphertext); + ciphertext1->loadFromBytes(ct1Blob); + + ct2Blob = ReadBlockFromFile(CT2_BEGIN_HEADER, CT2_END_HEADER, ciphertextFile.c_str()); + if (ct2Blob.size() == 0) { + cerr << "AEAD ciphertext not encoded properly." << endl; + } + + if (verbose) { + cout << "read " << ct1Blob.size() << " bytes" << endl; + cout << "read " << ct2Blob.size() << " bytes" << endl; + } + } catch (OpenABE_ERROR& error) { + cout << "caught exception: " << OpenABE_errorToString(error) << endl; + err_code = error; + return err_code; + } + + try { + // now we can load the user's secret key + if ((result = schemeContext->loadUserSecretParams(skID, skBlob)) != OpenABE_NOERROR) { + cerr << "Unable to load user's decryption key" << endl; + throw result; + } + + ciphertext2.reset(new OpenABECiphertext); + ciphertext2->loadFromBytesWithoutHeader(ct2Blob); + + // now we can decrypt + if ((result = schemeContext->decrypt(mpkID, skID, plaintext, ciphertext1.get(), ciphertext2.get())) != OpenABE_NOERROR) { + throw result; + } + + err_code = 0; + if(verbose) { + cout << "writing " << plaintext.size() << " bytes to " << outputFile << endl; + } + WriteBinaryFile(outputFile.c_str(), (uint8_t *)plaintext.c_str(), plaintext.size()); + } catch (OpenABE_ERROR & error) { + cout << "caught exception: " << OpenABE_errorToString(error) << endl; + err_code = error; + } + + return err_code; +} + +int main(int argc, char **argv) +{ + if(argc <= 1) { + cout << OpenABE_CLI_STRING << "decryption utility, v" << (OpenABE_LIBRARY_VERSION / 100.) << endl; + fprintf(stderr, USAGE); + exit(-1); + } + int opt; + string scheme_name, prefix, suffix; + string mpk_file, sender_id, recipient_id, key_file, ciphertext_file, out_file; + bool verbose = false; + while ((opt = getopt(argc,argv,"e:k:p:s:i:o:r:v")) != EOF) + { + switch(opt) + { + case 'e': sender_id = string(optarg); break; + case 's': scheme_name = string(optarg); break; + case 'p': prefix = string(optarg); break; + case 'k': key_file = string(optarg); break; + case 'i': cout << "ciphertext: "<< optarg << endl; ciphertext_file = optarg; break; + case 'r': recipient_id = string(optarg); break; + case 'o': out_file = optarg; break; + case 'v': verbose = true; break; + case '?': fprintf(stderr, USAGE); + default: cout<. +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file encrypt.cpp +/// +/// \brief OpenABE encryption utility. +/// +/// \author J. Ayo Akinyele +/// + +#include "common.h" + +using namespace std; +using namespace oabe; + +#define USAGE \ + "usage: [ -s scheme ] [ -p prefix ] [ -e encryption input ] [ -i input ] [ -o output ] -v\n\n" \ + "\t-v : turn on verbosity\n" \ + "\t-s : scheme types are 'PK', 'CP' or 'KP'\n" \ + "\t-e : sender key Id for PK, policy string for 'CP' or attribute list for 'KP'\n" \ + "\t-r : recipient key Id for PK\n" \ + "\t-i : input file\n" \ + "\t-o : output file for ciphertext\n" \ + "\t-p : prefix for generated authority public and secret parameter files (optional)\n\n" \ + +bool getPublicKey(OpenABEByteString& publicKey, string& id, string& suffix) { + const string pubKeyFile = id + ".pk" + suffix; + publicKey = ReadFile(pubKeyFile.c_str()); + if (publicKey.size() == 0) { + cerr << "public key file not encoded properly in: " << pubKeyFile << endl; + return false; + } + return true; +} + +void runPkEncrypt(string& suffix, string& sender_id, string& recipient_id, + string& inputStr, string& ciphertextFile, bool verbose) { + + OpenABE_ERROR result = OpenABE_NOERROR; + // load public key file for the recipient + OpenABEByteString send_PublicKey, recp_PublicKey, ctBlob; + try { + if (!getPublicKey(send_PublicKey, sender_id, suffix)) { + return; + } + if (!getPublicKey(recp_PublicKey, recipient_id, suffix)) { + return; + } + + unique_ptr schemeContext = OpenABE_createContextPKESchemeCCA(OpenABE_SCHEME_PK_OPDH); + if (schemeContext == nullptr) { + cerr << "unable to create a new context" << endl; + return; + } + + // Generate a set of parameters for an ABE authority + if ( (result = schemeContext->generateParams(DEFAULT_NIST_PARAM_STRING)) != OpenABE_NOERROR) { + cerr << "unable to generate curve parameters: " << DEFAULT_NIST_PARAM_STRING << endl; + throw result; + } + + string sen_pkID = "public_" + sender_id; + string rec_pkID = "public_" + recipient_id; + if ((result = schemeContext->loadPublicKey(sen_pkID, send_PublicKey)) != OpenABE_NOERROR) { + cerr << "unable to load the sender's public key: " << rec_pkID << endl; + throw result; + } + + if ((result = schemeContext->loadPublicKey(rec_pkID, recp_PublicKey)) != OpenABE_NOERROR) { + cerr << "unable to load the recipient's public key: " << rec_pkID << endl; + throw result; + } + + unique_ptr ciphertext(new OpenABECiphertext); + if ((result = schemeContext->encrypt(nullptr, rec_pkID, sen_pkID, inputStr, ciphertext.get())) != OpenABE_NOERROR) { + cerr << "error while trying to encrypt input file" << endl; + throw result; + } + + // write ciphertext out + ciphertext->exportToBytes(ctBlob); + string ctBlobStr = CT2_BEGIN_HEADER; + ctBlobStr += NL + Base64Encode(ctBlob.getInternalPtr(), ctBlob.size()) + NL; + ctBlobStr += CT2_END_HEADER; + ctBlobStr += NL; + + if (verbose) { + cout << "writing " << ctBlob.size() << " bytes" << endl; + } + WriteToFile(ciphertextFile.c_str(), ctBlobStr); + + } catch (OpenABE_ERROR& error) { + cout << "caught exception: " << OpenABE_errorToString(error) << endl; + } + + return; +} + + +void runAbeEncrypt(OpenABE_SCHEME scheme_type, string& prefix, string& suffix, string& func_input, + string& inputStr, string& ciphertextFile, bool verbose) +{ + OpenABE_ERROR result = OpenABE_NOERROR; + std::unique_ptr schemeContext = nullptr; + std::unique_ptr funcInput = nullptr; + string mpkID = MPK_ID; + string mpkFile = MPK_ID + suffix; + if(prefix != "") { + mpkFile = prefix + mpkFile; + } + + OpenABEByteString ct1Blob, ct2Blob, mpkBlob; + + try { + // Initialize a OpenABEContext structure + schemeContext = OpenABE_createContextABESchemeCCA(scheme_type); + if (schemeContext == nullptr) { + cerr << "unable to create a new context" << endl; + return; + } + + // next, get the functional input for encryption (based on scheme type) + if (scheme_type == OpenABE_SCHEME_KP_GPSW) { + funcInput = createAttributeList(func_input); + } else if(scheme_type == OpenABE_SCHEME_CP_WATERS) { + funcInput = createPolicyTree(func_input); + } + ASSERT(funcInput != nullptr, OpenABE_ERROR_INVALID_INPUT); + + // for KP and CP, we only have to do this once + mpkBlob = ReadFile(mpkFile.c_str()); + if (mpkBlob.size() == 0) { + cerr << "master public parameters not encoded properly." << endl; + return; + } + + if ((result = schemeContext->loadMasterPublicParams(mpkID, mpkBlob)) != OpenABE_NOERROR) { + cerr << "unable to load the master public parameters" << endl; + throw result; + } + + std::unique_ptr ciphertext1(new OpenABECiphertext); + std::unique_ptr ciphertext2(new OpenABECiphertext); + if ((result = schemeContext->encrypt(mpkID, funcInput.get(), inputStr, ciphertext1.get(), ciphertext2.get())) != OpenABE_NOERROR) { + cerr << "error occurred during encryption" << endl; + throw result; + } + + // write to disk + ciphertext1->exportToBytes(ct1Blob); + ciphertext2->exportToBytesWithoutHeader(ct2Blob); + string ctBlobStr = CT1_BEGIN_HEADER; + ctBlobStr += NL + Base64Encode(ct1Blob.getInternalPtr(), ct1Blob.size()) + NL; + ctBlobStr += CT1_END_HEADER; + ctBlobStr += NL; + ctBlobStr += CT2_BEGIN_HEADER; + ctBlobStr += NL + Base64Encode(ct2Blob.getInternalPtr(), ct2Blob.size()) + NL; + ctBlobStr += CT2_END_HEADER; + ctBlobStr += NL; + + if(verbose) { cout << "writing " << ct2Blob.size() << " bytes" << endl; } + WriteToFile(ciphertextFile.c_str(), ctBlobStr); + + } catch (OpenABE_ERROR & error) { + cout << "caught exception: " << OpenABE_errorToString(error) << endl; + } + + return; +} + +int main(int argc, char **argv) +{ + if (argc <= 1) { + cout << OpenABE_CLI_STRING << "encryption utility, v" << (OpenABE_LIBRARY_VERSION / 100.) << endl; + fprintf(stderr, USAGE); + exit(-1); + } + int opt; + string func_input = "", input_file = "", prefix = "", suffix = "", scheme_type = ""; + string mpk_file, recipient_id = "", ciphertext_file; + string inputStr; + + bool verbose = false; + while ((opt = getopt(argc,argv,"p:s:i:e:o:r:v")) != EOF) + { + switch(opt) + { + case 'p': prefix = string(optarg); break; + case 's': scheme_type = string(optarg); break; + case 'i': cout << "input file: " << optarg << endl; input_file = optarg; break; + case 'e': func_input = string(optarg); break; + case 'r': recipient_id = string(optarg); break; + case 'o': ciphertext_file = optarg; break; + case 'v': verbose = true; break; + case '?': fprintf(stderr, USAGE); + default: cout< MAX_FILE_SIZE) { + cerr << "input file is either empty or too big! Can encrypt up to 4GB files." << endl; + return -1; + } + } catch(const std::ios_base::failure& e) { + cerr << e.what() << endl; + return -1; + } + + if (verbose) { + cout << "read " << inputStr.size() << " bytes from " << input_file << endl; + } + + // see if suffix has been added to the ciphertext filename + addFileExtension(ciphertext_file, suffix); + + InitializeOpenABE(); + + if (scheme == OpenABE_SCHEME_PK_OPDH) { + string sender_id = func_input; + if (sender_id == "" || recipient_id == "") { + cerr << "missing sender ID (-e option) and/or recipient ID (-r option)" << endl; + goto cleanup; + } + cout << "sender ID: " << sender_id << endl; + cout << "recipient ID: " << recipient_id << endl; + runPkEncrypt(suffix, sender_id, recipient_id, inputStr, ciphertext_file, verbose); + } else { + cout << "encryption functional input: "<< func_input << endl; + runAbeEncrypt(scheme, prefix, suffix, func_input, inputStr, ciphertext_file, verbose); + } + +cleanup: + ShutdownOpenABE(); + + return 0; +} diff --git a/cli/fuzzTest.sh b/cli/fuzzTest.sh new file mode 100755 index 00000000..ca287572 --- /dev/null +++ b/cli/fuzzTest.sh @@ -0,0 +1,192 @@ +#!/bin/bash + +# Requires 'afl-fuzz' package installed + +PURPLE='\033[0;95m' +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' + +function log() { + printf "${PURPLE}[+] $1${NC}\n" +} + +if [ $# -ne 2 ]; then + log "No input file argument supplied. Exiting." + log "Usage: [ input.txt ] [ PK, KP, CP or MA ]\n" + exit -1 +fi + +ARGC=$# +INPUT=$1 +SCHEME=$2 + +if [[ ${SCHEME} -ne "PK" || ${SCHEME} -ne "KP" \ + || ${SCHEME} -ne "CP" || ${SCHEME} -ne "MA" ]]; then + log "Usage: [ input.txt ] [ PK, KP, CP or MA ]\n" + exit -1 +fi + +printf "Running tests for '${SCHEME}'\n" +echo "hello world!!!123456" > ${INPUT} + +#set -x +AFL_FUZZER=$(which afl-fuzz) +AFL_C=$(which afl-clang) +AFL_CPP=$(which afl-clang++) + +export CC="${AFL_C}" CXX="${AFL_CPP}" + +log "Found '${AFL_C}' for C compiler..." +log "Found '${AFL_CPP}' for C++ compiler..." +log "Found '${AFL_FUZZER}' tool..." +#make clean +make + + +function run_fuzzer() +{ + name=$1 + ciphertext=$2 + target=$3 + set -x + mkdir -p in_${name} + mkdir -p out_${name} + cp ${ciphertext} in_${name}/ + + ${AFL_FUZZER} -i in_${name} -o out_${name} ${target} + set +x +} + +function assert() +{ + msg=$1; shift + expected=$1; shift + actual=$1; shift + printf "${PURPLE}[+] $msg:${NC} " + if [ "$expected" != "$actual" ]; then + printf "${RED}FAILED with ERROR=$actual${NC}\n" + else + printf "${GREEN}PASSED${NC}\n" + fi +} + +function log_test() { + printf "${PURPLE}- Testing $1${NC}\n" +} + + +function cleanup() { + file=$1 + suffix=$2 + rm plainOK.${file} *.${suffix} + rm -f *.key +} + +function echo_line() { + echo "********************************************" +} + +#### TEST PK-ENC #### + +if [ "${SCHEME}" = "PK" ]; then + log_test "PK-ENC" + ./oabe_keygen -s PK -i alice + assert "Generate key for alice" 0 $? + ./oabe_keygen -s PK -i bob + assert "Generate key for bob" 0 $? + ./oabe_keygen -s PK -i eve + assert "Generate key for eve" 0 $? + + echo_line + ./oabe_enc -s PK -e alice -r bob -i ${INPUT} -o ${INPUT}.pkenc + assert "Encrypt ${INPUT} from alice to bob" 0 $? + + echo_line + ./oabe_dec -s PK -e alice -r eve -i ${INPUT}.pkenc -o plainFail.${INPUT} + assert "Decrypt as eve -- should fail" 32 $? + + echo_line + ./oabe_dec -s PK -e alice -r bob -i ${INPUT}.pkenc -o plainOK.${INPUT} + assert "Decrypt as bob -- should pass" 0 $? + + run_fuzzer pkenc ${INPUT}.pkenc "./oabe_dec -s PK -e alice -r bob -i @@ -o plainOK.${INPUT}" + + #cleanup ${INPUT} pkenc + exit 0 +fi + +#### TEST PK-ENC #### + +#### TEST CP-ABE #### + +if [ "${SCHEME}" = "CP" ]; then + echo_line + echo "" + echo_line + log_test "CP-ABE" + ./oabe_setup -s CP -p org1 + assert "Generate system parameters for CP" 0 $? + + ./oabe_keygen -s CP -p org1 -i "ONE|TWO|THREE" -o aliceCPABE + assert "Generate key for alice" 0 $? + + ./oabe_keygen -s CP -p org1 -i "ONE|TWO|" -o bobCPABE + assert "Generate key for bob" 0 $? + + + echo_line + ./oabe_enc -s CP -p org1 -e "((ONE and TWO) and THREE)" -i ${INPUT} -o ${INPUT}.cpabe + assert "Encrypt under a simple policy" 0 $? + + echo_line + ./oabe_dec -s CP -p org1 -k bobCPABE.key -i ${INPUT}.cpabe -o plainFail.${INPUT} + assert "Decrypt using bob's key -- should fail" 22 $? + + echo_line + ./oabe_dec -s CP -p org1 -k aliceCPABE.key -i ${INPUT}.cpabe -o plainOK.${INPUT} + assert "Decrypt using alice's key -- should pass" 0 $? + + run_fuzzer cpabe ${INPUT}.cpabe "./oabe_dec -s CP -p org1 -k aliceCPABE.key -i @@ -o plainOK.${INPUT}" + + #cleanup ${INPUT} cpabe + exit 0 +fi +#### TEST CP-ABE #### + +#### TEST KP-ABE #### + +if [ "${SCHEME}" = "KP" ]; then + echo_line + echo "" + echo_line + log_test "KP-ABE" + ./oabe_setup -s KP -p org2 + assert "Generate system parameters for KP" 0 $? + + ./oabe_keygen -s KP -p org2 -i "(ONE and (TWO or THREE))" -o aliceKPABE + assert "Generate key for alice" 0 $? + + ./oabe_keygen -s KP -p org2 -i "(ONE and (TWO and FOUR))" -o bobKPABE + assert "Generate key for bob" 0 $? + + echo_line + ./oabe_enc -s KP -p org2 -e "ONE|TWO|THREE" -i ${INPUT} -o ${INPUT}.kpabe + assert "Encrypt under three attributes" 0 $? + + echo_line + ./oabe_dec -s KP -p org2 -k bobKPABE.key -i ${INPUT}.kpabe -o plainFail.${INPUT} + assert "Decrypt using bob's key -- should fail" 22 $? + + echo_line + ./oabe_dec -s KP -p org2 -k aliceKPABE.key -i ${INPUT}.kpabe -o plainOK.${INPUT} + assert "Decrypt using alice's key -- should pass" 0 $? + + run_fuzzer kpabe ${INPUT}.kpabe "./oabe_dec -s KP -p org2 -k aliceKPABE.key -i @@ -o plainOK.${INPUT}" + + #cleanup ${INPUT} kpabe + exit 0 +fi +#### TEST KP-ABE #### + +#set +x diff --git a/cli/keygen.cpp b/cli/keygen.cpp new file mode 100644 index 00000000..06e75a24 --- /dev/null +++ b/cli/keygen.cpp @@ -0,0 +1,222 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file keygen.cpp +/// +/// \brief Generate a user's OpenABE ABE keys given function input. +/// +/// \author J. Ayo Akinyele +/// + +#include "common.h" + +using namespace std; +using namespace oabe; + +#define USAGE \ + "usage: [ -s scheme ] [ -p prefix ] [ -i input ] [ -o output ] -v\n\n" \ + "\t-v : turn on verbosity\n" \ + "\t-s : scheme types are 'PK', 'CP' or 'KP'\n" \ + "\t-i : key id for 'PK', attribute list for 'CP'/'MA' and policy string for 'KP'\n" \ + "\t-o : output file for generated secret key\n" \ + "\t-p : prefix for generated authority public and secret parameter files (optional)\n\n" + +int runPkeKeygen(string& id, string& suffix) { + OpenABE_ERROR result = OpenABE_NOERROR; + int err_code = -1; + + try { + unique_ptr schemeContext = OpenABE_createContextPKESchemeCCA(OpenABE_SCHEME_PK_OPDH); + if (schemeContext == nullptr) { + cerr << "unable to create a new context" << endl; + return err_code; + } + + // Generate a set of parameters for an ABE authority + if ( (result = schemeContext->generateParams(DEFAULT_NIST_PARAM_STRING)) != OpenABE_NOERROR) { + cerr << "Unable to generate curve parameters: " << DEFAULT_NIST_PARAM_STRING << endl; + throw result; + } + + // Compute party A's static public and private key + const string keyId = "ID_" + id; + const string pkId = "public_" + id; + const string skId = "private_" + id; + if ((result = schemeContext->keygen(keyId, pkId, skId)) != OpenABE_NOERROR) { + cerr << "unable to generate keys for: " << keyId << endl; + throw result; + } + + const string pubKeyFile = id + ".pk" + suffix; + const string privKeyFile = id + ".sk" + suffix; + OpenABEByteString publicKey, privateKey; + schemeContext->exportKey(pkId, publicKey); + schemeContext->exportKey(skId, privateKey); + + WriteToFile(pubKeyFile.c_str(), PK_BEGIN_HEADER + Base64Encode(publicKey.getInternalPtr(), publicKey.size()) + PK_END_HEADER); + WriteToFile(privKeyFile.c_str(), SK_BEGIN_HEADER + Base64Encode(privateKey.getInternalPtr(), privateKey.size()) + SK_END_HEADER); + err_code = 0; + } catch (OpenABE_ERROR & error) { + cout << "caught exception: " << OpenABE_errorToString(error) << endl; + err_code = error; + } + + return err_code; +} + +int runAbeKeygen(OpenABE_SCHEME scheme_type, string& prefix, string& suffix, string& keyInput, string& keyFile, string& userGlobID, bool verbose) +{ + int err_code = -1; + OpenABE_ERROR result = OpenABE_NOERROR; + std::unique_ptr schemeContext = nullptr; + std::unique_ptr funcInput = nullptr; + OpenABEByteString mpkBlob, mskBlob, skBlob; + + string mpkID = MPK_ID, mskID = MSK_ID, skID = SK_ID, globSkID = userGlobID; + string mpkFile = MPK_ID + suffix, mskFile = MSK_ID + suffix; + if(prefix != "") { + mpkFile = prefix + mpkFile; + mskFile = prefix + mskFile; + } + + // Initialize a OpenABEContext structure + schemeContext = OpenABE_createContextABESchemeCCA(scheme_type); + if (schemeContext == nullptr) { + cerr << "unable to create a new context" << endl; + return err_code; + } + + try { + // Get the functional input + if(scheme_type == OpenABE_SCHEME_CP_WATERS) { + funcInput = createAttributeList(keyInput); + } else if(scheme_type == OpenABE_SCHEME_KP_GPSW) { + funcInput = createPolicyTree(keyInput); + } + ASSERT(funcInput != nullptr, OpenABE_ERROR_INVALID_INPUT); + + // Do it once for CP or KP + // read the file + mpkBlob = ReadFile(mpkFile.c_str()); + if (mpkBlob.size() == 0) { + cerr << "master public parameters not encoded correctly." << endl; + return err_code; + } + + mskBlob = ReadFile(mskFile.c_str()); + if (mskBlob.size() == 0) { + cerr << "master secret parameters not encoded correctly." << endl; + return err_code; + } + + if ((result = schemeContext->loadMasterPublicParams(mpkID, mpkBlob)) != OpenABE_NOERROR) { + cerr << "unable to load the master public parameters" << endl; + throw result; + } + + if ((result = schemeContext->loadMasterSecretParams(mskID, mskBlob)) != OpenABE_NOERROR) { + cerr << "unable to load the master secret parameters" << endl; + throw result; + } + // generate the user's key + if ((result = schemeContext->keygen(funcInput.get(), skID, mpkID, mskID)) != OpenABE_NOERROR) { + cout << "decryption key error" << endl; + throw result; + } + + // export the generated key + if ((result = schemeContext->exportKey(skID, skBlob)) != OpenABE_NOERROR) { + cout << "unable to export master secret parameters" << endl; + throw result; + } + + WriteToFile(keyFile.c_str(), SK_BEGIN_HEADER + Base64Encode(skBlob.getInternalPtr(), skBlob.size()) + SK_END_HEADER); + err_code = 0; + } catch (OpenABE_ERROR & error) { + cout << "caught exception: " << OpenABE_errorToString(error) << endl; + err_code = error; + } + + return err_code; +} + +int main(int argc, char **argv) +{ + if(argc <= 1) { + cout << OpenABE_CLI_STRING << "keygen utility, v" << (OpenABE_LIBRARY_VERSION / 100.) << endl; + fprintf(stderr, USAGE); + exit(-1); + } + int opt, status = 0; + string scheme_type = "", prefix = "", suffix = "", funcInputStr = "", keyOutfile = ""; + string userGlobID = "", keySuffix = KEY_SUFFIX; + bool verbose = false; + + while ((opt = getopt(argc,argv,"p:s:i:o:v")) != EOF) + { + switch(opt) + { + case 'p': prefix = string(optarg); break; + case 's': scheme_type = string(optarg); break; + case 'i': funcInputStr = string(optarg); break; + case 'o': keyOutfile = optarg; break; + case 'v': verbose = true; break; + case '?': fprintf(stderr, USAGE); + default: cout << endl; exit(-1); + } + } + // check prefix ending + addNameSeparator(prefix); + // validate scheme type + OpenABE_SCHEME scheme = checkForScheme(scheme_type, suffix); + if(scheme == OpenABE_SCHEME_NONE) { + cerr << "selected an invalid scheme type. Try again with -s option.\n"; + return -1; + } + + addFileExtension(keyOutfile, keySuffix); + + InitializeOpenABE(); + + if (scheme == OpenABE_SCHEME_PK_OPDH) { + string key_id = funcInputStr; + if (key_id == "") { + cerr << "missing user's key ID. Specify with -i option." << endl; + status = -1; + goto cleanup; + } + runPkeKeygen(key_id, suffix); + } else { + cout << "functional key input: "<< funcInputStr << endl; + status = runAbeKeygen(scheme, prefix, suffix, funcInputStr, keyOutfile, userGlobID, verbose); + } + +cleanup: + + ShutdownOpenABE(); + + return status; +} diff --git a/cli/runBasicTest.sh b/cli/runBasicTest.sh new file mode 100755 index 00000000..99d5b59f --- /dev/null +++ b/cli/runBasicTest.sh @@ -0,0 +1,137 @@ +#!/bin/bash + +PURPLE='\033[0;95m' +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' + +#set -x + +function assert() +{ + msg=$1; shift + expected=$1; shift + actual=$1; shift + printf "${PURPLE}[+] $msg:${NC} " + if [ "$expected" != "$actual" ]; then + printf "${RED}FAILED with ERROR=$actual${NC}\n" + else + printf "${GREEN}PASSED${NC}\n" + fi +} + +function log() { + printf "${PURPLE}[+] $1${NC}\n" +} + +function log_test() { + printf "${PURPLE}- Testing $1${NC}\n" +} + + +function cleanup() { + file=$1 + suffix=$2 + rm plainOK.${file} *.${suffix} + rm -f *.key +} + +function echo_line() { + echo "********************************************" +} + +if [ $# -eq 0 ]; then + log "No input file argument supplied. Exiting." + exit -1 +fi + +INPUT=$1 + +#### TEST PK-ENC #### + +log_test "PK-ENC" +./oabe_keygen -s PK -i alice +assert "Generate key for alice" 0 $? +./oabe_keygen -s PK -i bob +assert "Generate key for bob" 0 $? +./oabe_keygen -s PK -i eve +assert "Generate key for eve" 0 $? + +echo_line +./oabe_enc -s PK -e alice -r bob -i ${INPUT} -o ${INPUT}.pkenc +assert "Encrypt ${INPUT} from alice to bob" 0 $? + +echo_line +./oabe_dec -s PK -e alice -r eve -i ${INPUT}.pkenc -o plainFail.${INPUT} +assert "Decrypt as eve -- should fail" 32 $? + +echo_line +./oabe_dec -s PK -e alice -r bob -i ${INPUT}.pkenc -o plainOK.${INPUT} +assert "Decrypt as bob -- should pass" 0 $? + +cleanup ${INPUT} pkenc + +#### TEST PK-ENC #### + +#### TEST CP-ABE #### +echo_line +echo "" +echo_line +log_test "CP-ABE" +./oabe_setup -s CP -p org1 +assert "Generate system parameters for CP" 0 $? + +./oabe_keygen -s CP -p org1 -i "ONE|TWO|THREE" -o aliceCPABE +assert "Generate key for alice" 0 $? + +./oabe_keygen -s CP -p org1 -i "ONE|TWO|" -o bobCPABE +assert "Generate key for bob" 0 $? + + +echo_line +./oabe_enc -s CP -p org1 -e "((ONE and TWO) and THREE)" -i ${INPUT} -o ${INPUT}.cpabe +assert "Encrypt under a simple policy" 0 $? + +echo_line +./oabe_dec -s CP -p org1 -k bobCPABE.key -i ${INPUT}.cpabe -o plainFail.${INPUT} +assert "Decrypt using bob's key -- should fail" 32 $? + +echo_line +./oabe_dec -s CP -p org1 -k aliceCPABE.key -i ${INPUT}.cpabe -o plainOK.${INPUT} +assert "Decrypt using alice's key -- should pass" 0 $? + +cleanup ${INPUT} cpabe + +#### TEST CP-ABE #### + +#### TEST KP-ABE #### +echo_line +echo "" +echo_line +log_test "KP-ABE" +./oabe_setup -s KP -p org2 +assert "Generate system parameters for KP" 0 $? + +./oabe_keygen -s KP -p org2 -i "(ONE and (TWO or THREE))" -o aliceKPABE +assert "Generate key for alice" 0 $? + +./oabe_keygen -s KP -p org2 -i "(ONE and (TWO and FOUR))" -o bobKPABE +assert "Generate key for bob" 0 $? + +echo_line +./oabe_enc -s KP -p org2 -e "ONE|TWO|THREE" -i ${INPUT} -o ${INPUT}.kpabe +assert "Encrypt under three attributes" 0 $? + +echo_line +./oabe_dec -s KP -p org2 -k bobKPABE.key -i ${INPUT}.kpabe -o plainFail.${INPUT} +assert "Decrypt using bob's key -- should fail" 32 $? + +echo_line +./oabe_dec -s KP -p org2 -k aliceKPABE.key -i ${INPUT}.kpabe -o plainOK.${INPUT} +assert "Decrypt using alice's key -- should pass" 0 $? + +cleanup ${INPUT} kpabe + +#### TEST KP-ABE #### + +#set +x diff --git a/cli/runComplexTest.sh b/cli/runComplexTest.sh new file mode 100755 index 00000000..bc9de780 --- /dev/null +++ b/cli/runComplexTest.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +PURPLE='\033[0;95m' +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' + +#set -x + +function assert() +{ + msg=$1; shift + expected=$1; shift + actual=$1; shift + printf "${PURPLE}[+] $msg:${NC} " + if [ "$expected" != "$actual" ]; then + printf "${RED}FAILED with ERROR=$actual${NC}\n" + else + printf "${GREEN}PASSED${NC}\n" + fi +} + +function log() { + printf "${PURPLE}[+] $1${NC}\n" +} + +function log_test() { + printf "${PURPLE}- Testing $1${NC}\n" +} + + +function cleanup() { + file=$1 + suffix=$2 + rm plainOK.${file} *.${suffix} + rm -f *.key +} + +function echo_line() { + echo "********************************************" +} + +if [ $# -eq 0 ]; then + log "No input file argument supplied. Exiting." + exit -1 +fi + +INPUT=$1 + +#### TEST PK-ENC #### + +log_test "PK-ENC" +./oabe_keygen -s PK -i alice +assert "Generate key for alice" 0 $? +./oabe_keygen -s PK -i bob +assert "Generate key for bob" 0 $? +./oabe_keygen -s PK -i eve +assert "Generate key for eve" 0 $? + +echo_line +./oabe_enc -s PK -e alice -r bob -i ${INPUT} -o ${INPUT}.pkenc +assert "Encrypt ${INPUT} from alice to bob" 0 $? + +echo_line +./oabe_dec -s PK -e alice -r eve -i ${INPUT}.pkenc -o plainFail.${INPUT} +assert "Decrypt as eve -- should fail" 32 $? + +echo_line +./oabe_dec -s PK -e alice -r bob -i ${INPUT}.pkenc -o plainOK.${INPUT} +assert "Decrypt as bob -- should pass" 0 $? + +cleanup ${INPUT} pkenc + +#### TEST PK-ENC #### + +#### TEST CP-ABE #### +echo_line +echo "" +echo_line +log_test "CP-ABE" +./oabe_setup -s CP -p org1 +assert "Generate system parameters for CP" 0 $? + +./oabe_keygen -s CP -p org1 -i "Female|Nurse|Floor=3|Respiratory_Specialist" -o aliceCPABE +assert "Generate key for alice" 0 $? + +./oabe_keygen -s CP -p org1 -i "Male|Doctor|Floor=5|Cardiologist" -o charlieCPABE +assert "Generate key for bob" 0 $? + + +echo_line +./oabe_enc -s CP -p org1 -e "((Doctor or Nurse) and (Floor >= 3 and Floor < 5))" -i ${INPUT} -o ${INPUT}.cpabe +assert "Encrypt under a simple policy" 0 $? + +echo_line +./oabe_dec -s CP -p org1 -k charlieCPABE.key -i ${INPUT}.cpabe -o plainFail.${INPUT} +assert "Decrypt using bob's key -- should fail" 32 $? + +echo_line +./oabe_dec -s CP -p org1 -k aliceCPABE.key -i ${INPUT}.cpabe -o plainOK.${INPUT} +assert "Decrypt using alice's key -- should pass" 0 $? + +cleanup ${INPUT} cpabe + +#### TEST CP-ABE #### + +#### TEST KP-ABE #### +echo_line +echo "" +echo_line +log_test "KP-ABE" +./oabe_setup -s KP -p org2 +assert "Generate system parameters for KP" 0 $? + +./oabe_keygen -s KP -p org2 -i "(From:Alice and (((Month:March and (Day >= 1 and Day <= 14)) or (Month:February and (Day > 22 and Day < 28))) and Year:2015))" -o analystKPABE +assert "Generate key for analyst" 0 $? + +#./oabe_keygen -s KP -p org2 -i "(ONE and (TWO and FOUR))" -o bobKPABE +#a#ssert "Generate key for bob" 0 $? + +echo_line +./oabe_enc -s KP -p org2 -e "From:Alice|To:Bob|Month:March|Day=7|Year:2015" -i ${INPUT} -o ${INPUT}1.kpabe +assert "Encrypt under three attributes" 0 $? + +echo_line +./oabe_enc -s KP -p org2 -e "From:Alice|To:Charlie|Month:March|Day=15|Year:2015" -i ${INPUT} -o ${INPUT}2.kpabe +assert "Encrypt under three attributes" 0 $? + +echo_line +./oabe_dec -s KP -p org2 -k analystKPABE.key -i ${INPUT}1.kpabe -o plainOK.${INPUT} +assert "Decrypt first CT using the analyst's key -- should pass" 0 $? + +echo_line +./oabe_dec -s KP -p org2 -k analystKPABE.key -i ${INPUT}2.kpabe -o plainFail.${INPUT} +assert "Decrypt second CT using the analyst's key -- should fail" 32 $? + +cleanup ${INPUT} kpabe + +#### TEST KP-ABE #### + +#set +x diff --git a/cli/runTest.sh b/cli/runTest.sh new file mode 100755 index 00000000..c2efb997 --- /dev/null +++ b/cli/runTest.sh @@ -0,0 +1,144 @@ +#!/bin/bash + +PURPLE='\033[0;95m' +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' + +#set -x + +function assert() +{ + msg=$1; shift + expected=$1; shift + actual=$1; shift + printf "${PURPLE}[+] $msg:${NC} " + if [ "$expected" != "$actual" ]; then + printf "${RED}FAILED with ERROR=$actual${NC}\n" + else + printf "${GREEN}PASSED${NC}\n" + fi +} + +function log() { + printf "${PURPLE}[+] $1${NC}\n" +} + +function log_test() { + printf "${PURPLE}- Testing $1${NC}\n" +} + + +function cleanup() { + file=$1 + suffix=$2 + rm plainOK.${file} *.${suffix} + rm -f *.key +} + +function echo_line() { + echo "********************************************" +} + +if [ $# -eq 0 ]; then + log "No input file argument supplied. Exiting." + exit -1 +fi + +INPUT=$1 + +#### TEST PK-ENC #### + +log_test "PK-ENC" +./oabe_keygen -s PK -i alice +assert "Generate key for alice" 0 $? +./oabe_keygen -s PK -i bob +assert "Generate key for bob" 0 $? +./oabe_keygen -s PK -i eve +assert "Generate key for eve" 0 $? + +echo_line +./oabe_enc -s PK -e alice -r bob -i ${INPUT} -o ${INPUT}.pkenc +assert "Encrypt ${INPUT} from alice to bob" 0 $? + +echo_line +./oabe_dec -s PK -e alice -r eve -i ${INPUT}.pkenc -o plainFail.${INPUT} +assert "Decrypt as eve -- should fail" 32 $? + +echo_line +./oabe_dec -s PK -e alice -r bob -i ${INPUT}.pkenc -o plainOK.${INPUT} +assert "Decrypt as bob -- should pass" 0 $? + +cleanup ${INPUT} pkenc + +#### TEST PK-ENC #### + +#### TEST CP-ABE #### +echo_line +echo "" +echo_line +log_test "CP-ABE" +./oabe_setup -s CP -p org1 +assert "Generate system parameters for CP" 0 $? + +./oabe_keygen -s CP -p org1 -i "Female|Nurse|Floor=3|Respiratory_Specialist" -o aliceCPABE +assert "Generate key for alice" 0 $? + +./oabe_keygen -s CP -p org1 -i "Male|Doctor|Floor=5|Cardiologist" -o charlieCPABE +assert "Generate key for bob" 0 $? + + +echo_line +# (Floor > 2 and Floor < 5) +./oabe_enc -s CP -p org1 -e "((Doctor or Nurse) and (Floor in (2-5)))" -i ${INPUT} -o ${INPUT}.cpabe +assert "Encrypt under a simple policy" 0 $? + +echo_line +./oabe_dec -s CP -p org1 -k charlieCPABE.key -i ${INPUT}.cpabe -o plainFail.${INPUT} +assert "Decrypt using bob's key -- should fail" 32 $? + +echo_line +./oabe_dec -s CP -p org1 -k aliceCPABE.key -i ${INPUT}.cpabe -o plainOK.${INPUT} +assert "Decrypt using alice's key -- should pass" 0 $? + +cleanup ${INPUT} cpabe + +#### TEST CP-ABE #### + +#### TEST KP-ABE #### +echo_line +echo "" +echo_line +log_test "KP-ABE" +./oabe_setup -s KP -p org2 +assert "Generate system parameters for KP" 0 $? + +#./oabe_keygen -s KP -p org2 -i "(From:Alice and (((Month:March and (Day >= 1 and Day <= 14)) or (Month:February and (Day > 22 and Day < 28))) and Year:2015))" -o analystKPABE +./oabe_keygen -s KP -p org2 -i "(From:Alice and (Date = March 1-14, 2015 or Date = February 22-28, 2015))" -o analystKPABE +assert "Generate key for analyst" 0 $? + +#./oabe_keygen -s KP -p org2 -i "(ONE and (TWO and FOUR))" -o bobKPABE +#a#ssert "Generate key for bob" 0 $? + +echo_line +./oabe_enc -s KP -p org2 -e "From:Alice|To:Bob|Date = March 7, 2015" -i ${INPUT} -o ${INPUT}1.kpabe +assert "Encrypt under three attributes" 0 $? + +echo_line +./oabe_enc -s KP -p org2 -e "From:Alice|To:Charlie|Date = March 15, 2015" -i ${INPUT} -o ${INPUT}2.kpabe +assert "Encrypt under three attributes" 0 $? + +echo_line +./oabe_dec -s KP -p org2 -k analystKPABE.key -i ${INPUT}1.kpabe -o plainOK.${INPUT} +assert "Decrypt first CT using the analyst's key -- should pass" 0 $? + +echo_line +./oabe_dec -s KP -p org2 -k analystKPABE.key -i ${INPUT}2.kpabe -o plainFail.${INPUT} +assert "Decrypt second CT using the analyst's key -- should fail" 32 $? + +cleanup ${INPUT} kpabe + +#### TEST KP-ABE #### + + +exit 0 diff --git a/cli/setup.cpp b/cli/setup.cpp new file mode 100644 index 00000000..e4957ff2 --- /dev/null +++ b/cli/setup.cpp @@ -0,0 +1,143 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file setup.cpp +/// +/// \brief Generate the ABE global system parameters. +/// +/// \author J. Ayo Akinyele +/// + +#include "common.h" + +using namespace std; +using namespace oabe; + +#define USAGE \ + "usage: [ -s scheme ] [ -p prefix ] -v\n\n" \ + "\t-v : turn on verbose mode\n" \ + "\t-s : scheme types are 'CP' or 'KP'\n" \ + "\t-p : prefix string for generated authority public and secret parameter files (optional)\n\n" + +void runSetup(OpenABE_SCHEME scheme_type, string& prefix, string& suffix, bool verbose) +{ + try { + OpenABEByteString mpkBlob, mskBlob; + string mpkFile = MPK_ID + suffix, mskFile = MSK_ID + suffix; + if(prefix != "") { + mpkFile = prefix + mpkFile; + mskFile = prefix + mskFile; + } + + // abeSetup(scheme_type, prefix, mpkBlob, mskBlob); + std::unique_ptr schemeContext = nullptr; + // default parameters + string mpkID = MPK_ID, mskID = MSK_ID; + if (prefix != "") { + mpkID = prefix + mpkID; + mskID = prefix + mskID; + } + // Initialize a OpenABEContext structure + schemeContext = OpenABE_createContextABESchemeCCA(scheme_type); + if (schemeContext == nullptr) { + cerr << "unable to create a new context" << endl; + return; + } + + // Generate a set of parameters for an ABE authority + if (schemeContext->generateParams(DEFAULT_PARAMETER_STRING, mpkID, mskID) != OpenABE_NOERROR) { + cerr << "unable to generate parameters" << endl; + return; + } + + // don't password protect the master public parameters (not necessary here) + if (schemeContext->exportKey(mpkID, mpkBlob) != OpenABE_NOERROR) { + cerr << "unable to export public parameters" << endl; + return; + } + + if (schemeContext->exportKey(mskID, mskBlob) != OpenABE_NOERROR) { + cerr << "unable to export master secret parameters" << endl; + return; + } + + // cout << "MPK: " << mpkBlob.toHex() << endl; + // cout << "MSK: " << mskBlob.toHex() << endl; + cout << "writing " << mpkBlob.size() << " bytes to " << mpkFile << endl; + WriteToFile(mpkFile.c_str(), MPK_BEGIN_HEADER + Base64Encode(mpkBlob.getInternalPtr(), mpkBlob.size()) + MPK_END_HEADER); + cout << "writing " << mskBlob.size() << " bytes to " << mskFile << endl; + WriteToFile(mskFile.c_str(), MSK_BEGIN_HEADER + Base64Encode(mskBlob.getInternalPtr(), mskBlob.size()) + MSK_END_HEADER); + + } catch (OpenABE_ERROR& error) { + cout << "caught exception: " << OpenABE_errorToString(error) << endl; + return; + } + + return; +} + +int main(int argc, char **argv) +{ + // if interactive flag set, then enter password via stdin (instead of command line) + bool verbose_flag = false; + string scheme_type = "", prefix = "", suffix = ""; + int c; + if(argc <= 1) { + cout << OpenABE_CLI_STRING << "system setup utility, v" << (OpenABE_LIBRARY_VERSION / 100.) << endl; + fprintf(stderr, USAGE); + return -1; + } + + while((c = getopt(argc, argv, "vs:p:")) != -1) { + switch(c) { + case 's': scheme_type = string(optarg); break; + case 'p': prefix = string(optarg); break; + case 'v': verbose_flag = true; break; + case '?': fprintf(stderr, USAGE); + default: cout< 21 ]]; then + console "$OS_VERSION > 21" + else + #if [[ $(yum list installed | grep $1) ]]; then + # console "$1 is already installed. skipping." + #else + console "installing $1" + sudo yum -y install $1 + #fi + fi + fi +} + +# packages needed for Mac OS X +function main_darwin() { + type brew >/dev/null 2>&1 || { + fail "Could not find homebrew. Please install it from http://brew.sh/"; + } + + type pip >/dev/null 2>&1 || { + fail "Could not find pip. please install it using 'sudo easy_install pip'"; + } + + brew update + + install_package wget + install_package cmake + install_package gnu-sed + install_package coreutils + install_package autoconf + install_package automake + install_package libtool + install_package pkg-config + install_package python + install_package gmp + install_package doxygen + install_package bison + install_package node + + sudo pip install virtualenv +} + +function upgrade_cmake() { + + # check if cmake has been installed already + CMAKE_CHECK=`cmake --version` + STATUS=$? + + if [[ $STATUS -eq 0 ]]; then + CMAKE_VERS=`cmake --version | grep version | cut -b 15-17 | tr -d [.]` + if [[ $CMAKE_VERS -gt 30 ]]; then + echo "[+] cmake version greater than or equal to 3.1. skipping upgrade." + return 0 + fi + fi + + # install cmake from source + echo "[+] Install cmake v3.2" + CMAKE32=cmake-3.2.2 + if [[ ! -f ${CMAKE32}/.built ]]; then + wget https://www.cmake.org/files/v3.2/${CMAKE32}.tar.gz + tar xf ${CMAKE32}.tar.gz + cd ${CMAKE32} + ./configure + make install + touch .built + cd .. + else + cd ${CMAKE32} + make install + cd .. + fi +} + +function upgrade_bison() { + BISON30=bison-3.0 + BISON_URL=https://ftp.gnu.org/gnu/bison/${BISON30}.tar.gz + + # check the existing version first + BISON_VERSION=`bison --version | grep Bison | cut -b 19-21 | tr -d [.]` + if [[ ${BISON_VERSION} -ge 30 ]]; then + echo "[+] bison version is 3.0 or greater. skipping upgrade" + return 0 + fi + + if [[ ! -f ${BISON30}/.built ]]; then + wget ${BISON_URL} + tar xf ${BISON30}.tar.gz + cd ${BISON30} + ./configure + make install + touch .built + cd .. + fi +} + +# packages needed for Linux/Ubuntu distro +function main_ubuntu() { + sudo apt-get update + install_package python-pip + + type pip >/dev/null 2>&1 || { + fail "Could not find pip. please install it using 'sudo easy_install pip'"; + } + + install_package wget + install_package autoconf + install_package m4 + install_package libtool + install_package g++ + install_package cmake + install_package libgmp-dev + install_package libssl-dev + install_package bison + install_package flex + install_package unzip + install_package libglib2.0-dev + install_package doxygen + install_package python3-setuptools + install_package python3-dev + install_package python3-pip + install_package nodejs + install_package npm + upgrade_cmake + upgrade_bison + + sudo ldconfig +} + +function main_debian() { + sudo apt-get update + + install_package wget + install_package autoconf + install_package m4 + install_package libtool + install_package g++ + install_package cmake + install_package libgmp-dev + install_package libssl-dev + install_package bison + install_package flex + install_package unzip + install_package libglib2.0-dev + install_package doxygen + install_package python3-setuptools + install_package python3-dev + install_package python3-pip + install_package nodejs + install_package npm + upgrade_cmake + upgrade_bison + + sudo ldconfig +} + +function main_redhat() { + + yum -y update + yum install -y centos-release-scl + yum install -y devtoolset-3-toolchain + + install_package wget + install_package autoconf + install_package m4 + install_package libtool + install_package gcc + install_package gcc-c++ + install_package gmp-devel + install_package bison + install_package flex + install_package unzip + install_package glib-devel + install_package doxygen + install_package python3 + install_package python-pip + install_package python-devel + install_package python-setuptools + install_package python3-setuptools + install_package python3-devel + install_package python3-pip + upgrade_cmake + upgrade_bison + + sudo ldconfig +} + +function main_fedora() { + + yum -y update + + install_package wget + install_package autoconf + install_package m4 + install_package libtool + install_package gcc + install_package gcc-c++ + install_package gmp-devel + install_package bison + install_package flex + install_package unzip + install_package glib-devel + install_package doxygen + install_package python3 + install_package python-pip + install_package python-devel + install_package python-setuptools + install_package python3-setuptools + install_package python3-devel + install_package python3-pip + upgrade_cmake + upgrade_bison + + sudo ldconfig +} + + +function main() { + platform OS + distro $OS OS_VERSION + + if [[ $1 = "get_platform" ]]; then + printf "OS:\t$OS\n" + printf "VER:\t$OS_VERSION\n" + return 0 + fi + + if [[ $OS = "ubuntu" ]]; then + log "Detected Ubuntu ($OS_VERSION)" + main_ubuntu + elif [[ $OS = "darwin" ]]; then + log "Detected Mac OS X ($OS_VERSION)" + main_darwin + elif [[ $OS = "debian" ]]; then + log "Detected Debian ($OS_VERSION)" + main_debian + elif [[ $OS = "centos" ]]; then + log "Detected CentOS ($OS_VERSION)" + main_redhat $OS_VERSION + scl enable devtoolset-3 bash + elif [[ $OS = "redhat" ]]; then + log "Detected Redhat ($OS_VERSION)" + main_redhat $OS_VERSION + elif [[ $OS = "fedora" ]]; then + log "Detected Fedora ($OS_VERSION)" + main_fedora $OS_VERSION + else + fail "Could not detect the OS." + fi +} + +main $1 + +#set +x diff --git a/deps/openssl/Makefile b/deps/openssl/Makefile new file mode 100644 index 00000000..76d97475 --- /dev/null +++ b/deps/openssl/Makefile @@ -0,0 +1,30 @@ +.PHONY: all clean + +include ../../Makefile.common + +# defined in Makefile.common +VERSION=${OPENSSL_VERSION} + +all: package openssl-${VERSION}/.built + +DEST_LIBDIR := $(DEPS_INSTALL_ZROOT)/lib +DEST_INCLUDEDIR := $(DEPS_INSTALL_ZROOT)/include + +openssl-${VERSION}/.built: openssl-${VERSION} + cd $<; \ + ./${OPENSSL_CONFIG} --prefix=$(DEPS_INSTALL_ZROOT) && \ + make && \ + make install_sw && \ + touch .built + +package: + ./download_openssl.sh + +openssl-${VERSION}: openssl-${VERSION}.tar.gz + tar -zxf $^ + +clean: + rm -rf openssl-$(VERSION) + +distclean: + rm -rf openssl-$(VERSION)* diff --git a/deps/openssl/download_openssl.sh b/deps/openssl/download_openssl.sh new file mode 100755 index 00000000..a2ce79fa --- /dev/null +++ b/deps/openssl/download_openssl.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +CMD=$1 +FORMAT=tar.gz +# commit as of 4/13/2018 +# comment 'make update' +COMMIT=560096f804a3712eea161726a8f085beefe8838a + +# openssl with BP support +if [[ $CMD == "with-bp" ]]; then + LINK=https://github.com/zeutro/openssl + VERSION=1.1.1-dev-bp + echo "Clone github repo @ ${LINK}" + git clone -b patch ${LINK} openssl-${VERSION}.git + cd openssl-${VERSION}.git +else + LINK=https://github.com/openssl/openssl + VERSION=1.1.1-dev + echo "Clone github repo @ ${LINK}" + git clone ${LINK} openssl-${VERSION}.git + cd openssl-${VERSION}.git + git reset --hard ${COMMIT} +fi + +OPENSSL=openssl-${VERSION} +if [[ ! -f ./${OPENSSL}.${FORMAT} ]]; then + echo "Create archive of source (without git files)" + git archive --output ../openssl-${VERSION}.test.${FORMAT} HEAD + + echo "Create final tarball: openssl-${VERSION}.${FORMAT}" + cd .. + mkdir -p openssl-${VERSION} + cd openssl-${VERSION} + tar -xf ../openssl-${VERSION}.test.${FORMAT} + + cd .. + tar -czf openssl-${VERSION}.${FORMAT} openssl-${VERSION} + rm openssl-${VERSION}.test.${FORMAT} + rm -r openssl-${VERSION} +else + echo "[!] ${OPENSSL}.${FORMAT} already exists." +fi + diff --git a/deps/relic/Makefile b/deps/relic/Makefile new file mode 100644 index 00000000..957ba83c --- /dev/null +++ b/deps/relic/Makefile @@ -0,0 +1,61 @@ +.PHONY: all clean + +include ../../Makefile.common + +# RELIC commit 955ed39 (4/2/17) = toolkit-0.4.1h (unofficially) +VERSION=toolkit-0.4.1h +BP_LABEL=bp +BP_TMP=$(shell mktemp -d tmp$(BP_LABEL)-XXXX) +BP_HDR_PREFIX=_$(BP_LABEL) + +EC_LABEL=ec +EC_TMP=$(shell mktemp -d tmp$(EC_LABEL)-XXXX) +EC_HDR_PREFIX=_$(EC_LABEL) + +# Options: BN254 or BN382 (ARITH=x64-asm-382) +BN_CURVE=254 +EC_CURVE=256 + +all: package relic-$(VERSION)/.built + +# We remove the VERSION define from (the installed) relic_conf.h +# because this conflicts with other libraries. Actually, they +# shouldn't really include relic_conf.h in anywhere other than C +# files. +# +# We also undefine MIN and MAX before they are redefined. +# +#-DLABEL="$(BP_LABEL)" +relic-$(VERSION)/.built: relic-${VERSION} + cd $(BP_TMP); \ + $(CMAKE_VARS) COMP="-O2 -funroll-loops -fomit-frame-pointer -Wno-incompatible-pointer-types -Wno-unused-function -Wno-implicit-function-declaration -Wno-incompatible-pointer-types-discards-qualifiers" cmake $(COMPILER_VARS) -DCMAKE_INSTALL_PREFIX:PATH=$(DEPS_INSTALL_ZROOT) -DOPSYS=$(RELIC_OS) -DARCH="X64" \ + -DWITH="BN;DV;FP;FPX;EP;EPX;PP;PC;MD" -DCHECK=off -DVERBS=off -DDEBUG=off -DMULTI=PTHREAD -DBENCH=0 -DTESTS=10 -DARITH=x64-asm-$(BN_CURVE) -DFP_PRIME=$(BN_CURVE) -DBN_PRECI=$(BN_CURVE) \ + -DFP_QNRES=on -DEP_METHD="PROJC;LWNAF;COMBS;INTER" -DFP_METHD="BASIC;COMBA;COMBA;MONTY;LOWER;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" \ + -DSEED="ZERO" -DRAND="CALL" ../$<; \ + make && \ + make install && \ + cd ../$(EC_TMP); \ + $(CMAKE_VARS) COMP="-O2 -funroll-loops -fomit-frame-pointer -Wno-unused-function -Wno-implicit-function-declaration -Wno-incompatible-pointer-types-discards-qualifiers" cmake $(COMPILER_VARS) -DCMAKE_INSTALL_PREFIX:PATH=$(DEPS_INSTALL_ZROOT) -DOPSYS=$(RELIC_OS) -DARCH="X64" \ + -DWITH="BN;DV;FP;EP;MD" -DCHECK=off -DVERBS=off -DDEBUG=off -DMULTI=PTHREAD -DBENCH=0 -DTESTS=0 -DARITH=gmp -DFP_PRIME=$(EC_CURVE) \ + -DFP_QNRES=off -DEP_METHD="PROJC;LWNAF;COMBS;INTER" -DFP_METHD="BASIC;COMBA;COMBA;MONTY;LOWER;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" \ + -DSEED="ZERO" -DRAND="CALL" -DLABEL="$(EC_LABEL)" ../$<; \ + make && \ + make install && \ + sed -i -e '/^#define VERSION/d' $(DEPS_INSTALL_ZROOT)/include/relic/relic_conf.h && \ + sed -i -e '/^#define ep2_mul/i \ +//#define ep2_mul' $(DEPS_INSTALL_ZROOT)/include/relic/relic_label.h && \ + sed -i -e '/^#define VERSION/d' $(DEPS_INSTALL_ZROOT)/include/relic$(EC_HDR_PREFIX)/relic_conf.h && \ + ../run_install_clean.sh && \ + touch ../$@ + +relic-$(VERSION): relic-$(VERSION).tar.gz + tar xf $^ + +package: + ./download_relic.sh relic-$(VERSION) + +clean: + rm -rf relic-$(VERSION) tmp* + +distclean: + rm -rf relic-$(VERSION)* tmp* diff --git a/deps/relic/download_relic.sh b/deps/relic/download_relic.sh new file mode 100755 index 00000000..adc44beb --- /dev/null +++ b/deps/relic/download_relic.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +VERSION=0.4.1h +FORMAT=tar.gz +LINK=https://github.com/relic-toolkit/relic +RELIC=${1:-relic-toolkit-${VERSION}} +# commit as of 4/2/2018 +# comment 'Merge pull request #73' +COMMIT=6609c924395ab6a48955c74558dda38b638b5cba + +echo "Clone github repo @ ${LINK}" +git clone ${LINK} ${RELIC}.git +cd ${RELIC}.git +git reset --hard ${COMMIT} + +if [[ ! -f ${RELIC}.${FORMAT} ]]; then + echo "Create archive of source (without git files)" + git archive --output ../${RELIC}.test.${FORMAT} HEAD + + echo "Create final tarball: ${RELIC}.${FORMAT}" + cd .. + mkdir ${RELIC} + cd ${RELIC} + tar -xf ../${RELIC}.test.${FORMAT} + + echo "Fix symbols..." + grep -rl "MIN" ./ | xargs sed -i 's/MIN/RLC_MIN/g' + grep -rl "MAX" ./ | xargs sed -i 's/MAX/RLC_MAX/g' + grep -rl "ALIGN" ./ | xargs sed -i 's/ALIGN/RLC_ALIGN/g' + grep -rl "rsa_t" ./ | xargs sed -i 's/rsa_t/rlc_rsa_t/g' + grep -rl "rsa_st" ./ | xargs sed -i 's/rsa_st/rlc_rsa_st/g' + sed -i -e '/^#define ep2_mul /d' include/relic_label.h + + cd .. + tar -czf ${RELIC}.${FORMAT} ${RELIC} + rm ${RELIC}.test.${FORMAT} + rm -r ${RELIC} +else + echo "[!] ${RELIC}.tar.gz already exists." +fi diff --git a/deps/relic/run_install_clean.sh b/deps/relic/run_install_clean.sh new file mode 100755 index 00000000..bf7925b9 --- /dev/null +++ b/deps/relic/run_install_clean.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +ORACLE_RELEASE=/etc/oracle-release +SYSTEM_RELEASE=/etc/system-release +DEBIAN_VERSION=/etc/debian_version +SERVER_ONLY="no" + +function console() { + echo "[+] $1" +} + +function fail() { + echo "[!] $1" + exit 1 +} + +function platform() { + local __out=$1 + if [[ -f "$LSB_RELEASE" ]] && grep -q 'DISTRIB_ID=Ubuntu' $LSB_RELEASE; then + FAMILY="debian" + eval $__out="ubuntu" + elif [[ -f "$DEBIAN_VERSION" ]]; then + FAMILY="debian" + eval $__out="debian" + else + eval $__out=`uname -s | tr '[:upper:]' '[:lower:]'` + fi +} + +function distro() { + local __out=$2 + if [[ $1 = "ubuntu" ]]; then + eval $__out=`awk -F= '/DISTRIB_CODENAME/ { print $2 }' $LSB_RELEASE` + elif [[ $1 = "darwin" ]]; then + eval $__out=`sw_vers -productVersion | awk -F '.' '{print $1 "." $2}'` + elif [[ $1 = "debian" ]]; then + eval $__out="`lsb_release -cs`" + else + eval $__out="unknown_version" + fi +} + +DEPS_INSTALL_ROOT=$ZROOT/deps/root +RELIC_LIB=$DEPS_INSTALL_ZROOT/lib/librelic + +function main() { + platform OS + distro $OS OS_VERSION + + if [[ $1 = "get_platform" ]]; then + printf "OS:\t$OS\n" + printf "VER:\t$OS_VERSION\n" + return 0 + fi + + if [[ $OS = "darwin" ]]; then + console "Detected Mac OS X ($OS_VERSION)" + set -x + install_name_tool -id ${RELIC_LIB}.dylib ${RELIC_LIB}.dylib + install_name_tool -id ${RELIC_LIB}_ec.dylib ${RELIC_LIB}_ec.dylib + set +x + fi +} + +main $1 + diff --git a/env b/env new file mode 100755 index 00000000..c394a9c6 --- /dev/null +++ b/env @@ -0,0 +1,59 @@ + +# Setup environment for Android. +if [ $# -eq 2 ]; then + ANDROID_NDK_ROOT=$1 + TOOLCHAIN=$2 + + export LIBS="-lgnustl_shared -llog -fexceptions" + export CXX="${TOOLCHAIN}/bin/arm-linux-androideabi-g++" + export CC="${TOOLCHAIN}/bin/arm-linux-androideabi-gcc" + export CXXFLAGS+="-DANDROID=1 -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -I${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/4.8/include -I${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi/include -I${ANDROID_NDK_ROOT}/sources/cxx-stl/system/include -I${ANDROID_NDK_ROOT}/platforms/android-14/arch-arm/usr/include ${LIBS}" + export CCFLAGS="-I/${TOOLCHAIN}/sysroot/usr/include" + export ANDROIDSTL="-L${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi" + export AR="${TOOLCHAIN}/bin/arm-linux-androideabi-ar" + export LD="${TOOLCHAIN}/bin/arm-linux-androideabi-ld" +fi + +ZROOT=$(pwd) +DEPS_INSTALL_ZROOT=${ZROOT}/deps/root +OABE_LIBS_ROOT=${ZROOT}/root + +# get the platform +REDHAT_RELEASE=/etc/redhat-release +FEDORA_RELEASE=/etc/fedora-release +LSB_RELEASE=/etc/lsb-release +ORACLE_RELEASE=/etc/oracle-release +SYSTEM_RELEASE=/etc/system-release +DEBIAN_VERSION=/etc/debian_version + +function get_os_family() { + if [[ -f "$LSB_RELEASE" ]] && grep -q 'DISTRIB_ID=Ubuntu' $LSB_RELEASE; then + export OS_FAMILY="debian" + elif [[ -f "$DEBIAN_VERSION" ]]; then + export OS_FAMILY="debian" + elif [[ -f "$FEDORA_RELEASE" ]]; then + export OS_FAMILY="fedora" + elif [[ -f "$REDHAT_RELEASE" ]]; then + export OS_FAMILY="redhat" + else + export OS_FAMILY=`uname -s | tr '[:upper:]' '[:lower:]'` + fi +} + +export ZROOT +export DEPS_INSTALL_ZROOT +export LD_LIBRARY_PATH=${DEPS_INSTALL_ZROOT}/lib:${OABE_LIBS_ROOT}/lib:${LD_LIBRARY_PATH} + +OS_NAME=`uname -s` +if [[ $OS_NAME == "Linux" ]]; then + # get the family name if a Linux system + get_os_family + export OS_FAMILY=$OS_FAMILY +elif [[ $OS_NAME == "MINGW64_NT-10.0" ]]; then + # mingw64 (win 10) + export ZML_LIB=with_openssl + export OS_FAMILY="windows" +else + export OS_FAMILY=`uname -s | tr '[:upper:]' '[:lower:]'` +fi + diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 00000000..72142814 --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,30 @@ +include ../Makefile.common + +.PHONY: all + +CXXFLAGS := $(CXX11FLAGS)$(OS_CXXFLAGS) -pthread -Wall -g -O2 -DSSL_LIB_INIT -I${ZROOT}/deps/root/include -I${ZROOT}/root/include +LDFLAGS := -L${ZROOT}/deps/root/lib -L${ZROOT}/root/lib +LIBS := -lcrypto -lrelic -lrelic_ec -lopenabe + +all: test_kp test_cp test_pk test_km + +test_kp: test_kp.o + $(CXX) -o test_kp $(CXXFLAGS) $(LDFLAGS) test_kp.cpp $(LIBS) + +test_cp: test_cp.o + $(CXX) -o test_cp $(CXXFLAGS) $(LDFLAGS) test_cp.cpp $(LIBS) + +test_pk: test_pk.o + $(CXX) -o test_pk $(CXXFLAGS) $(LDFLAGS) test_pk.cpp $(LIBS) + +test_km: test_km.o + $(CXX) -o test_km $(CXXFLAGS) $(LDFLAGS) test_km.cpp $(LIBS) + +test: + ./test_kp + ./test_cp + ./test_pk + ./test_km + +clean: + rm -rf *.o *.dSYM test_kp test_cp test_pk test_km diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..5e335339 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,5 @@ +Examples +======== + +This directory contains example code in various languages for using the high-level OpenABE zcrypto_box API. + diff --git a/examples/test_cp.cpp b/examples/test_cp.cpp new file mode 100644 index 00000000..3c891621 --- /dev/null +++ b/examples/test_cp.cpp @@ -0,0 +1,65 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \brief Example use of the OpenABE API with CP-ABE +/// + +#include +#include +#include +#include +#include + +using namespace std; +using namespace oabe; +using namespace oabe::crypto; + +int main(int argc, char **argv) { + + InitializeOpenABE(); + + cout << "Testing CP-ABE context" << endl; + + OpenABECryptoContext cpabe("CP-ABE"); + + string ct, pt1 = "hello world!", pt2; + + cpabe.generateParams(); + + cpabe.keygen("|attr1|attr2", "key0"); + + cpabe.encrypt("attr1 and attr2", pt1, ct); + + bool result = cpabe.decrypt("key0", ct, pt2); + + assert(result && pt1 == pt2); + + cout << "Recovered message: " << pt2 << endl; + + ShutdownOpenABE(); + + return 0; +} diff --git a/examples/test_km.cpp b/examples/test_km.cpp new file mode 100644 index 00000000..3d1c963a --- /dev/null +++ b/examples/test_km.cpp @@ -0,0 +1,101 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \brief Example use of the Keystore + OpenABE API with KP-ABE +/// + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace oabe; +using namespace oabe::crypto; + +int main(int argc, char **argv) { + + InitializeOpenABE(); + + cout << "Testing KP-ABE context with Key Manager" << endl; + + OpenABECryptoContext kpabe("KP-ABE"); + + string pt1 = "hello world!", pt2 = "another hello!", pt3 = "this should fail!"; + string rpt1, rpt2, rpt3, ct1, ct2, ct3; + + kpabe.generateParams(); + + map keyBlobs; + string tmp; + vector key_inputs = { "(attr1 or attr2) and attr3", "attr1 and attr2", "attr2 and attr3", "attr3 and attr4" }; + // generate keys and delete from context (we will load later) + for(size_t i = 0; i < key_inputs.size(); i++) { + const string keyID = "key"+to_string(i+1); + cout << "Generate " << keyID << ": " << key_inputs[i] << endl; + kpabe.keygen(key_inputs[i], keyID); + kpabe.exportUserKey(keyID, tmp); + keyBlobs[ keyID ] = tmp; + assert(kpabe.deleteKey(keyID)); + } + + // enable use of key manager + kpabe.enableKeyManager("user1"); + kpabe.enableVerbose(); // more internal output to stdout + + map::iterator it; + // load the keystore with the generated keys + for(it = keyBlobs.begin(); it != keyBlobs.end(); it++) { + kpabe.importUserKey(it->first, it->second); + } + + // encrypt + kpabe.encrypt("|attr1|attr2", pt1, ct1); + kpabe.encrypt("|attr3|attr4", pt2, ct2); + kpabe.encrypt("|attr4|attr5", pt3, ct3); + + // decrypt + bool result = kpabe.decrypt(ct1, rpt1); + + assert(result && pt1 == rpt1); + cout << "Recovered message 1: " << rpt1 << endl; + + result = kpabe.decrypt(ct2, rpt2); + assert(result && pt2 == rpt2); + cout << "Recovered message 2: " << rpt2 << endl; + + try { + result = kpabe.decrypt(ct3, rpt3); + } catch (oabe::ZCryptoBoxException& ex) { + cout << "Correctly failed to recover message 3!" << endl; + } + ShutdownOpenABE(); + + return 0; +} diff --git a/examples/test_kp.cpp b/examples/test_kp.cpp new file mode 100644 index 00000000..3faf6525 --- /dev/null +++ b/examples/test_kp.cpp @@ -0,0 +1,65 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \brief Example use of the OpenABE API with KP-ABE +/// + +#include +#include +#include +#include +#include + +using namespace std; +using namespace oabe; +using namespace oabe::crypto; + +int main(int argc, char **argv) { + + InitializeOpenABE(); + + cout << "Testing KP-ABE context" << endl; + + OpenABECryptoContext kpabe("KP-ABE"); + + string ct, pt1 = "hello world!", pt2; + + kpabe.generateParams(); + + kpabe.keygen("attr1 and attr2", "key0"); + + kpabe.encrypt("|attr1|attr2", pt1, ct); + + bool result = kpabe.decrypt("key0", ct, pt2); + + assert(result && pt1 == pt2); + + cout << "Recovered message: " << pt2 << endl; + + ShutdownOpenABE(); + + return 0; +} diff --git a/examples/test_pk.cpp b/examples/test_pk.cpp new file mode 100644 index 00000000..b980dcbf --- /dev/null +++ b/examples/test_pk.cpp @@ -0,0 +1,63 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \brief Example use of the OpenABE API with PKE +/// + +#include +#include +#include +#include +#include + +using namespace std; +using namespace oabe; +using namespace oabe::crypto; + +int main(int argc, char **argv) { + + InitializeOpenABE(); + + cout << "Testing PKE context" << endl; + + OpenPKEContext pke; + + pke.keygen("user0"); + + string pt1 = "hello world!", pt2, ct; + + pke.encrypt("user0", pt1, ct); + + bool result = pke.decrypt("user0", ct, pt2); + + assert(result && pt1 == pt2); + + cout << "Recovered message: " << pt2 << endl; + + ShutdownOpenABE(); + + return 0; +} diff --git a/platforms/android.sh b/platforms/android.sh new file mode 100755 index 00000000..b120ef52 --- /dev/null +++ b/platforms/android.sh @@ -0,0 +1,300 @@ +############################################################################### +# android-dependencies.sh +# +# This script implicitly documents the software dependencies, and current +# software versions, for our OpenABE android cross-compilation. Patches and +# modifications to software are found in this directory. +# +# Adjust the global environment variables for your specific system config. In +# particular, the Android NDK must be on your system so that we can build a +# standalone toolchain. You will use your toolchain to cross-compile a number +# of dependencies before building OpenABE. Some of this software needs to be +# patched to compile successfully. +# +# Example use: +# ./android-dependencies.sh /opt/android-ndk-r10e /home/userfoo/android +# +# Copy Flexlexer.h to /sysroot/usr +# +# Example use: +# ./android.sh /path/to/android/ndk/? +# +################################################################################ + +#!/bin/bash + +# Specify software versions as globals in this script. +OPENSSL="openssl-1.1.1-dev" +RELIC="relic-toolkit-0.4.1h" +GTEST="googletest-release-1.8.0" +GMP="gmp-6.0.0a" +CWD=$PWD + +# Specify the default compiler as clang++ or g++. + +# Make a standalone toolchain that contains all cross compilation tools and a +# sysroot for linking cross-compiled libraries. Defaults are: --stl=gnustl, +# --system=linux-x86_64, platform=android-3. We will use platform=android-14 +# but we could use 9 to cover those left with Android 2.3. +makeStandAloneToolChain() +{ + printf "Making standalone toolchain in $HOME/android\n" + $ANDROID_NDK_ROOT/build/tools/make-standalone-toolchain.sh --toolchain=$TOOLCHAIN_ARCH --llvm-version=3.6 --platform=$MIN_PLATFORM --install-dir=$INSTALLDIR +} + +# Check environment variables and command line arguments for build setup. +if [ -n "$ANDROID_NDK_ROOT" ]; then + printf "ANDROID_NDK_ROOT=$ANDROID_NDK_ROOT\n" +elif [ -n "$1" ]; then + printf "ANDROID_NDK_ROOT=$1\n" + ANDROID_NDK_ROOT=$1 +else + printf "Android NDK Root not provided, exiting\n" + exit 1 +fi + +# The user can supply either a maketoolchain option or a path to a built +# toolchain. The make option builds a standalone toolchain per the NDK. +if [ -n "$2" ]; then + if [ "$2" == "maketoolchain" ]; then + if [ -n "$3" ]; then + if [ "$3" == "32" ]; then + TOOLCHAIN_ARCH="arm-linux-androideabi-4.8" + MIN_PLATFORM=android-14 + INSTALLDIR=$HOME/android + elif [ "$3" == "64" ]; then + TOOLCHAIN_ARCH="aarch64-linux-android-4.9" + MIN_PLATFORM=android-21 + INSTALLDIR=$HOME/android64 + else + printf "Provide either no arguments, 32, or 64 for the architecture, exiting\n" + exit 1 + fi + else + # Same as the else 64 above. + TOOLCHAIN_ARCH="aarch64-linux-android-4.9" + MIN_PLATFORM=android-21 + INSTALLDIR=$HOME/android64 + fi + + makeStandAloneToolChain + exit 1 + fi + TOOLCHAIN=$2 +else + printf "maktoolchain option or android toolchain path not provided, exiting\n" + exit 1 +fi + +# Check the toolchain architecture. +if [ -f "$TOOLCHAIN/bin/aarch64-linux-android-g++" ]; then + printf "64-bit toolchain architecture\n" + TOOLCHAIN_ARCH="aarch64-linux-android" + MIN_ARCH="aarch64" # For boost. + OARCH="linux-aarch64" # For OpenSSL. + RARM="ARM" # For Relic. + RDWORD="64" +elif [ -f "$TOOLCHAIN/bin/arm-linux-androideabi-g++" ]; then + printf "32-bit toolchain architecture\n" + TOOLCHAIN_ARCH="arm-linux-androideabi" + MIN_ARCH="arm" # For boost. + OARCH="android-armv7" # For OpenSSL. + RARM="ARM" # For Relic. + RDWORD="32" +else + printf "Toolchain path provided doesn't contain a valid compiler, exiting\n" +fi + +# The user can choose whether to compile with clang or gcc. Gold linker always used. +if [ -n "$3" ]; then + if [ "$3" == "clang" ]; then + printf "Setup for compilation with clang front-end\n" + CPPCOMPILER="clang++" + CCOMPILER="clang" + AR="llvm-ar" + AS="llvm-as" + RANLIB="/bin/true" + LD="$TOOLCHAIN_ARCH-ld" + else + printf "Incorrect option provided (specify clang or nothing), exiting\n" + exit 1 + fi +else + printf "Setup for compilation with gnu compiler\n" + CPPCOMPILER="$TOOLCHAIN_ARCH-g++" + CCOMPILER="$TOOLCHAIN_ARCH-gcc" + AR="$TOOLCHAIN_ARCH-ar" + AS="$TOOLCHAIN_ARCH-as" + RANLIB="$TOOLCHAIN_ARCH-ranlib" + LD="$TOOLCHAIN_ARCH-ld" +fi + +# Specify some useful variables for subsequent dependency build functions. +SYSROOT=$TOOLCHAIN/sysroot/usr +PREF=$TOOLCHAIN/bin/ +CWD=$PWD + +# Export variables required by a few of the build functions. +export CC="$PREF$CCOMPILER" +export CXX="$PREF$CPPCOMPILER" +export LD="$PREF$LD" +export AS="$PREF$AS" +export RANLIB="$PREF$RANLIB" +export AR="$PREF$AR" +export CFLAGS="-I$SYSROOT/include --sysroot=$SYSROOT -I$ANDROID_NDK_ROOT/sources/cxx-stl/gnu-libstdc++/4.8/include/" +export LDFLAGS="-L$SYSROOT/lib -L$ANDROID_NDK_ROOT/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi/ -lgnustl_shared" + +# Download and compile gmp. The only flag we have to include is --enable-cxx. +buildGMPForAndroid() +{ + printf "Building GMP\n" + wget https://gmplib.org/download/gmp/$GMP.tar.lz + sleep 1 + lzip -d $GMP.tar.lz + tar -xvf $GMP.tar + cd $CWD/gmp-6.0.0 + ./configure --enable-cxx --prefix=$SYSROOT --host=$TOOLCHAIN_ARCH CC=$CC LD=$LD RANLIB=$RANLIB CXX=$CXX + make install + cd $CWD +} + +# Download, patch and compile Relic. The patch is from OpenABE for fixing symbols. +buildRelicForAndroid() +{ + printf "Building Relic\n" + if [ ! -f $RELIC.tar.gz ]; then + # check for it in deps/relic + RELIC_SRC=$ZROOT/deps/relic/$RELIC.tar.gz + if [ -f $RELIC_SRC ]; then + tar -xf $RELIC_SRC + else + printf "Could not find $RELIC.tar.gz in current directory\n" + return 1 + fi + else + tar -xf $RELIC.tar.gz + fi + + cd $RELIC/ + BP_LABEL=bp + BP_TMP=$(mktemp -d tmp$BP_LABEL-XXXX) + + EC_LABEL=ec + EC_TMP=$(mktemp -d tmp$EC_LABEL-XXXX) + EC_HDR_PREFIX="_$EC_LABEL" + + # Options: BN254 or BN256 + BN_CURVE=254 + EC_CURVE=256 + + cd $BP_TMP + CC="$CC --sysroot=$SYSROOT" RANLIB="$RANLIB" CMAKE_INCLUDE_PATH=$SYSROOT/include CMAKE_LIBRARY_PATH=$SYSROOT/lib + cmake -DCMAKE_INSTALL_PREFIX:PATH=$SYSROOT -DOPSYS=DROID -DARCH=$RARM \ + -DWITH="BN;DV;FP;FPX;EP;EPX;PP;PC;MD" -DCHECK=off -DVERBS=off -DDEBUG=off \ + -DSHLIB=on -DSTLIB=on -DBENCH=0 -DTESTS=0 -DARITH=gmp -DFP_PRIME="$BN_CURVE" \ + -DFP_QNRES=off -DEP_METHD="PROJC;LWNAF;COMBS;INTER" -DFP_METHD="BASIC;COMBA;COMBA;MONTY;LOWER;SLIDE" \ + -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" -DRAND="CALL" \ + -DCOMP="-O3 -funroll-loops -fomit-frame-pointer -I$SYSROOT/include" -DLINK="-L$SYSROOT/lib" -DWORD=$RDWORD ../ + make install + + cd ../$EC_TMP + CC="$CC --sysroot=$SYSROOT" RANLIB="$RANLIB" CMAKE_INCLUDE_PATH=$SYSROOT/include CMAKE_LIBRARY_PATH=$SYSROOT/lib + cmake -DCMAKE_INSTALL_PREFIX:PATH=$SYSROOT -DOPSYS=DROID -DARCH=$RARM \ + -DWITH="BN;DV;FP;EP;MD" -DCHECK=off -DVERBS=off -DDEBUG=off \ + -DSHLIB=on -DSTLIB=on -DMULTI=NONE -DBENCH=0 -DTESTS=0 -DARITH=easy -DFP_PRIME="$EC_CURVE" \ + -DFP_QNRES=off -DEP_METHD="PROJC;LWNAF;COMBS;INTER" -DFP_METHD="BASIC;COMBA;COMBA;MONTY;LOWER;SLIDE" \ + -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" -DRAND="CALL" \ + -DCOMP="-O3 -funroll-loops -fomit-frame-pointer -I$SYSROOT/include" -DLINK="-L$SYSROOT/lib" -DWORD=$RDWORD \ + -DLABEL="$EC_LABEL" ../ + make install + + # clean up relic includes + sed -i -e '/^#define VERSION/d' $SYSROOT/include/relic/relic_conf.h + sed -i -e '/^#define ep2_mul/i \ +//#define ep2_mul' $SYSROOT/include/relic/relic_label.h + sed -i -e '/^#define VERSION/d' $SYSROOT/include/relic$EC_HDR_PREFIX/relic_conf.h + + cd $CWD +} + +# Download and compile openssl. +buildOpenSSLForAndroid() +{ + printf "Building OpenSSL\n" + if [ ! -f "$OPENSSL.tar.gz" ]; then + # check for it in deps/openssl + OPENSSL_SRC=$ZROOT/deps/openssl/$OPENSSL.tar.gz + if [ -f $OPENSSL_SRC ]; then + tar -xf $OPENSSL_SRC + else + printf "Could not find $OPENSSL.tar.gz in current directory\n" + return 1 + fi + else + tar -xvf $OPENSSL.tar.gz + fi + + cd $CWD/$OPENSSL + ./Configure android shared no-async --prefix=$SYSROOT --openssldir=$SYSROOT "-I$ANDROID_NDK_ROOT/platforms/android-14/arch-arm/usr/include/" + sed -i 's/LDFLAG= -pie/LDFLAG=/g' Makefile + make CC="$CC" LD=$LD RANLIB=$RANLIB CROSS_SYSROOT=$SYSROOT + make install_sw CC="$CC" LD=$LD RANLIB=$RANLIB CROSS_SYSROOT=$SYSROOT + #set +x + cd $CWD +} + +# Download and compile libgtest using the ndk-build tool. +buildGTestForAndroid() +{ + printf "Building Google Test\n" + if [ ! -f $GTEST.zip ]; then + # check for it in deps/gtest + GTEST_SRC=$ZROOT/deps/gtest/$GTEST.zip + if [ -f $GTEST_SRC ]; then + unzip $GTEST_SRC + else + printf "Could not find $GTEST.zip in current directory\n" + return 1 + fi + else + unzip $GTEST.zip + fi + + cd $CWD/$GTEST + mkdir jni + echo " + LOCAL_PATH := \$(call my-dir) + include \$(CLEAR_VARS) + LOCAL_CPP_EXTENSION := .cc + LOCAL_MODULE := libgtest + LOCAL_C_INCLUDES := include . + LOCAL_SRC_FILES := ../src/gtest-all.cc + include \$(BUILD_SHARED_LIBRARY) + " > ./jni/Android.mk + echo " + APP_MODULES := libgtest + APP_STL := gnustl_shared + " > ./jni/Application.mk + $ANDROID_NDK_ROOT/ndk-build + cp ./libs/armeabi/libgtest.so $SYSROOT/lib/ + cp -r ./include/gtest $SYSROOT/include/ + cd $CWD +} + +# Main function to call all of the build functions. +build_main() +{ + buildGMPForAndroid + buildRelicForAndroid + buildOpenSSLForAndroid + buildGTestForAndroid +} + +CHECK_ZROOT=`env | grep ZROOT` + +if [ -z "$CHECK_ZROOT" ]; then + printf "Please '. ./env $ANDROID_NDK_ROOT $INSTALLDIR' before running '$0'\n" + exit 1 +fi + +build_main diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..7368bf31 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,140 @@ +include Makefile.inc +include ../Makefile.common + +.PHONY: all clean header + +CC = gcc + +OABE_INCLUDE_DIR := $(INCLUDE_ROOT)/openabe +CXX11FLAGS += $(CXXFLAGS) + +RELICLIBS = -lrelic_s +#$(DEPS_INSTALL_ROOT)/lib/librelic_s.a + +GTESTLIBS = -lgtest -lpthread + +OABE_SHLIB = libopenabe.$(SHLIB) +OABE_KEYS = keys/zkdf.o keys/zkey.o keys/zpkey.o keys/zkeystore.o keys/zsymkey.o +OABE_LOW = ske/zcontextske.o pke/zcontextpke.o pksig/zcontextpksig.o \ + abe/zcontextabe.o abe/zcontextcca.o abe/zcontextcpwaters.o abe/zcontextkpgpsw.o +OABE_TOOLS = tools/zlsss.o tools/zprng.o +OABE_ZML = zml/zgroup.o zml/zpairing.o zml/zelliptic.o zml/zelement.o zml/zelement_ec.o zml/zelement_bp.o +OABE_UTILS = utils/zkeymgr.o utils/zcryptoutils.o utils/zcontainer.o utils/zbenchmark.o utils/zerror.o utils/zcontainer.o \ + utils/zciphertext.o utils/zpolicy.o utils/zattributelist.o utils/zdriver.o utils/zfunctioninput.o + +OABE_OBJ_TARGETS = zobject.o openabe.o zcontext.o zcrypto_box.o zsymcrypto.o zparser.o zscanner.o \ + $(OABE_ZML) $(OABE_KEYS) $(OABE_LOW) $(OABE_TOOLS) $(OABE_UTILS) openssl_init.o $(OS_OBJS) + +OABE_OBJ_FILES = zobject.o openabe.o zgroup.o zlsss.o zerror.o zpairing.o zelliptic.o zelement.o zelement_ec.o zelement_bp.o zcontainer.o zciphertext.o \ + zkey.o zpkey.o zkeystore.o zfunctioninput.o zcontext.o zpolicy.o zsymkey.o zprng.o zattributelist.o \ + zcontextske.o zcontextpke.o zcontextpksig.o zcontextabe.o zcontextcpwaters.o zcontextkpgpsw.o \ + zcontextcca.o zkdf.o zkeymgr.o zcryptoutils.o zcrypto_box.o zbenchmark.o zparser.o zscanner.o zdriver.o zsymcrypto.o \ + openssl_init.o $(OS_OBJS) + +ifeq ($(OS),Windows_NT) + LDFLAGS += -L/mingw64/bin +endif + +ifeq ($(ENABLE_GCOV), yes) + CXXFLAGS += $(COVERAGE_CFLAGS) + LDFLAGS += $(COVERAGE_LINKER) + SHFLAGS += $(COVERAGE_LINKER) +endif + +ZSYM_OBJS = zobject.o zerror.o zprng.o zsymcrypto.o + +LIBRARYH=header + +GENFILES = location.hh position.hh stack.hh *.tab.* zscanner.cpp + +PROGRAMS = test_libopenabe test_zml test_zml1 test_zml2 test_policy test_abe test_pke test_ske test_zsym test_keystore bench_libopenabe profile_libopenabe fuzz_policy fuzz_attrlist + +all: $(OABELIB) $(ZSYMLIB) $(PROGRAMS) + +zml/zelement.o: + $(CC) $(CCFLAGS) -c zml/zelement.c -o zelement.o + +zparser.o: zparser.yy + $(BISON) -d -v zparser.yy + cp *.hh $(OABE_INCLUDE_DIR) + $(CXX) $(CXXFLAGS) -c -o zparser.o zparser.tab.cc + +zscanner.o: zscanner.ll + $(FLEX) --outfile=zscanner.cpp $< + $(CXX) $(CXXFLAGS) -c zscanner.cpp -o zscanner.o + +header: + mkdir -p $(OABE_INCLUDE_DIR) + cp -r include/openabe/* $(OABE_INCLUDE_DIR) + +# provides PK, ABE, AEAD and crypto tools +$(OABELIB): $(LIBRARYH) $(OABE_OBJ_TARGETS) + $(AR) rcs $@ $(OABE_OBJ_FILES) + $(CXX) $(SHFLAGS) -o $(OABE_SHLIB) $(OABE_OBJ_FILES) $(SHLIB_PATH) $(OABELDSHLIBS) + mkdir -p $(OABE_LIB_ROOT) + cp $@ $(OABE_LIB_ROOT) + cp $(OABE_SHLIB) $(OABE_LIB_ROOT) + +# provides only AEAD impl for integration with libzclient +$(ZSYMLIB): $(OABELIB) + $(AR) rcs $(ZSYMLIB) $(ZSYM_OBJS) + cp $@ $(OABE_LIB_ROOT) + +test: + ./test_libopenabe || exit 1 + ./test_zml || exit 1 + ./test_abe || exit 1 + ./test_pke || exit 1 + ./test_ske || exit 1 + ./test_keystore || exit 1 + +test_libopenabe: $(OABELIB) + $(CXX) -o test_libopenabe $(CXX11FLAGS) $(LDFLAGS) -L. test_libopenabe.cpp $(OABELIB) $(OABELDLIBS) $(GTESTLIBS) + +test_zml: $(OABELIB) + $(CXX) -o test_zml $(CXX11FLAGS) $(LDFLAGS) -L. test_zml.cpp $(OABELIB) $(OABELDLIBS) $(GTESTLIBS) + +test_zml1: $(OABELIB) + $(CXX) -o test_zml1 $(CXX11FLAGS) $(LDFLAGS) -L. test_zml1.cpp $(OABELIB) $(OABELDLIBS) -lpthread + +test_zml2: $(OABELIB) + $(CXX) -o test_zml2 $(CXX11FLAGS) $(LDFLAGS) -L. test_zml2.cpp $(OABELIB) $(OABELDLIBS) -lpthread + +test_policy: $(OABELIB) + $(CXX) -o test_policy $(CXX11FLAGS) $(LDFLAGS) -L. test_policy.cpp $(OABELIB) $(OABELDLIBS) $(GTESTLIBS) + +test_abe: $(OABELIB) + $(CXX) -o test_abe $(CXX11FLAGS) $(LDFLAGS) -L. test_abe.cpp $(OABELIB) $(OABELDLIBS) $(GTESTLIBS) + +test_pke: $(OABELIB) + $(CXX) -o test_pke $(CXX11FLAGS) $(LDFLAGS) -L. test_pke.cpp $(OABELIB) $(OABELDLIBS) $(GTESTLIBS) + +test_ske: $(OABELIB) + $(CXX) -o test_ske $(CXX11FLAGS) $(LDFLAGS) -L. test_ske.cpp $(OABELIB) $(OABELDLIBS) $(GTESTLIBS) + +test_keystore: $(OABELIB) + $(CXX) -o test_keystore $(CXX11FLAGS) $(LDFLAGS) -L. test_keystore.cpp $(OABELIB) $(OABELDLIBS) $(GTESTLIBS) + +bench_libopenabe: $(OABELIB) + $(CXX) -o bench_libopenabe $(CXX11FLAGS) $(LDFLAGS) -L. bench_libopenabe.cpp $(OABELIB) $(OABELDLIBS) $(BOOST_SYSTEM) $(BOOST_THREAD) + +profile_libopenabe: $(OABELIB) + $(CXX) -o profile_libopenabe $(CXX11FLAGS) $(LDFLAGS) -L. profile_libopenabe.cpp $(OABELIB) $(OABELDLIBS) + +fuzz_policy: $(OABELIB) + $(CXX) -o fuzz_policy $(CXX11FLAGS) $(LDFLAGS) -L. fuzz_policy.cpp $(OABELIB) $(OABELDLIBS) + +fuzz_attrlist: $(OABELIB) + $(CXX) -o fuzz_attrlist $(CXX11FLAGS) $(LDFLAGS) -L. fuzz_attrlist.cpp $(OABELIB) $(OABELDLIBS) + +test_zsym: $(ZSYMLIB) + $(CXX) -o test_zsym $(CXX11FLAGS) $(LDFLAGS) -L. test_zsym.cpp $(ZSYMLIB) $(ZSYM_DEP_LIBS) + +clean: + -rm -rf *.o a.out $(PROGRAMS) $(OABELIB) $(OABE_SHLIB) $(ZSYMLIB) $(GENFILES) + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< + +%.o: %.c + $(CC) $(CXXFLAGS) -c $< diff --git a/src/Makefile.inc b/src/Makefile.inc new file mode 100644 index 00000000..3532089e --- /dev/null +++ b/src/Makefile.inc @@ -0,0 +1,10 @@ + +ZSYMLIB = libzsym.a +ZSYM_DEP_LIBS = -lcrypto +OABELIB = libopenabe.a + +AR = ar +MAKE = make +BISON = bison +FLEX = flex +INSTALL = install diff --git a/src/abe/zcontextabe.cpp b/src/abe/zcontextabe.cpp new file mode 100644 index 00000000..6d00becd --- /dev/null +++ b/src/abe/zcontextabe.cpp @@ -0,0 +1,408 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextabe.cpp +/// +/// \brief Abstract base class for the OpenABE context ABE +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include + +using namespace std; + +#include + +/******************************************************************************** + * Implementation of the OpenABEContextABE class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEContextABE base class. + * + */ +OpenABEContextABE::OpenABEContextABE() : OpenABEContext() {} + +/*! + * Destructor for the OpenABEContextABE base class. + * + */ +OpenABEContextABE::~OpenABEContextABE() {} + +/*! + * Initialize the pairing structure in underlying pairing library + * + * @param String for initializing the group parameters + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextABE::initializeCurve(const string groupParams) { + OpenABE_ERROR result = OpenABE_NOERROR; + if (this->m_Pairing_ != nullptr) { + return result; + } + // Instantiate a OpenABE pairing object with the given parameters + this->m_Pairing_.reset(OpenABE_createNewPairing(groupParams)); + if (this->m_Pairing_ == nullptr) { + throw OpenABE_ERROR_INVALID_GROUP_PARAMS; + } + return result; +} + + +/******************************************************************************** + * Implementation of the OpenABEContextSchemeCPA class + ********************************************************************************/ + +/*! + * Constructor for the OpenABEContextSchemeCPA base class. + * Note: we add to + */ +OpenABEContextSchemeCPA::OpenABEContextSchemeCPA(unique_ptr kem_) : ZObject() { + ASSERT_NOTNULL(kem_.get()); + if (kem_->getSchemeType() == OpenABE_SCHEME_KP_GPSW || + kem_->getSchemeType() == OpenABE_SCHEME_CP_WATERS) { + this->isMAABE = false; + } else { + /* unrecognized scheme type */ + throw OpenABE_ERROR_INVALID_INPUT; + } + this->m_KEM_ = move(kem_); +} + +/*! + * Destructor for the OpenABEContextABE base class. + * + */ +OpenABEContextSchemeCPA::~OpenABEContextSchemeCPA() {} + +/*! + * Generate parameters of the pairing curve based on a string identifier. + * + * @param[in] specific string identifier to instantiate the pairing curve. + * @param[in] a string identifier for the master public parameters. + * @param[in] a string identifier for the master secret parameters. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCPA::generateParams(const string groupParams, const string &mpkID, + const string &mskID) { + return this->m_KEM_->generateParams(groupParams, mpkID, mskID); +} + +OpenABE_ERROR +OpenABEContextSchemeCPA::generateGlobalParams(const string groupParams, + const string &gpkID) { + return OpenABE_ERROR_NOT_IMPLEMENTED; +} + +OpenABE_ERROR +OpenABEContextSchemeCPA::generateAuthorityParams(const string &gpkID, + const string &auth_mpkID, + const string &auth_mskID) { + return OpenABE_ERROR_NOT_IMPLEMENTED; +} + +/*! + * Retrieve the hash function key from the master public parameters + * + * @param[in] identifier for the MPK in the keystore. + * @param[out] a pointer to the internal OpenABEByteString of the hash key + * @return OpenABEByteString of hash key (should not be freed by caller) + */ +OpenABEByteString* +OpenABEContextSchemeCPA::getHashKey(const std::string &mpkID) { + std::shared_ptr MPK = this->m_KEM_->getKeystore()->getPublicKey(mpkID); + if (!MPK) { + throw OpenABE_ERROR_INVALID_PARAMS; + } else { + // hash key defined for every scheme in the OpenABE + return MPK->getByteString("k"); + } +} + + +/*! + * Export a key from the keystore given the key identifier. + * + * @param[in] identifier for the key. + * @param[out] an allocated OpenABEByteString to store the exported key header/body. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCPA::exportKey(const string &keyID, OpenABEByteString &keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString tmpKeyBlob; + + try { + // attempt to export the given keyID to a temp keyBlob output buffer + if (OpenABE_exportKey(this->m_KEM_->getKeystore(), keyID, &tmpKeyBlob) != + OpenABE_NOERROR) { + throw OpenABE_ERROR_INVALID_INPUT; + } + + // just set the keyBlob + keyBlob.clear(); + keyBlob += tmpKeyBlob; + // clear the temp buffer + tmpKeyBlob.clear(); + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +/*! + * Generic method for loading a key header/body regardless of the key type. + * + * @param[in] identifier for the key. + * @param[in] serialized blob that represents the key parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @param[in] a key type for designating storage in keystore. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCPA::loadKey(const string &ID, OpenABEByteString &keyBlob, + zKeyType keyType) { + OpenABEByteString outputKeyBytes; + shared_ptr KEY = this->m_KEM_->getKeystore()->parseKeyHeader( + ID, keyBlob, outputKeyBytes); + if (KEY == nullptr) { + return OpenABE_ERROR_INVALID_INPUT; + } + + // initialize the pairing object if not already + if (this->m_KEM_->getPairing() == nullptr) { + this->m_KEM_->initializeCurve( + OpenABE_convertCurveIDToString((OpenABECurveID)KEY->getCurveID())); + } + + // validate the header is not malformed + if (KEY->getCurveID() != this->m_KEM_->getPairing()->getCurveID() || + KEY->getAlgorithmID() != this->m_KEM_->getAlgorithmID()) { + // SAFE_DELETE(KEY); + return OpenABE_ERROR_INVALID_KEY_HEADER; + } + // now, we can load the key + KEY->setGroup(this->m_KEM_->getPairing()->getGroup()); + KEY->loadKeyFromBytes(outputKeyBytes); + this->m_KEM_->getKeystore()->addKey(ID, KEY, keyType); + + return OpenABE_NOERROR; +} + +/*! + * Load and validate the master public parameters. + * + * @param[in] identifier for the public key in the keystore. + * @param[in] serialized blob that represents the public parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCPA::loadMasterPublicParams(const string &mpkID, + OpenABEByteString &mpkBlob) { + return this->loadKey(mpkID, mpkBlob, KEY_TYPE_PUBLIC); +} + +/*! + * Load and validate the master secret parameters. + * + * @param[in] identifier for the secret key in the keystore. + * @param[in] serialized blob that represents the secret parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCPA::loadMasterSecretParams(const string &mskID, + OpenABEByteString &mskBlob) { + return this->loadKey(mskID, mskBlob, KEY_TYPE_SECRET); +} + +/*! + * Load and validate the user's secret parameter. + * + * @param[in] identifier for the secret key in the keystore. + * @param[in] serialized blob that represents the secret parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextSchemeCPA::loadUserSecretParams(const string &skID, + OpenABEByteString &skBlob) { + return this->loadKey(skID, skBlob, KEY_TYPE_SECRET); +} + + +/*! + * Delete a key from the in-memory keystore given a key identifier. + * + * @param[in] a string key identifier. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCPA::deleteKey(const string keyID) { + return this->m_KEM_->getKeystore()->deleteKey(keyID); +} + +bool OpenABEContextSchemeCPA::checkSecretKey(const string keyID) { + return this->m_KEM_->getKeystore()->checkSecretKey(keyID); +} + +/*! + * Generate a public/private keypair for a given user. + * + * @param[in] functional input of the key to be created (either attribute list or policy). + * @param[in] parameter ID of the master public key. + * @param[in] parameter ID of the master secret key. + * @param[in] parameter ID of the global public key (optional). + * @param[in] parameter ID of the global identifier (optional). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCPA::keygen(OpenABEFunctionInput *keyInput, const string &keyID, + const string &mpkID, const string &mskID, + const string &gpkID, const string &GID) { + return this->m_KEM_->generateDecryptionKey(keyInput, keyID, mpkID, mskID, + gpkID, GID); +} + +/*! + * Generate and encrypt a symmetric key using the key encapsulation mode + * of the underlying KEM scheme. Use the symmetric key with PRNG to encrypt + * the plaintext. Return the ciphertext. + * + * @param[in] random number generator to use during encryption (it is optional: could be set to NULL here). + * @param[in] master public key identifier in keystore for the recipient (assumes it's already in keystore). + * @param[in] functional input of the underlying KEM context (either attribute list or policy). + * @param[in] the plaintext. + * @param[out] the ciphertext (must be allocated). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCPA::encrypt(OpenABERNG *rng, const string &mpkID, + const OpenABEFunctionInput *encryptInput, + OpenABEByteString *plaintext, OpenABECiphertext *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr K(new OpenABESymKey); + unique_ptr PRNG = nullptr; + unique_ptr y = nullptr; + + try { + ASSERT_NOTNULL(plaintext); + ASSERT_NOTNULL(ciphertext); + // generate Key Encapsulation for access structure under MPK + result = this->m_KEM_->encryptKEM(rng, mpkID, encryptInput, + DEFAULT_SYM_KEY_BYTES, K, ciphertext); + ASSERT(result == OpenABE_NOERROR, result); + // compute H_0(K) to get initial seed for PRNG + uint32_t target_len = plaintext->size(); + OpenABEByteString hashK = this->m_KEM_->getPairing()->hashFromBytes( + K->getKeyBytes(), OpenABE_CTR_DRBG_NONCELEN, SCHEME_HASH_FUNCTION); + + // instantiate PRNG with entropy from K + PRNG.reset(new OpenABECTR_DRBG(K->getInternalPtr(), K->getLength())); + // hashK buffer as initial seed (or plaintext) + PRNG->setSeed(hashK); + // extract length bytes from RNG then XOR with plaintext + y.reset(new OpenABEByteString); + PRNG->getRandomBytes(y.get(), target_len); + // y = y XOR plaintext + *y ^= *plaintext; + ciphertext->setComponent("_ED", y.get()); // encryptedData + + // cout << "encryptedData: " << y->toHex() << endl; + hashK.zeroize(); + K->zeroize(); + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + + /*! + * Decrypt a symmetric key using the key encapsulation mode + * of the underlying scheme. Use the key with PRNG to decrypt + * the other half of the ciphertext payload. Return the plaintext. + * + * @param[in] master public key identifier of the sender (assumes it's already in keystore). + * @param[in] key identifier of recipient (assumes it's already in keystore). + * @param[out] OpenABEByteString object to store resulting plaintext (assumes it's already allocated). + * @param[in] the ciphertext. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCPA::decrypt(const string &mpkID, const string &keyID, + OpenABEByteString *plaintext, OpenABECiphertext *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr K(new OpenABESymKey); + unique_ptr PRNG = nullptr; + + try { + result = this->m_KEM_->decryptKEM(mpkID, keyID, ciphertext, + DEFAULT_SYM_KEY_BYTES, K); + ASSERT(result == OpenABE_NOERROR, result); + // retrieve encrypted data + OpenABEByteString *encMessage = + ciphertext->getByteString("_ED"); // encryptedData + if (encMessage == nullptr) { + throw OpenABE_ERROR_INVALID_INPUT; + } + + uint32_t target_len = encMessage->size(); + OpenABEByteString hashK = this->m_KEM_->getPairing()->hashFromBytes( + K->getKeyBytes(), OpenABE_CTR_DRBG_NONCELEN, SCHEME_HASH_FUNCTION); + // instantiate PRNG with the K from encryptKEM + PRNG.reset(new OpenABECTR_DRBG(K->getInternalPtr(), K->getLength())); + // hashK buffer as initial seed (or plaintext) + PRNG->setSeed(hashK); + + // extract length bytes from RNG then XOR with plaintext + plaintext->clear(); + PRNG->getRandomBytes(plaintext, target_len); + + // PRNG(K, l) XOR *encMessage + *plaintext ^= *encMessage; + // zeroize + hashK.zeroize(); + K->zeroize(); + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} +} diff --git a/src/abe/zcontextcca.cpp b/src/abe/zcontextcca.cpp new file mode 100644 index 00000000..7812b5fb --- /dev/null +++ b/src/abe/zcontextcca.cpp @@ -0,0 +1,894 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextcca.cpp +/// +/// \brief Base class definition for OpenABE context CCA schemes +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace oabe::crypto; + +/******************************************************************************** + * Implementation of the OpenABEContextCCA class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEContextCCA base class. + * + */ +OpenABEContextCCA::OpenABEContextCCA(unique_ptr scheme_) + : OpenABEContextABE() { + if (scheme_) { + this->abeSchemeContext = move(scheme_); + } else { + /* throw error */ + throw OpenABE_ERROR_INVALID_INPUT; + } +} + +/*! + * Destructor for the OpenABEContextCCA base class. + * + */ + +OpenABEContextCCA::~OpenABEContextCCA() {} + +/*! + * Export a key from the keystore given the key identifier. + * + * @param[in] identifier for the key. + * @param[out] an allocated OpenABEByteString to store the exported key header/body. + * @param[in] a password to encrypt the exported key under (optional). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextCCA::exportKey(const string &keyID, OpenABEByteString &keyBlob) { + return this->abeSchemeContext->exportKey(keyID, keyBlob); +} + +/*! + * Load and validate the master public parameters. + * + * @param[in] identifier for the public key in the keystore. + * @param[in] serialized blob that represents the public parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextCCA::loadMasterPublicParams(const string &mpkID, + OpenABEByteString &mpkBlob) { + return this->abeSchemeContext->loadMasterPublicParams(mpkID, mpkBlob); +} + +/*! + * Load and validate the master secret parameters. + * + * @param[in] identifier for the secret key in the keystore. + * @param[in] serialized blob that represents the secret parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextCCA::loadMasterSecretParams(const string &mskID, + OpenABEByteString &mskBlob) { + return this->abeSchemeContext->loadMasterSecretParams(mskID, mskBlob); +} + +/*! + * Load and validate the user's secret parameter. + * + * @param[in] identifier for the secret key in the keystore. + * @param[in] serialized blob that represents the secret parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextCCA::loadUserSecretParams(const string &skID, OpenABEByteString &skBlob) { + return this->abeSchemeContext->loadUserSecretParams(skID, skBlob); +} + + +/*! + * Delete a key from the in-memory keystore given a key identifier. + * + * @param[in] a string key identifier. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextCCA::deleteKey(const string keyID) { + return this->abeSchemeContext->deleteKey(keyID); +} + +bool +OpenABEContextCCA::checkSecretKey(const string keyID) +{ + return this->abeSchemeContext->checkSecretKey(keyID); +} + +OpenABE_ERROR +OpenABEContextCCA::generateGlobalParams(const string groupParams, + const string &gpkID) { + return this->abeSchemeContext->generateGlobalParams(groupParams, gpkID); +} + +OpenABE_ERROR +OpenABEContextCCA::generateAuthorityParams(const string &gpkID, + const string &auth_mpkID, + const string &auth_mskID) { + return this->abeSchemeContext->generateAuthorityParams(gpkID, auth_mpkID, + auth_mskID); +} + +OpenABEByteString* +OpenABEContextCCA::getHashKey(const string &mpkID) { + return this->abeSchemeContext->getHashKey(mpkID); +} + +/******************************************************************************** + * Implementation of the OpenABEContextGenericCCA class + ********************************************************************************/ + +/*! + * Constructor for the OpenABEContextGenericCCA base class. + * + */ +OpenABEContextGenericCCA::OpenABEContextGenericCCA(unique_ptr scheme) + : OpenABEContextCCA(move(scheme)) {} + +/*! + * Destructor for the OpenABEContextCCA base class. + * + */ + +OpenABEContextGenericCCA::~OpenABEContextGenericCCA() {} + +OpenABE_ERROR +OpenABEContextGenericCCA::generateParams(const string groupParams, + const string &mpkID, const string &mskID) { + return this->abeSchemeContext->generateParams(groupParams, mpkID, mskID); +} + + +/*! + * Generate a decryption key for a given function input. This function + * requires that the master secret parameters are available. + * + * @param[in] mpkID - parameter ID of the Master Public Key + * @param[in] mskID - parameter ID of the Master Secret Key + * @param[in] keyID - parameter ID of the decryption key to be created + * @param[in] keyInput - A OpenABEAttributeList structure for the key to be constructed + * @return - An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextGenericCCA::generateDecryptionKey( + OpenABEFunctionInput *keyInput, const string &keyID, const string &mpkID, + const string &mskID, const string &gpkID, const string &GID) { + return this->abeSchemeContext->keygen(keyInput, keyID, mpkID, mskID, gpkID, + GID); +} + +/*! + * Generate and encrypt a symmetric key using the key encapsulation mode + * of the scheme. Use resulting key to encrypt randomness and plaintext. + * Return the ciphertext. + * + * @param Parameters ID for the public master parameters. + * @param Function input for the encryption. + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextGenericCCA::encryptKEM(OpenABERNG *rng, const string &mpkID, + const OpenABEFunctionInput *encryptInput, + uint32_t keyByteLen, + const std::shared_ptr &key, + OpenABECiphertext *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABERNG *myRNG = nullptr; + unique_ptr PRNG = nullptr; + OpenABEByteString r, K, u, nonceU, concat; + try { + ASSERT_NOTNULL(encryptInput); + ASSERT_NOTNULL(key); + ASSERT_NOTNULL(ciphertext); + if (rng == nullptr) { + // expect the RNG to be set in constructor + myRNG = this->getRNG(); + } else { + // use the passed in RNG + myRNG = rng; + } + // Assert that the RNG has been set + ASSERT_NOTNULL(myRNG); + + // choose r + myRNG->getRandomBytes(&r, keyByteLen); + // cout << "r : " << r.toHex() << endl; + + // choose K + myRNG->getRandomBytes(&K, keyByteLen); + // cout << "K : " << K.toHex() << endl; + + // set M = r || K + OpenABEByteString M = r + K; + // r || K || A + concat = M + encryptInput->toString(); + // uint32_t target_len = concat.size(); + + // u = H_1(r || K || A) + u = this->getPairing()->hashFromBytes(concat, keyByteLen, + CCA_HASH_FUNCTION_ONE); + // hashU = H_2(u) + nonceU = this->getPairing()->hashFromBytes(u, OpenABE_CTR_DRBG_NONCELEN, + CCA_HASH_FUNCTION_TWO); + + // construct a new PRNG + // set the key and seed (or plaintext) + PRNG.reset(new OpenABECTR_DRBG(u)); + PRNG->setSeed(nonceU); + + // compute ciphertext, C + result = this->abeSchemeContext->encrypt(PRNG.get(), mpkID, encryptInput, + &M, ciphertext); + if (result != OpenABE_NOERROR) { + OpenABE_LOG_AND_THROW("ABE Encryption failed.", OpenABE_ERROR_ENCRYPTION_ERROR); + } + + // set the encapsulation key + // by storing K in 'key' object + key->setSymmetricKey(K); + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +/*! + * Decrypt a symmetric key using the generic transform + * Return the key. + * + * @param Parameters ID for the public master parameters. + * @param Identifier for the decryption key to be used. + * @param ABE ciphertext. + * @param Symmetric key to be returned. + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextGenericCCA::decryptKEM(const string &mpkID, const string &keyID, + OpenABECiphertext *ciphertext, uint32_t keyByteLen, + const std::shared_ptr &key) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString M; + unique_ptr PRNG = nullptr; + unique_ptr encryptInput = nullptr; + unique_ptr ciphertext2(new OpenABECiphertext); + OpenABEByteString u, nonceU, concat; + + try { + // fully decrypt the ciphertext and recover 'r' and 'M' + ASSERT_NOTNULL(ciphertext); + ASSERT_NOTNULL(key); + result = this->abeSchemeContext->decrypt(mpkID, keyID, &M, ciphertext); + if (result != OpenABE_NOERROR) { + OpenABE_LOG_AND_THROW("ABE Decryption failed.", OpenABE_ERROR_DECRYPTION_FAILED); + } + + // extract 'r' and 'K' from M + OpenABEByteString r = M.getSubset(0, keyByteLen); + OpenABEByteString K = M.getSubset(keyByteLen, keyByteLen); + + // retrieve inputs from ciphertext and recovered message + encryptInput = getFunctionInput(ciphertext); + if (encryptInput == nullptr) { + OpenABE_LOG_AND_THROW("Failed to get functional input.", + OpenABE_ERROR_INVALID_INPUT); + } + // r' || K' || A + concat = r + K + encryptInput->toString(); + // u = H_1(r' || K' || A) + u = this->getPairing()->hashFromBytes(concat, keyByteLen, + CCA_HASH_FUNCTION_ONE); + // nonceU = H_2(u) + nonceU = this->getPairing()->hashFromBytes(u, OpenABE_CTR_DRBG_NONCELEN, + CCA_HASH_FUNCTION_TWO); + + // construct a new PRNG + // set the key and seed (or plaintext) + PRNG.reset(new OpenABECTR_DRBG(u)); + PRNG->setSeed(nonceU); + + // compute ciphertext, C + result = this->abeSchemeContext->encrypt( + PRNG.get(), mpkID, encryptInput.get(), &M, ciphertext2.get()); + // verification check + if (*ciphertext == *ciphertext2) { + key->setSymmetricKey(K); + } else { + OpenABE_LOG_AND_THROW("Failed ABE decryption verification check.", + OpenABE_ERROR_DECRYPTION_FAILED); + } + + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +/******************************************************************************** + * Implementation of the OpenABEContextSchemeCCA class + ********************************************************************************/ + +/*! + * Constructor for the OpenABEContextSchemeCCA base class. + * Note: we add to + */ +OpenABEContextSchemeCCA::OpenABEContextSchemeCCA(unique_ptr kem_) + : ZObject() { + OpenABE_SCHEME scheme_type = OpenABE_SCHEME_NONE; + // upgrade the scheme type according to input KEM type + if (kem_->getSchemeType() == OpenABE_SCHEME_KP_GPSW) { + scheme_type = OpenABE_SCHEME_KP_GPSW_CCA; + } else if (kem_->getSchemeType() == OpenABE_SCHEME_CP_WATERS) { + scheme_type = OpenABE_SCHEME_CP_WATERS_CCA; + } else { + /* unrecognized scheme type */ + throw OpenABE_ERROR_INVALID_INPUT; + } + this->m_KEM_ = move(kem_); + this->m_KEM_->setSchemeType(scheme_type); +} + +/*! + * Destructor for the OpenABEContextABE base class. + * + */ +OpenABEContextSchemeCCA::~OpenABEContextSchemeCCA() {} + +/*! + * Generate parameters of the pairing curve based on a string identifier. + * + * @param[in] specific string identifier to instantiate the pairing curve. + * @param[in] a string identifier for the master public parameters. + * @param[in] a string identifier for the master secret parameters. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCA::generateParams(const string groupParams, + const string &mpkID, const string &mskID) { + return this->m_KEM_->generateParams(groupParams, mpkID, mskID); +} + +/*! + * Generate global parameters of the pairing curve based on a string identifier. + * + * @param[in] specific string identifier to instantiate the pairing curve. + * @param[in] a string identifier for the global public parameters. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCA::generateGlobalParams(const string groupParams, + const string &gpkID) { + return this->m_KEM_->generateGlobalParams(groupParams, gpkID); +} + +/*! + * Generate authority parameters of the pairing curve based on a string identifier. + * + * @param[in] specific string identifier to instantiate the pairing curve. + * @param[in] a string identifier for the authority's master public parameters. + * @param[in] a string identifier for the authority's master secret parameters. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCA::generateAuthorityParams(const string &gpkID, + const string &auth_mpkID, + const string &auth_mskID) { + return this->m_KEM_->generateAuthorityParams(gpkID, auth_mpkID, auth_mskID); +} + +/*! + * Export a key from the keystore given the key identifier. + * + * @param[in] identifier for the key. + * @param[out] an allocated OpenABEByteString to store the exported key header/body. + * @param[in] a password to encrypt the exported key under (optional). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCA::exportKey(const string &keyID, OpenABEByteString &keyBlob) { + return this->m_KEM_->exportKey(keyID, keyBlob); +} + +/*! + * Load and validate the master public parameters. + * + * @param[in] identifier for the public key in the keystore. + * @param[in] serialized blob that represents the public parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCA::loadMasterPublicParams(const string &mpkID, + OpenABEByteString &mpkBlob) { + return this->m_KEM_->loadMasterPublicParams(mpkID, mpkBlob); +} + +/*! + * Load and validate the master secret parameters. + * + * @param[in] identifier for the secret key in the keystore. + * @param[in] serialized blob that represents the secret parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCA::loadMasterSecretParams(const string &mskID, + OpenABEByteString &mskBlob) { + return this->m_KEM_->loadMasterSecretParams(mskID, mskBlob); +} + +/*! + * Load and validate the user's secret parameter. + * + * @param[in] identifier for the secret key in the keystore. + * @param[in] serialized blob that represents the secret parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextSchemeCCA::loadUserSecretParams(const string &skID, + OpenABEByteString &skBlob) { + return this->m_KEM_->loadUserSecretParams(skID, skBlob); +} + + +/*! + * Delete a key from the in-memory keystore given a key identifier. + * + * @param[in] a string key identifier. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCA::deleteKey(const string keyID) { + return this->m_KEM_->deleteKey(keyID); +} + +bool OpenABEContextSchemeCCA::checkSecretKey(const string keyID) { + return this->m_KEM_->checkSecretKey(keyID); +} + +/*! + * Generate a public/private keypair for a given user. + * + * @param[in] functional input of the key to be created (either attribute list or policy). + * @param[in] parameter ID of the master public key. + * @param[in] parameter ID of the master secret key. + * @param[in] parameter ID of the global public key (optional). + * @param[in] parameter ID of the global identifier (optional). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCA::keygen(OpenABEFunctionInput *keyInput, const string &keyID, + const string &mpkID, const string &mskID, + const string &gpkID, const string &GID) { + return this->m_KEM_->generateDecryptionKey(keyInput, keyID, mpkID, mskID, + gpkID, GID); +} + +/*! + * Generate and encrypt a symmetric key using the key encapsulation mode + * of the underlying KEM scheme. Use the symmetric key with AES-GCM to encrypt + * the plaintext. Return the ciphertext. + * + * @param[in] random number generator to use during encryption (it is optional: could be set to NULL here). + * @param[in] master public key identifier in keystore for the recipient (assumes it's already in keystore). + * @param[in] functional input of the underlying KEM context (either attribute list or policy). + * @param[in] the plaintext. + * @param[out] the ciphertext (must be allocated). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCA::encrypt(const string &mpkID, + const OpenABEFunctionInput *encryptInput, + const string &plaintext, + OpenABECiphertext *ciphertext1, + OpenABECiphertext *ciphertext2) { + OpenABE_ERROR result = OpenABE_NOERROR; + unique_ptr rng(new OpenABERNG); + shared_ptr symkey(new OpenABESymKey); + OpenABEByteString ctHdr, symkeyBytes, iv, ct, tag; + + try { + ASSERT_NOTNULL(ciphertext1); + ASSERT_NOTNULL(ciphertext2); + // make sure plaintext size > 0 + ASSERT(plaintext.size() > 0, OpenABE_ERROR_NO_PLAINTEXT_SPECIFIED); + + result = + this->m_KEM_->encryptKEM(rng.get(), mpkID, encryptInput, + DEFAULT_SYM_KEY_BYTES, symkey, ciphertext1); + ASSERT(result == OpenABE_NOERROR, result); + // instantiate an auth enc scheme with the symmetric key + symkeyBytes = symkey->getKeyBytes(); + unique_ptr authEnc( + new oabe::crypto::OpenABESymKeyAuthEnc(DEFAULT_AES_SEC_LEVEL, symkeyBytes)); + // obtain header from ciphertext + ciphertext1->getHeader(ctHdr); + // embed the header of the ciphertext as AAD + authEnc->setAddAuthData(ctHdr); + // encrypt plaintext and store in iv/ct/tag + authEnc->encrypt(plaintext, &iv, &ct, &tag); + + // Store symmetric ciphertext + ciphertext2->setComponent("IV", &iv); + ciphertext2->setComponent("CT", &ct); + ciphertext2->setComponent("Tag", &tag); + ciphertext2->setHeader(OpenABE_NONE_ID, OpenABE_SCHEME_AES_GCM, ciphertext1->getUID()); + } catch (OpenABE_ERROR &error) { + result = error; + } + + symkey->zeroize(); + symkeyBytes.zeroize(); + return result; +} + + /*! + * Decrypt a symmetric key using the key encapsulation mode + * of the underlying scheme. Use the key with AES-GCM to decrypt + * the other half of the ciphertext payload. Return the plaintext. + * + * @param[in] master public key identifier of the sender (assumes it's already in keystore). + * @param[in] key identifier of recipient (assumes it's already in keystore). + * @param[out] string reference to store resulting plaintext if decrypt successful. + * @param[in] the ciphertext. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCA::decrypt(const string &mpkID, const string &keyID, + string &plaintext, OpenABECiphertext *ciphertext1, + OpenABECiphertext *ciphertext2) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString ctHdr, symkeyBytes; + OpenABEByteString *iv, *ct, *tag; + shared_ptr symkey(new OpenABESymKey); + unique_ptr authEnc = nullptr; + + try { + ASSERT_NOTNULL(ciphertext1); + ASSERT_NOTNULL(ciphertext2); + iv = ciphertext2->getByteString("IV"); + ASSERT_NOTNULL(iv); + ct = ciphertext2->getByteString("CT"); + ASSERT_NOTNULL(ct); + tag = ciphertext2->getByteString("Tag"); + ASSERT_NOTNULL(tag); + + // get the header of the input ciphertext + ciphertext1->getHeader(ctHdr); + // decrypt part 1 of the ciphertext (corresponds to ABE portion) + result = this->m_KEM_->decryptKEM(mpkID, keyID, ciphertext1, + DEFAULT_SYM_KEY_BYTES, symkey); + // propagate errors from decryptKEM + ASSERT(result == OpenABE_NOERROR, result); + // apply AEAD to decrypt part 2 of the ciphertext (ciphertext header is + // added as add auth data) + symkeyBytes = symkey->getKeyBytes(); + authEnc.reset( + new oabe::crypto::OpenABESymKeyAuthEnc(DEFAULT_AES_SEC_LEVEL, symkeyBytes)); + // embed the header of the ciphertext as AAD + authEnc->setAddAuthData(ctHdr); + // now attempt to decrypt + if (!authEnc->decrypt(plaintext, iv, ct, tag)) { + throw OpenABE_ERROR_DECRYPTION_FAILED; + } + } catch (OpenABE_ERROR &error) { + result = error; + } + + symkey->zeroize(); + symkeyBytes.zeroize(); + return result; +} + +/******************************************************************************** + * Implementation of the OpenABEContextSchemeCCAWithATZN class + ********************************************************************************/ + +/*! + * Constructor for the OpenABEContextSchemeCCA base class. + * Note: we add to + */ +OpenABEContextSchemeCCAWithATZN::OpenABEContextSchemeCCAWithATZN(unique_ptr kem_) + : ZObject() { + OpenABE_SCHEME scheme_type = OpenABE_SCHEME_NONE; + // upgrade the scheme type according to input KEM type + if (kem_->getSchemeType() == OpenABE_SCHEME_KP_GPSW) { + scheme_type = OpenABE_SCHEME_KP_GPSW_CCA; + } else if (kem_->getSchemeType() == OpenABE_SCHEME_CP_WATERS) { + scheme_type = OpenABE_SCHEME_CP_WATERS_CCA; + } else { + /* unrecognized scheme type */ + throw OpenABE_ERROR_INVALID_INPUT; + } + this->m_KEM_ = move(kem_); + this->m_KEM_->setSchemeType(scheme_type); +} + +/*! + * Destructor for the OpenABEContextSchemeCCAWithATZN base class. + * + */ +OpenABEContextSchemeCCAWithATZN::~OpenABEContextSchemeCCAWithATZN() {} + +/*! + * Generate parameters of the pairing curve based on a string identifier. + * + * @param[in] specific string identifier to instantiate the pairing curve. + * @param[in] a string identifier for the master public parameters. + * @param[in] a string identifier for the master secret parameters. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCAWithATZN::generateParams(const string groupParams, + const string &mpkID, const string &mskID) { + return this->m_KEM_->generateParams(groupParams, mpkID, mskID); +} + +/*! + * Generate global parameters of the pairing curve based on a string identifier. + * + * @param[in] specific string identifier to instantiate the pairing curve. + * @param[in] a string identifier for the global public parameters. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCAWithATZN::generateGlobalParams(const string groupParams, + const string &gpkID) { + return this->m_KEM_->generateGlobalParams(groupParams, gpkID); +} + +/*! + * Generate authority parameters of the pairing curve based on a string identifier. + * + * @param[in] specific string identifier to instantiate the pairing curve. + * @param[in] a string identifier for the authority's master public parameters. + * @param[in] a string identifier for the authority's master secret parameters. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCAWithATZN::generateAuthorityParams(const string &gpkID, + const string &auth_mpkID, + const string &auth_mskID) { + return this->m_KEM_->generateAuthorityParams(gpkID, auth_mpkID, auth_mskID); +} + +/*! + * Export a key from the keystore given the key identifier. + * + * @param[in] identifier for the key. + * @param[out] an allocated OpenABEByteString to store the exported key header/body. + * @param[in] a password to encrypt the exported key under (optional). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCAWithATZN::exportKey(const string &keyID, OpenABEByteString &keyBlob) { + return this->m_KEM_->exportKey(keyID, keyBlob); +} + +/*! + * Load and validate the master public parameters. + * + * @param[in] identifier for the public key in the keystore. + * @param[in] serialized blob that represents the public parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCAWithATZN::loadMasterPublicParams(const string &mpkID, + OpenABEByteString &mpkBlob) { + return this->m_KEM_->loadMasterPublicParams(mpkID, mpkBlob); +} + +/*! + * Load and validate the master secret parameters. + * + * @param[in] identifier for the secret key in the keystore. + * @param[in] serialized blob that represents the secret parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCAWithATZN::loadMasterSecretParams(const string &mskID, + OpenABEByteString &mskBlob) { + return this->m_KEM_->loadMasterSecretParams(mskID, mskBlob); +} + +/*! + * Load and validate the user's secret parameter. + * + * @param[in] identifier for the secret key in the keystore. + * @param[in] serialized blob that represents the secret parameters. + * @param[in] an optional password to derive a key for decrypting the serialized blob. + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextSchemeCCAWithATZN::loadUserSecretParams(const string &skID, + OpenABEByteString &skBlob) { + return this->m_KEM_->loadUserSecretParams(skID, skBlob); +} + + +/*! + * Delete a key from the in-memory keystore given a key identifier. + * + * @param[in] a string key identifier. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCAWithATZN::deleteKey(const string keyID) { + return this->m_KEM_->deleteKey(keyID); +} + +bool OpenABEContextSchemeCCAWithATZN::checkSecretKey(const string keyID) { + return this->m_KEM_->checkSecretKey(keyID); +} + +/*! + * Generate a public/private keypair for a given user. + * + * @param[in] functional input of the key to be created (either attribute list or policy). + * @param[in] parameter ID of the master public key. + * @param[in] parameter ID of the master secret key. + * @param[in] parameter ID of the global public key (optional). + * @param[in] parameter ID of the global identifier (optional). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemeCCAWithATZN::keygen(OpenABEFunctionInput *keyInput, const string &keyID, + const string &mpkID, const string &mskID, + const string &gpkID, const string &GID) { + return this->m_KEM_->generateDecryptionKey(keyInput, keyID, mpkID, mskID, + gpkID, GID); +} + +/*! + * Generate and encrypt a symmetric key using the key encapsulation mode + * of the underlying KEM scheme. Use the symmetric key with AES-GCM to encrypt + * the plaintext. Return the ciphertext. + * + * @param[in] random number generator to use during encryption (it is optional: could be set to NULL here). + * @param[in] master public key identifier in keystore for the recipient (assumes it's already in keystore). + * @param[in] functional input of the underlying KEM context (either attribute list or policy). + * @param[out] the ciphertext (must be allocated). + * @param[out] the sym key handle for encrypting data + * @return An error code or OpenABE_NOERROR. + */ +std::unique_ptr +OpenABEContextSchemeCCAWithATZN::encrypt(const string &mpkID, + const OpenABEFunctionInput *encryptInput, + OpenABECiphertext *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + unique_ptr rng(new OpenABERNG); + shared_ptr symkey(new OpenABESymKey); + unique_ptr keyHandle = nullptr; + OpenABEByteString ctBlob, ctHash, symkeyBytes; + + try { + ASSERT_NOTNULL(encryptInput); + ASSERT_NOTNULL(ciphertext); + + result = + this->m_KEM_->encryptKEM(rng.get(), mpkID, encryptInput, + DEFAULT_SYM_KEY_BYTES, symkey, ciphertext); + ASSERT(result == OpenABE_NOERROR, result); + // retrieve the symmetric key + symkeyBytes = symkey->getKeyBytes(); + // (1) get the ciphertext header and body bytes + ciphertext->exportToBytes(ctBlob); + // (2) compute hash of the ciphertext + OpenABEByteString *k = this->m_KEM_->getHashKey(mpkID); + ASSERT_NOTNULL(k); + OpenABEComputeHash(*k, ctBlob, ctHash); + // (3) create the key handle (from key and hash of ABE ciphertext) + keyHandle.reset(new OpenABESymKeyHandleImpl(symkeyBytes, ctHash)); // no b64 encoding by default + } catch (OpenABE_ERROR &error) { + cerr << "CCAWithATZN::encrypt: " << OpenABE_errorToString(error) << endl; + } catch (oabe::CryptoException& ex) { + cerr << "CCAWithATZN::encrypt(CryptoException): " << ex.what() << endl; + } + + symkey->zeroize(); + symkeyBytes.zeroize(); + return keyHandle; +} + + /*! + * Decrypt a symmetric key using the key encapsulation mode + * of the underlying scheme. Return the key handle. + * + * @param[in] master public key identifier of the sender (assumes it's already in keystore). + * @param[in] key identifier of recipient (assumes it's already in keystore). + * @param[out] string reference to store resulting plaintext if decrypt successful. + * @param[in] the ciphertext. + * @return An error code or OpenABE_NOERROR. + */ +std::unique_ptr +OpenABEContextSchemeCCAWithATZN::decrypt(const string &mpkID, const string &keyID, + OpenABECiphertext *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr symkey(new OpenABESymKey); + unique_ptr keyHandle = nullptr; + OpenABEByteString ctBlob, ctHash, symkeyBytes; + + try { + ASSERT_NOTNULL(ciphertext); + // decrypt part 1 of the ciphertext (corresponds to ABE portion) + result = this->m_KEM_->decryptKEM(mpkID, keyID, ciphertext, + DEFAULT_SYM_KEY_BYTES, symkey); + // propagate errors from decryptKEM + ASSERT(result == OpenABE_NOERROR, result); + // (0) retrieve the symmetric key + symkeyBytes = symkey->getKeyBytes(); + // (1) get the ciphertext header and body bytes + ciphertext->exportToBytes(ctBlob); + // (2) compute hash of the ciphertext + OpenABEByteString *k = this->m_KEM_->getHashKey(mpkID); + ASSERT_NOTNULL(k); + OpenABEComputeHash(*k, ctBlob, ctHash); + // (3) create the key handle (from key and hash of ABE ciphertext) + keyHandle.reset(new OpenABESymKeyHandleImpl(symkeyBytes, ctHash)); // no b64 encoding by default + } catch (OpenABE_ERROR &error) { + cerr << "CCAWithATZN::decrypt: " << OpenABE_errorToString(error) << endl; + } catch (oabe::CryptoException& ex) { + cerr << "CCAWithATZN::decrypt(CryptoException): " << ex.what() << endl; + } + + symkey->zeroize(); + symkeyBytes.zeroize(); + return keyHandle; +} + + +} diff --git a/src/abe/zcontextcpwaters.cpp b/src/abe/zcontextcpwaters.cpp new file mode 100644 index 00000000..77cac4f8 --- /dev/null +++ b/src/abe/zcontextcpwaters.cpp @@ -0,0 +1,396 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextcpwaters.cpp +/// +/// \brief Implementation of the Waters '11 CP-ABE scheme. +/// +/// \source http://eprint.iacr.org/2008/290.pdf (Appendix A -- Large Universe Construction) +/// +/// \author J. Ayo Akinyele +/// + +#define __ZCONTEXTCPWATERS_CPP__ + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEContextCPWaters class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEContextCPWaters class. + * + */ +OpenABEContextCPWaters::OpenABEContextCPWaters(unique_ptr rng) + : OpenABEContextABE() { + this->debug = false; + // KEM context will take ownership of the given RNG + this->m_RNG_ = move(rng); + this->algID = OpenABE_SCHEME_CP_WATERS; +} + +/*! + * Destructor for the OpenABEContextCPWaters class. + * + */ +OpenABEContextCPWaters::~OpenABEContextCPWaters() {} + +/*! + * Generate scheme public and private parameters for the Waters '11 CP-ABE + * scheme. This function takes in a specific set of pairing parameters. + * + * @param[in] pairingParams - Identifier for the pairing parameters. + * @param[in] mpkID - Identifier to use for the new Master Public Key + * @param[in] mskID - Identifier to use for the new Master Secret Key + * @return - An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextCPWaters::generateParams(const string pairingParams, + const string &mpkID, const string &mskID) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr MPK = nullptr, MSK = nullptr; + OpenABERNG *myRNG = this->getRNG(); + OpenABEByteString k; + + try { + // Instantiate a OpenABE pairing object with the given parameters + this->initializeCurve(pairingParams); + + // Make sure these parameter IDs are valid and not already in use + if (this->getKeystore()->validateNewParamsID(mpkID) == false || + this->getKeystore()->validateNewParamsID(mskID) == false) { + throw OpenABE_ERROR_INVALID_PARAMS_ID; + } + + // Initialize the elements of the public and secret parameters + MPK.reset(new OpenABEKey(this->getPairing()->getCurveID(), this->algID, mpkID)); + MSK.reset(new OpenABEKey(this->getPairing()->getCurveID(), this->algID, mskID)); + + // Select random generators g1 \in G1, g2 \in G2 + G1 g1 = this->getPairing()->randomG1(myRNG); + G2 g2 = this->getPairing()->randomG2(myRNG); + // Select two random elements (a, \alpha) \in ZP + ZP alpha = this->getPairing()->randomZP(myRNG); + ZP a = this->getPairing()->randomZP(myRNG); + // key prefix for hash function + myRNG->getRandomBytes(&k, HASH_LEN); + + // Compute g1^a, g2^a + G1 g1a = g1.exp(a); + G2 g2a = g2.exp(a); + + // Compute A = e(g1, g2)^\alpha + GT A = this->getPairing()->pairing(g1, g2).exp(alpha); + + // Add (g1, g2, g1a) to the public params + MPK->setComponent("g1", &g1); + MPK->setComponent("g2", &g2); + MPK->setComponent("g1a", &g1a); + MPK->setComponent("A", &A); + MPK->setComponent("k", &k); + + // Add (\alpha and g2a) to the secret params + MSK->setComponent("alpha", &alpha); + MSK->setComponent("g2a", &g2a); + + // Add (MPK, MSK) to the keystore + this->getKeystore()->addKey(mpkID, MPK, KEY_TYPE_PUBLIC); + this->getKeystore()->addKey(mskID, MSK, KEY_TYPE_SECRET); + + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + + +/*! + * Generate a decryption key for a given function input. This function + * requires that the master secret parameters are available. + * + * @param[in] mpkID - parameter ID of the Master Public Key + * @param[in] mskID - parameter ID of the Master Secret Key + * @param[in] keyID - parameter ID of the decryption key to be created + * @param[in] keyInput - A OpenABEAttributeList structure for the key to be constructed + * @return - An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextCPWaters::generateDecryptionKey( + OpenABEFunctionInput *keyInput, const string &keyID, const string &mpkID, + const string &mskID, const string &gpkID = "", const string &GID = "") { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr decKey = nullptr; + OpenABEAttributeList *attrList = nullptr; + OpenABERNG *myRNG = this->getRNG(); + OpenABEByteString *k = nullptr; + + try { + // Ensure that the given input is a OpenABEAttributeList + if ((attrList = dynamic_cast(keyInput)) == nullptr) { + OpenABE_LOG_AND_THROW("Decryption key input must be an Attribute List", + OpenABE_ERROR_INVALID_INPUT); + } + + // Load the master secret and public key + shared_ptr MPK = this->getKeystore()->getPublicKey(mpkID); + shared_ptr MSK = this->getKeystore()->getSecretKey(mskID); + if (MPK == nullptr || MSK == nullptr) { + throw OpenABE_ERROR_INVALID_PARAMS; + } + // retrieve the hash function key prefix + k = MPK->getByteString("k"); + // Create a new OpenABEKey object for the decryption key + decKey.reset( + new OpenABEKey(this->getPairing()->getCurveID(), this->algID, keyID)); + + // Add the attribute list to the key + decKey->setComponent("input", attrList); + + // Select a random element t \in ZP + ZP t = this->getPairing()->randomZP(myRNG); + ZP alpha = *(MSK->getZP("alpha")); + + // K = g2^\alpha * (g2^{a})^t + G2 K = (MPK->getG2("g2")->exp(alpha)) * (MSK->getG2("g2a")->exp(t)); + decKey->setComponent("K", &K); + + // L = g2^t + G2 L = MPK->getG2("g2")->exp(t); + decKey->setComponent("L", &L); + + // For each attribute in the attribute list + string attr, attr_deckey; + const vector *attrStrings = attrList->getAttributeList(); + for (auto it = attrStrings->begin(); it != attrStrings->end(); ++it) { + // Compute KX_{attribute} = hash_to_G1(attribute)^t + attr = *it; + G1 kx = this->getPairing()->hashToG1(*k, attr).exp(t); + attr_deckey = OpenABEHashKey(attr); + decKey->setComponent(OpenABEMakeElementLabel("KX", attr_deckey), &kx); + } + + // Add the decryption key to the keystore + this->getKeystore()->addKey(keyID, decKey, KEY_TYPE_SECRET); + + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +/*! + * Generate and encrypt a symmetric key using the key encapsulation mode + * of the scheme. Return the key and ciphertext. + * + * @param Parameters ID for the public master parameters. + * @param Function input for the encryption. + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextCPWaters::encryptKEM(OpenABERNG *rng, const string &mpkID, + const OpenABEFunctionInput *encryptInput, + uint32_t keyByteLen, + const std::shared_ptr &key, + OpenABECiphertext *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABERNG *myRNG = this->getRNG(); + OpenABEByteString *k = nullptr; + + try { + ASSERT_NOTNULL(key); + ASSERT_NOTNULL(ciphertext); + + if (rng != nullptr) { + // use the passed in RNG + myRNG = rng; + } + // Assert that the RNG has been set + ASSERT_NOTNULL(myRNG); + + // Ensure that the given input is a OpenABEPolicy + const OpenABEPolicy *policy = dynamic_cast(encryptInput); + if (policy == nullptr) { + OpenABE_LOG_AND_THROW("Encryption input must be a Policy", + OpenABE_ERROR_INVALID_INPUT); + } + // Load the master public key + shared_ptr MPK = this->getKeystore()->getPublicKey(mpkID); + if (MPK == nullptr) { + throw OpenABE_ERROR_INVALID_PARAMS; + } + // retrieve the hash function key prefix + k = MPK->getByteString("k"); + + // Select s and compute C = e(g1, g2)^\(alpha*s) + ZP s = this->getPairing()->randomZP(myRNG); + GT C = MPK->getGT("A")->exp(s); + + // Use the Linear Secret Sharing Scheme (LSSS) to compute an enumerated list + // of all + // attributes and corresponding secret shares of s. + OpenABELSSS lsss(this->getPairing(), myRNG); + lsss.shareSecret(policy, s); + + // Allocate the ciphertext object and add the policy and key length + OpenABEByteString pol; + pol = policy->toCompactString(); + ciphertext->setComponent("policy", &pol); + + // Compute Cprime = g1^s + G1 Cprime = MPK->getG1("g1")->exp(s); + ciphertext->setComponent("Cprime", &Cprime); + + // For each element of the LSSS + ZP ri; + string attr_key; + OpenABELSSSRowMap lsssRows = lsss.getRows(); + for (auto it = lsssRows.begin(); it != lsssRows.end(); ++it) { + // Pick a random value ri. + ri = this->getPairing()->randomZP(myRNG); + // Compute D[i] = g2^{ri} + G2 Di = (MPK->getG2("g2")->exp(ri)); + attr_key = OpenABEHashKey(it->first); + ciphertext->setComponent(OpenABEMakeElementLabel("D", attr_key), &Di); + + // Compute C[i] = g1a^{share_i} * hash_to_G1(attribute)^{-r} + G1 hG1 = this->getPairing()->hashToG1(*k, it->second.label()); + G1 Ci = MPK->getG1("g1a")->exp(it->second.element()) * (hG1.exp(-ri)); + ciphertext->setComponent(OpenABEMakeElementLabel("C", attr_key), &Ci); + } + + // Hash C to obtain the symmetric key result. + key->hashToSymmetricKey(C, keyByteLen, HASH_FUNCTION_TYPE_SHA256); + ciphertext->setHeader(this->getPairing()->getCurveID(), this->algID, myRNG); + + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +/*! + * Decrypt a symmetric key using the key encapsulation mode + * of the scheme. Return the key. + * + * @param Parameters ID for the public master parameters. + * @param Identifier for the decryption key to be used. + * @param ABE ciphertext. + * @param Symmetric key to be returned. + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextCPWaters::decryptKEM(const string &mpkID, const string &keyID, + OpenABECiphertext *ciphertext, uint32_t keyByteLen, + const std::shared_ptr &key) { + OpenABE_ERROR result = OpenABE_NOERROR; + ZP coeff; + G1 prod1 = this->getPairing()->initG1(); + G1 *Kx, *Cx; + G2 *Dx; + GT prodT = this->getPairing()->initGT(); + + try { + ASSERT_NOTNULL(ciphertext); + ASSERT_NOTNULL(key); + // Load the given decryption key + shared_ptr decKey = this->getKeystore()->getSecretKey(keyID); + ASSERT_NOTNULL(decKey); + // Obtain the attribute list from the decryption key + OpenABEAttributeList *attrList = + (OpenABEAttributeList *)decKey->getComponent("input"); + + // Initialize an LSSS structure. Given an attribute list and policy + // it will identify the necessary solution and return the appropriate + // components of the access/policy and secret key along with coefficients. + // If the policy is not satisfied, it throws an error. + OpenABELSSS lsss(this->getPairing(), this->getRNG()); + + OpenABEByteString *policy_str = ciphertext->getByteString("policy"); + ASSERT_NOTNULL(policy_str); + + unique_ptr policy = createPolicyTree(policy_str->toString()); + lsss.recoverCoefficients(policy.get(), attrList); + + // Compute prod1 = prod_{attr_i \in S} C[attr_i]^{coefficient[attr_i]} + // prodT = prod_{attr_i \in S} e(KX[attr_i]^{coefficient[attr_i]}, + // D[attr_i]) + vector g1s; + vector g2s; + string attr_key, attr_deckey; + OpenABELSSSRowMap lsssRows = lsss.getRows(); + for (auto it = lsssRows.begin(); it != lsssRows.end(); ++it) { + coeff = it->second.element(); + attr_key = OpenABEHashKey(it->first); + attr_deckey = OpenABEHashKey(it->second.label()); + Kx = decKey->getG1(OpenABEMakeElementLabel("KX", attr_deckey)); + Cx = ciphertext->getG1(OpenABEMakeElementLabel("C", attr_key)); + ASSERT_NOTNULL(Cx); + Dx = ciphertext->getG2(OpenABEMakeElementLabel("D", attr_key)); + ASSERT_NOTNULL(Dx); + prod1 *= (Cx->exp(coeff)); + // G1 Kxpr = Kx->exp(coeff); + // prodT *= this->getPairing()->pairing(Kxpr, *Dx); + g1s.push_back(Kx->exp(coeff)); + g2s.push_back(*Dx); + } + + this->getPairing()->multi_pairing(prodT, g1s, g2s); + G1 *Cprime = ciphertext->getG1("Cprime"); + G2 *K = decKey->getG2("K"); + G2 *L = decKey->getG2("L"); + ASSERT_NOTNULL(Cprime); + ASSERT_NOTNULL(K); + ASSERT_NOTNULL(L); + // Now compute final = e(Cprime, K) / (prodT * e(prod1, L)) + GT final = this->getPairing()->pairing(*Cprime, *K) / + (prodT * this->getPairing()->pairing(prod1, *L)); + // Compute key = hash_to_bitstring( prodT ); + key->hashToSymmetricKey(final, keyByteLen, HASH_FUNCTION_TYPE_SHA256); + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +} diff --git a/src/abe/zcontextkpgpsw.cpp b/src/abe/zcontextkpgpsw.cpp new file mode 100644 index 00000000..ef380c38 --- /dev/null +++ b/src/abe/zcontextkpgpsw.cpp @@ -0,0 +1,369 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextkpgpsw.cpp +/// +/// \brief Implementation of the KP-ABE [GPSW '06] scheme. +/// +/// \source [GPSW 06, Sec 5] and [PTMW 06, Sec 2.2 + Appendix B] +/// +/// \author J. Ayo Akinyele +/// + +#define __ZCONTEXTKPGPSW_CPP__ + +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEContextKPGPSW class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEContextKPGPSW class. + * + */ + +OpenABEContextKPGPSW::OpenABEContextKPGPSW(unique_ptr rng) : OpenABEContextABE() { + this->debug = false; + this->m_RNG_ = move(rng); + this->algID = OpenABE_SCHEME_KP_GPSW; +} + +/*! + * Destructor for the OpenABEContextKPGPSW class. + * + */ + +OpenABEContextKPGPSW::~OpenABEContextKPGPSW() {} + +/*! + * Generate scheme public and private parameters for the Waters '11 CP-ABE + * scheme. This function takes in a specific set of pairing parameters. + * + * @param[in] pairingParams - Identifier for the pairing parameters. + * @param[in] mpkID - Identifier to use for the new Master Public Key + * @param[in] mskID - Identifier to use for the new Master Secret Key + * @return - An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextKPGPSW::generateParams(const string pairingParams, + const string &mpkID, const string &mskID) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr MPK = nullptr, MSK = nullptr; + OpenABERNG *myRNG = this->getRNG(); + OpenABEByteString k; + + try { + // Instantiate a OpenABE pairing object with the given parameters + this->initializeCurve(pairingParams); + + // Make sure these parameter IDs are valid and not already in use + if (this->getKeystore()->validateNewParamsID(mpkID) == false || + this->getKeystore()->validateNewParamsID(mskID) == false) { + throw OpenABE_ERROR_INVALID_PARAMS_ID; + } + + // Initialize the elements of the public and secret parameters + MPK.reset(new OpenABEKey(this->getPairing()->getCurveID(), this->algID, mpkID)); + MSK.reset(new OpenABEKey(this->getPairing()->getCurveID(), this->algID, mskID)); + + // Select random generators g1 \in G1 and g2 \in G2 + G1 g1 = this->getPairing()->randomG1(myRNG); + G2 g2 = this->getPairing()->randomG2(myRNG); + // Select random y \in ZP + ZP y = this->getPairing()->randomZP(myRNG); + // Compute e(g,g2) ==> e(g1,g2)^y + GT Y = this->getPairing()->pairing(g1, g2).exp(y); + // key prefix for hash function + myRNG->getRandomBytes(&k, HASH_LEN); + + // MPK = {g1, g2, Y = e(g1, g2)^y, k} + MPK->setComponent("g1", &g1); + MPK->setComponent("g2", &g2); + MPK->setComponent("Y", &Y); + MPK->setComponent("k", &k); + // MSK = {y} + MSK->setComponent("y", &y); + + // Add (MPK, MSK) to the keystore + this->getKeystore()->addKey(mpkID, MPK, KEY_TYPE_PUBLIC); + this->getKeystore()->addKey(mskID, MSK, KEY_TYPE_SECRET); + + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + + +/*! + * Generate a decryption key for a given function input. This function + * requires that the master secret parameters are available. + * + * @param[in] mpkID - parameter ID of the Master Public Key + * @param[in] mskID - parameter ID of the Master Secret Key + * @param[in] keyID - parameter ID of the decryption key to be created + * @param[in] keyInput - A OpenABEPolicy structure for the key to be constructed + * @return - An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextKPGPSW::generateDecryptionKey( + OpenABEFunctionInput *keyInput, const string &keyID, const string &mpkID, + const string &mskID, const string &gpkID = "", const string &GID = "") { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr decKey = nullptr; + OpenABEPolicy *policy = nullptr; + OpenABERNG *myRNG = this->getRNG(); + OpenABEByteString *k = nullptr; + + try { + // Ensure that the given input is a OpenABEPolicy + if ((policy = dynamic_cast(keyInput)) == nullptr) { + OpenABE_LOG_AND_THROW("Encryption input must be a Policy", + OpenABE_ERROR_INVALID_INPUT); + } + + // Load the master secret and public key + shared_ptr MPK = this->getKeystore()->getPublicKey(mpkID); + shared_ptr MSK = this->getKeystore()->getSecretKey(mskID); + if (MPK == nullptr || MSK == nullptr) { + throw OpenABE_ERROR_INVALID_PARAMS; + } + // retrieve the hash function key prefix + k = MPK->getByteString("k"); + + // Create a new OpenABEKey object for the decryption key + decKey.reset( + new OpenABEKey(this->getPairing()->getCurveID(), this->algID, keyID)); + + // Store the policy in the decryption key + OpenABEByteString pol; + pol = policy->toCompactString(); + decKey->setComponent("input", &pol); + ZP y = *(MSK->getZP("y")); + + OpenABELSSS lsss(this->getPairing(), myRNG); + // Share the secret y over the policy tree + lsss.shareSecret(policy, y); + + // For each element/share of the policy tree + string attr_deckey; + OpenABELSSSRowMap lsssRows = lsss.getRows(); + for (auto it = lsssRows.begin(); it != lsssRows.end(); ++it) { + // Pick a random value ri in ZP + ZP ri = this->getPairing()->randomZP(myRNG); + // Di = g ^ \share(attr) * H(attr)^ri + G1 Di = MPK->getG1("g1")->exp(it->second.element()) * + this->getPairing()->hashToG1(*k, it->second.label()).exp(ri); + // di = g ^ ri + G2 di = MPK->getG2("g2")->exp(ri); + attr_deckey = OpenABEHashKey(it->first); + decKey->setComponent(OpenABEMakeElementLabel("D", attr_deckey), &Di); + decKey->setComponent(OpenABEMakeElementLabel("d", attr_deckey), &di); + } + + // Add the decryption key to the keystore + this->getKeystore()->addKey(keyID, decKey, KEY_TYPE_SECRET); + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +/*! + * Generate and encrypt a symmetric key using the key encapsulation mode + * of the scheme. Return the key and ciphertext. + * + * @param Parameters ID for the public master parameters. + * @param Function input for the encryption: OpenABEAttributeList + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextKPGPSW::encryptKEM(OpenABERNG *rng, const string &mpkID, + const OpenABEFunctionInput *encryptInput, + uint32_t keyByteLen, + const std::shared_ptr &key, + OpenABECiphertext *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABERNG *myRNG = this->getRNG(); + shared_ptr MPK = nullptr; + OpenABEByteString *k = nullptr; + + try { + ASSERT_NOTNULL(key); + ASSERT_NOTNULL(ciphertext); + if (rng != nullptr) { + // Use the provided RNG + myRNG = rng; + } + // Assert that the RNG has been set + ASSERT_NOTNULL(myRNG); + + // Ensure that the given input is a OpenABEAttributeList + const OpenABEAttributeList *attrList = + dynamic_cast(encryptInput); + if (attrList == nullptr) { + OpenABE_LOG_AND_THROW("Encryption input must be a Policy", + OpenABE_ERROR_INVALID_INPUT); + } + // Load the master public key + if ((MPK = this->getKeystore()->getPublicKey(mpkID)) == nullptr) { + OpenABE_LOG_AND_THROW("Could not get master public params", + OpenABE_ERROR_INVALID_PARAMS); + } + // Retrieve the hash function key prefix + k = MPK->getByteString("k"); + // Choose random t \in ZP + ZP t = this->getPairing()->randomZP(myRNG); + // Compute Y^t => e(g1, g2)^(y*t). Note: this is hashed into a key later due + // to KEM + GT Cpr1 = MPK->getGT("Y")->exp(t); + // Compute g2 ^ t + G2 Cpr2 = MPK->getG2("g2")->exp(t); + ciphertext->setComponent("Cpr2", &Cpr2); + + string attr, attr_key; + const vector *attrStrings = attrList->getAttributeList(); + for (auto it = attrStrings->begin(); it != attrStrings->end(); ++it) { + // For each attribute in input, compute H(attribute) ^ t + attr = *it; + G1 hG1 = this->getPairing()->hashToG1(*k, attr).exp(t); + attr_key = OpenABEHashKey(attr); + ciphertext->setComponent(OpenABEMakeElementLabel("C", attr_key), &hG1); + } + // Set the attribute list in the policy + ciphertext->setComponent("attributes", attrList); + + // Hash Cpr1 to obtain the encapsulation key. + key->hashToSymmetricKey(Cpr1, keyByteLen, HASH_FUNCTION_TYPE_SHA256); + // Set the ciphertext header + ciphertext->setHeader(this->getPairing()->getCurveID(), this->algID, myRNG); + + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +/*! + * Decrypt a symmetric key using the key encapsulation mode + * of the scheme. Return the key. + * + * @param Parameters ID for the public master parameters. + * @param Identifier for the decryption key to be used. + * @param ABE ciphertext. + * @param Symmetric key to be returned. + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextKPGPSW::decryptKEM(const string &mpkID, const string &keyID, + OpenABECiphertext *ciphertext, uint32_t keyByteLen, + const std::shared_ptr &key) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABERNG *myRNG = this->getRNG(); + + try { + ASSERT_NOTNULL(ciphertext); + ASSERT_NOTNULL(key); + // Load the given decryption key + shared_ptr decKey = this->getKeystore()->getSecretKey(keyID); + ASSERT_NOTNULL(decKey); + + // Obtain the attribute list from the decryption key + OpenABEByteString *policy_str = decKey->getByteString("input"); + ASSERT_NOTNULL(policy_str); + unique_ptr policy = createPolicyTree(policy_str->toString()); + + // Obtain the attribute list from the decryption key + OpenABEAttributeList *attrList = + (OpenABEAttributeList *)ciphertext->getComponent("attributes"); + ASSERT_NOTNULL(attrList); + + // Initialize an LSSS structure. Given an attribute list and policy + // it will identify the necessary solution and return the appropriate + // components of the access/policy and secret key along with coefficients. + // If the policy is not satisfied, it throws an error. + OpenABELSSS lsss(this->getPairing(), myRNG); + lsss.recoverCoefficients(policy.get(), attrList); + + ZP coeff; + G1 prod1 = this->getPairing()->initG1(); + G1 *Ci, *Di; + G2 *di; + GT prodT = this->getPairing()->initGT(); + vector g1s; + vector g2s; + // Get coefficients for satisfiable attributes + OpenABELSSSRowMap lsssRows = lsss.getRows(); + string attr_key, attr_deckey; + for (auto it = lsssRows.begin(); it != lsssRows.end(); ++it) { + coeff = it->second.element(); + attr_key = OpenABEHashKey(it->second.label()); + Ci = ciphertext->getG1(OpenABEMakeElementLabel("C", attr_key)); + attr_deckey = OpenABEHashKey(it->first); + + di = decKey->getG2(OpenABEMakeElementLabel("d", attr_deckey)); + // prod1 => prod{i \in S} D_i ^ coeff_i + Di = decKey->getG1(OpenABEMakeElementLabel("D", attr_deckey)); + prod1 *= Di->exp(coeff); + // prodT => prod{i \in S} e(d_i, C_i) + g1s.push_back(Ci->exp(coeff)); + g2s.push_back(*di); + } + // prodT => prod{i \in S} e(d_i, C_i) + this->getPairing()->multi_pairing(prodT, g1s, g2s); + G2 *Cpr2 = ciphertext->getG2("Cpr2"); + ASSERT_NOTNULL(Cpr2); + GT A = this->getPairing()->pairing(prod1, *Cpr2) / prodT; + + // Compute key = hash_to_bitstring( A ); + key->hashToSymmetricKey(A, keyByteLen, HASH_FUNCTION_TYPE_SHA256); + + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +} diff --git a/src/bench_libopenabe.cpp b/src/bench_libopenabe.cpp new file mode 100644 index 00000000..c46e6812 --- /dev/null +++ b/src/bench_libopenabe.cpp @@ -0,0 +1,576 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file bench_libopenabe.cpp +/// +/// \brief Benchmarking utility for the OpenABE +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include + +#include +#include +#if defined(USE_BOOST) +#define BOOST_SPIRIT_THREADSAFE +#include +#include +#endif + +using namespace std; +using namespace oabe; + +#define DEFAULT_SECURITY_LEVEL 128 +#define FIXED_CMD "fixed" +#define RANGE_CMD "range" + +#define CPABE "CP" +#define KPABE "KP" + +#define CPA "cpa" +#define CCA "cca" +#define EXIT(msg) cout << msg << endl; goto CLEANUP + +const string mapToJsonString(map& data) { + stringstream ss; + int data_size = data.size(); + bool has_one = (data_size > 0) ? true : false; + string data_json = ""; + +#if defined(USE_BOOST) + boost::property_tree::ptree pt; + + for(auto& d : data) { + // keep this simple... + pt.put(d.first, d.second); + } + boost::property_tree::json_parser::write_json(ss, pt); +#else + int c = 0; + ss << "{" << endl; + for (auto& d : data) { + c++; + ss << "\t\"" << d.first << "\": \"" << d.second << "\""; + if (c < data_size) { ss << ","; } + ss << endl; + } + ss << "}" << endl; +#endif + if (has_one) + data_json = ss.str(); + return data_json; +} + + +bool isEqual(string value1, string value2) +{ + string s1 = value1; + string s2 = value2; + if (strcmp(s1.c_str(), s2.c_str()) == 0) + return true; + else + return false; +} + +string createAttribute(const string& prefix, int i) +{ + stringstream ss; + if (prefix == "") + ss << "Attr" << i; + else + ss << prefix << ":Attr" << i; + return ss.str(); +} + +bool getAttributes(const string& prefix, int max, vector & attrList) +{ + if(max < 0) { return false; } + + for(int i = 0; i < max; i++) { + attrList.push_back(createAttribute(prefix, i)); + } + return true; +} + +// returns an evenly distributed / balanced policy tree +string getBalancedOpenABETree(const string& prefix, int start, int end) { + if(start == end) { return createAttribute(prefix, start); } + int mid = ceil((start + (end - start) / 2.0)); + if(mid == 0) { + return "(" + createAttribute(prefix, start) + " and " + createAttribute(prefix, end) + ")"; + } + else { + return "(" + getBalancedOpenABETree(prefix, start, mid-1) + " and " + getBalancedOpenABETree(prefix, mid, end) + ")"; + } +} + +//string getPolicyString(int max) +//{ +// return getBalancedOpenABETree(0, max-1); +//} + +string getPolicyString(const string& prefix, int max) +{ + string policystr; + if(max >= 2) { + policystr = "(" + createAttribute(prefix, 0) + " and " + createAttribute(prefix, 1) + ")"; + } + else if(max == 1) { + policystr = createAttribute(prefix, 0); + } + + for(int i = 2; i < max; i++) + { + policystr = "(" + policystr + " and " + createAttribute(prefix, i) + ")"; + } + + return policystr; +} + +string getSchemeString(OpenABE_SCHEME scheme_type) +{ + if(scheme_type == OpenABE_SCHEME_CP_WATERS) + return "CP-ABE"; + else if(scheme_type == OpenABE_SCHEME_KP_GPSW) + return "KP-ABE"; + else + throw runtime_error("Invalid scheme type"); +} + +/////////////////////////////////////////////////////////////////////////////////// +/// Benchmark routines for CP-ABE Waters '11 and KP-ABE GPSW /// +/////////////////////////////////////////////////////////////////////////////////// + +void benchmarkABE_CPA_KEM(map& data, OpenABE_SCHEME scheme_type, ofstream & outfile0, + ofstream & outfile1, ofstream & outfile2, int attributeCount, + int iterationCount, ListStr & encryptResults, ListStr & keygenResults, + ListStr & decryptResults, bool verbose) +{ + data["scheme"] = getSchemeString(scheme_type); + data["security"] = "CPA_KEM"; + Benchmark benchE, benchD, benchK; + OpenABE_ERROR res; + double en_in_ms, de_in_ms, kg_in_ms; + stringstream s0, s1, s2; + string mpk, msk, auth1mpk, auth1msk, decKey = "decKey", decKeyBench = "decKeyBench"; + std::unique_ptr keyFuncInput = nullptr, encFuncInput = nullptr; + shared_ptr symkey = nullptr, newkey = nullptr; + unique_ptr ciphertext = nullptr; + unique_ptr context = nullptr; + unique_ptr rng(new OpenABERNG); + string prefix = ""; + + // get the attribute list + vector S; + getAttributes(prefix, attributeCount, S); + // Initialize a OpenABEContext structure + context.reset(OpenABE_createContextABE(&rng, scheme_type)); + if (context == nullptr) { + EXIT("Unable to create a new context"); + } + + if(scheme_type == OpenABE_SCHEME_CP_WATERS || scheme_type == OpenABE_SCHEME_KP_GPSW) { + mpk = "MPK"; + msk = "MSK"; + // Generate a set of parameters for an ABE authority + if (context->generateParams(DEFAULT_BP_PARAM, mpk, msk) != OpenABE_NOERROR) { + EXIT("Unable to generate params"); + } + } else { + EXIT("ERROR: not one of the supported scheme types"); + } + + // get attributes from + if(scheme_type == OpenABE_SCHEME_CP_WATERS) { + // attributes are embedded in the key + keyFuncInput.reset(new OpenABEAttributeList(S.size(), S)); + cout << "<== ATTRIBUTES ==>" << keyFuncInput->toString() << "<== ATTRIBUTES ==>\n"; // DEBUG + + // policy is embedded in the ciphertext + string policy_str = getPolicyString(prefix, attributeCount); + encFuncInput = std::unique_ptr(createPolicyTree(policy_str)); + //cout << "<=== FUNC INPUT ===>\n" << policy_str << "<=== FUNC INPUT ===>\n"; + } + else if(scheme_type == OpenABE_SCHEME_KP_GPSW) { + // policy is embedded in the key + string policy_str = getPolicyString(prefix, attributeCount); + keyFuncInput = std::unique_ptr(createPolicyTree(policy_str)); + + // attributes are embedded in the ciphertext + encFuncInput.reset(new OpenABEAttributeList(S.size(), S)); + cout << "<== ATTRIBUTES ==>" << encFuncInput->toString() << "<== ATTRIBUTES ==>\n"; // DEBUG + } + + // generate key used for decryption + res = context->generateDecryptionKey(keyFuncInput.get(), decKey, mpk, msk); + + // benchmarking key generation + cout << "Testing with " << S.size() << " attributes" << endl; + for(int i = 0; i < iterationCount; i++) { + benchK.start(); + res = context->generateDecryptionKey(keyFuncInput.get(), decKeyBench, mpk, msk); + benchK.stop(); + kg_in_ms = benchK.computeTimeInMilliseconds(); + if(res != OpenABE_NOERROR) { cout << "Fail: " << OpenABE_errorToString(res) << ", time: " << kg_in_ms << " ms" << endl; EXIT("failed to generate key"); } + context->getKeystore()->deleteKey(decKeyBench); + } + cout << "Keygen avg: " << benchK.getAverage() << " ms" << endl; + data["keygen"] = std::to_string(benchK.getAverage()); + s1 << attributeCount << " " << benchK.getAverage() << endl; + outfile1 << s1.str(); + keygenResults[attributeCount] = benchK.getRawResultString(); + + // benchmarking encryption + for(int i = 0; i < iterationCount; i++) { + symkey.reset(new OpenABESymKey); + ciphertext.reset(new OpenABECiphertext); + benchE.start(); + res = context->encryptKEM(nullptr, mpk, encFuncInput.get(), DEFAULT_SYM_KEY_BYTES, symkey, ciphertext.get()); + benchE.stop(); + en_in_ms = benchE.computeTimeInMilliseconds(); + if(res != OpenABE_NOERROR) { cout << "Fail: " << OpenABE_errorToString(res) << ", time: " << en_in_ms << " ms" << endl; } + } + // get encryption measurements + cout << "Encrypt avg: " << benchE.getAverage() << " ms" << endl; + data["encrypt"] = std::to_string(benchE.getAverage()); + s0 << attributeCount << " " << benchE.getAverage() << endl; + outfile0 << s0.str(); + encryptResults[attributeCount] = benchE.getRawResultString(); + + // benchmarking decryption + for(int i = 0; i < iterationCount; i++) { + newkey.reset(new OpenABESymKey); + benchD.start(); + res = context->decryptKEM(mpk, decKey, ciphertext.get(), DEFAULT_SYM_KEY_BYTES, newkey); + benchD.stop(); + de_in_ms = benchD.computeTimeInMilliseconds(); + if(res != OpenABE_NOERROR) { cout << "Fail: " << OpenABE_errorToString(res) << ", time: " << de_in_ms << " ms" << endl; } + } + // get decryption measurements + cout << "Decrypt avg: " << benchD.getAverage() << " ms" << endl; + data["decrypt"] = std::to_string(benchD.getAverage()); + s2 << attributeCount << " " << benchD.getAverage() << endl; + outfile2 << s2.str(); + decryptResults[attributeCount] = benchD.getRawResultString(); + + if(CheckEqual(newkey->toString(), symkey->toString())) { + cout << "Succesful Decryption!\n"; + } + else { + cout << "FAILED DECRYPTION!!!\n"; + } +CLEANUP: + return; +} + +void benchmarkABE_CCA_KEM(map& data, OpenABE_SCHEME scheme_type, ofstream & outfile0, ofstream & outfile1, + ofstream & outfile2, int attributeCount, int iterationCount, ListStr & encryptResults, + ListStr & keygenResults, ListStr & decryptResults, bool verbose) +{ + data["scheme"] = getSchemeString(scheme_type); + data["security"] = "CCA_KEM"; + Benchmark benchE, benchD, benchK; + OpenABE_ERROR res; + double en_in_ms, de_in_ms, kg_in_ms; + stringstream s0, s1, s2; + string mpk, msk, auth1mpk, auth1msk, decKey = "decKey", decKeyBench = "decKeyBench"; + std::unique_ptr keyFuncInput = nullptr, encFuncInput = nullptr; + shared_ptr symkey = nullptr, newkey = nullptr; + unique_ptr ciphertext = nullptr; + unique_ptr ccaContext = nullptr; + unique_ptr schemeContext = nullptr; + unique_ptr rng(new OpenABERNG), rng2(new OpenABERNG); + string prefix = ""; + + // get the attribute list + vector S; + getAttributes(prefix, attributeCount, S); + + // initialize a scheme context with the KEM context + schemeContext = OpenABE_createContextABESchemeCPA(scheme_type); + if(!schemeContext) { + EXIT("Unable to create CPA scheme context"); + } + + // initialize a CCA scheme context + ccaContext.reset(new OpenABEContextGenericCCA(std::move(schemeContext))); + if(ccaContext == nullptr) { + EXIT("Unable to create a new CCA KEM context"); + } + + // generate the parameters for the given scheme_type + if(scheme_type == OpenABE_SCHEME_CP_WATERS || scheme_type == OpenABE_SCHEME_KP_GPSW) { + mpk = "MPK"; + msk = "MSK"; + // Generate a set of parameters for an ABE authority + if (ccaContext->generateParams(DEFAULT_BP_PARAM, mpk, msk) != OpenABE_NOERROR) { + EXIT("Unable to generate params"); + } + } else { + cout << "ERROR: not one of the supported scheme types" << endl; + return; + } + + // get attributes from + if(scheme_type == OpenABE_SCHEME_CP_WATERS) { + // attributes are embedded in the key + keyFuncInput.reset(new OpenABEAttributeList(S.size(), S)); + if (verbose) cout << "<== ATTRIBUTES ==>" << keyFuncInput->toString() << "<== ATTRIBUTES ==>\n"; + + // policy is embedded in the ciphertext + string policy_str = getPolicyString(prefix, attributeCount); + encFuncInput = std::unique_ptr(createPolicyTree(policy_str)); + } + else if(scheme_type == OpenABE_SCHEME_KP_GPSW) { + // policy is embedded in the key + string policy_str = getPolicyString(prefix, attributeCount); + keyFuncInput = std::unique_ptr(createPolicyTree(policy_str)); + + // attributes are embedded in the ciphertext + encFuncInput.reset(new OpenABEAttributeList(S.size(), S)); + if (verbose) cout << "<== ATTRIBUTES ==>" << encFuncInput->toString() << "<== ATTRIBUTES ==>\n"; + } + + // generate key used for decryption + res = ccaContext->generateDecryptionKey(keyFuncInput.get(), decKey, mpk, msk); + + // benchmarking key generation + if (verbose) cout << "Testing with " << S.size() << " attributes" << endl; + for(int i = 0; i < iterationCount; i++) { + benchK.start(); + res = ccaContext->generateDecryptionKey(keyFuncInput.get(), decKeyBench, mpk, msk); + benchK.stop(); + kg_in_ms = benchK.computeTimeInMilliseconds(); + if(res != OpenABE_NOERROR) { cout << "Fail: " << OpenABE_errorToString(res) << ", time: " << kg_in_ms << " ms" << endl; EXIT("failed to generate dec key"); } + ccaContext->deleteKey(decKeyBench); + } + if (verbose) cout << "Keygen avg: " << benchK.getAverage() << " ms" << endl; + data["keygen"] = std::to_string(benchK.getAverage()); + s1 << attributeCount << " " << benchK.getAverage() << endl; + outfile1 << s1.str(); + keygenResults[attributeCount] = benchK.getRawResultString(); + + // benchmarking encryption + for(int i = 0; i < iterationCount; i++) { + symkey.reset(new OpenABESymKey); + ciphertext.reset(new OpenABECiphertext); + benchE.start(); + res = ccaContext->encryptKEM(rng2.get(), mpk, encFuncInput.get(), DEFAULT_SYM_KEY_BYTES, symkey, ciphertext.get()); + benchE.stop(); + en_in_ms = benchE.computeTimeInMilliseconds(); + if(res != OpenABE_NOERROR) { cout << "Fail: " << OpenABE_errorToString(res) << ", time: " << en_in_ms << " ms" << endl; } + } + // get encryption measurements + if (verbose) cout << "Encrypt avg: " << benchE.getAverage() << " ms" << endl; + data["encrypt"] = std::to_string(benchE.getAverage()); + s0 << attributeCount << " " << benchE.getAverage() << endl; + outfile0 << s0.str(); + encryptResults[attributeCount] = benchE.getRawResultString(); + + // benchmarking decryption + for(int i = 0; i < iterationCount; i++) { + newkey.reset(new OpenABESymKey); + benchD.start(); + res = ccaContext->decryptKEM(mpk, decKey, ciphertext.get(), DEFAULT_SYM_KEY_BYTES, newkey); + benchD.stop(); + de_in_ms = benchD.computeTimeInMilliseconds(); + if(res != OpenABE_NOERROR) { cout << "Fail: " << OpenABE_errorToString(res) << ", time: " << de_in_ms << " ms" << endl; } + } + // get decryption measurements + if (verbose) cout << "Decrypt avg: " << benchD.getAverage() << " ms" << endl; + data["decrypt"] = std::to_string(benchD.getAverage()); + s2 << attributeCount << " " << benchD.getAverage() << endl; + outfile2 << s2.str(); + decryptResults[attributeCount] = benchD.getRawResultString(); + + if(CheckEqual(newkey->toString(), symkey->toString())) { + if (verbose) cout << "Succesful Decryption!\n"; + } + else { + cout << "FAILED DECRYPTION!!!\n"; + } + +CLEANUP: + return; +} + + +int runBenchmark(map& data, OpenABE_SCHEME scheme_type, string filename, int iterationCount, int attributeCount, string fixOrRange, + void (*benchmarkFunc)(map& data, OpenABE_SCHEME type, ofstream & outfile0, ofstream & outfile1, ofstream & outfile2, + int attributeCount, int iterationCount, ListStr & encryptResults, ListStr & keygenResults, ListStr & decryptResults, bool verbose)) +{ + stringstream s3, s4, s5; + ofstream outfile0, outfile1, outfile2, outfile3, outfile4, outfile5; + string f0 = filename + "_encrypt.dat"; + string f1 = filename + "_keygen.dat"; + string f2 = filename + "_decrypt.dat"; + string f3 = filename + "_keygen_raw.txt"; + string f4 = filename + "_decrypt_raw.txt"; + string f5 = filename + "_encrypt_raw.txt"; + outfile0.open(f0.c_str()); // enc + outfile1.open(f1.c_str()); + outfile2.open(f2.c_str()); + outfile3.open(f3.c_str()); + outfile4.open(f4.c_str()); + outfile5.open(f5.c_str()); // enc + + ListStr encryptResults, keygenResults, decryptResults; + cout << "Benchmarking " << getSchemeString(scheme_type) << " scheme" << endl; + if(fixOrRange.compare(RANGE_CMD) == 0) { + for(int i = 1; i < attributeCount; i++) { + cout << "Benchmark with " << i << " attributes." << endl; + benchmarkFunc(data, scheme_type, outfile0, outfile1, outfile2, + i, iterationCount, encryptResults, keygenResults, decryptResults, false); + } + cout << "Benchmark with " << attributeCount << " attributes." << endl; + benchmarkFunc(data, scheme_type, outfile0, outfile1, outfile2, + attributeCount, iterationCount, encryptResults, + keygenResults, decryptResults, true); + s3 << keygenResults << endl; + data["keygen"] = s3.str(); + s4 << decryptResults << endl; + data["decrypt"] = s4.str(); + s5 << encryptResults << endl; + data["encrypt"] = s5.str(); + } else if(fixOrRange.compare(FIXED_CMD) == 0) { + cout << "Benchmark with " << attributeCount << " attributes." << endl; + benchmarkFunc(data, scheme_type, outfile0, outfile1, outfile2, + attributeCount, iterationCount, encryptResults, keygenResults, decryptResults, true); + s3 << attributeCount << " " << keygenResults[attributeCount] << endl; + s4 << attributeCount << " " << decryptResults[attributeCount] << endl; + s5 << attributeCount << " " << encryptResults[attributeCount] << endl; + } else { + cout << "invalid option." << endl; + return -1; + } + + outfile3 << s3.str(); + outfile4 << s4.str(); + outfile5 << s5.str(); + outfile0.close(); + outfile1.close(); + outfile2.close(); + outfile3.close(); + outfile4.close(); + outfile5.close(); + return 0; +} + +int main(int argc, const char *argv[]) +{ + cout << "Math Library: " << DEFAULT_MATH_LIB << endl; + cout << "Curve Param ID: " << DEFAULT_BP_PARAM << endl; + if(argc < 7) { + cout << "OpenABE benchmark utility, v" << (OpenABE_LIBRARY_VERSION / 100.) << endl; + cout << "Usage " << argv[0] << ": [ scheme => 'CP', 'KP' or 'MA' ] [ iterations ] [ attributes ] [ 'fixed' or 'range' ] [ 'cpa' or 'cca'] [ filename.json ] [ optional: timestamp in secs ]" << endl; + cout << "\tscheme: the type of ABE scheme to benchmark" << endl; + cout << "\titerations: the number of iterations per test" << endl; + cout << "\tattributes: the number of attributes in the policy/attribute list for encryption" << endl; + cout << "\tfixed or range: run with a fixed number of attributes or as a range from 1 to num. attributes" << endl; + cout << "\tcpa or cca: chosen-plaintext secure vs chosen-ciphertext secure versions" << endl; + cout << "\tfilename.json: output file name for result summary in JSON format" << endl; + cout << "\ttimestamp: an optional timestamp (generated via 'date +%s' via cmd line) to group results based on scheme/security/attributes" << endl; + cout << "Benchmark Description: records the time to encrypt/decrypt a 256-bit symmetric key using the CPA-KEM or CCA-KEM constructions." << endl; + return -1; + } + + string filename = string(argv[0]); + string schemeType = argv[1]; + int iterationCount = atoi( argv[2] ); + int attributeCount = atoi( argv[3] ); + string fixOrRange = string( argv[4] ); + string secType = string( argv[5] ); + string output_file = string( argv[6] ); + string timestamp = ""; + if (argc == 8) { + timestamp = string( argv[7] ); + } else { + uint64_t tstamp = time(NULL); + timestamp = std::to_string(tstamp);; + } + + map data; + data["iterations"] = std::to_string(iterationCount); + data["attributes"] = std::to_string(attributeCount); + data["measurement"] = fixOrRange; + data["time"] = "ms"; + data["timestamp"] = timestamp; + cout << "iterations: " << iterationCount << endl; + cout << "attributes: " << attributeCount << endl; + cout << "msmt type: " << fixOrRange << endl; + + InitializeOpenABE(); + + // get the scheme type + OpenABE_SCHEME scheme_type; + if(schemeType == CPABE) { + /* benchmark with CP-ABE func */ + scheme_type = OpenABE_SCHEME_CP_WATERS; + } + else if(schemeType == KPABE) { + /* benchmark with KP-ABE func */ + scheme_type = OpenABE_SCHEME_KP_GPSW; + } + else { + /* other scheme types */ + cout << "Invalid scheme type!" << endl; + return -1; + } + + + if(secType == CPA) { + // run all the CPA tests + cout << "Running the CPA tests" << endl; + runBenchmark(data, scheme_type, filename, iterationCount, attributeCount, fixOrRange, benchmarkABE_CPA_KEM); + } + else if(secType == CCA) { + // run all the CCA tests + cout << "Running the CCA tests" << endl; + runBenchmark(data, scheme_type, filename, iterationCount, attributeCount, fixOrRange, benchmarkABE_CCA_KEM); + } + else { + cout << "Invalid security type! Expected Argument: '" << CPA << "' or '" << CCA << "'" << endl; + return -1; + } + + ShutdownOpenABE(); + + string data_json = mapToJsonString(data); + ofstream outfile0; + outfile0.open(output_file.c_str()); + outfile0 << data_json; + outfile0.close(); + cout << "Writing " << data_json.size() << " bytes to " << output_file << "." << endl; + + return 0; +} + diff --git a/src/fuzz_attrlist.cpp b/src/fuzz_attrlist.cpp new file mode 100644 index 00000000..cc64566b --- /dev/null +++ b/src/fuzz_attrlist.cpp @@ -0,0 +1,98 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file fuzz_attrlist.cpp +/// +/// \brief This isolates attr list parsing for fuzzing +/// using afl-fuzz and such tools. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace oabe; + +void getFile(std::string &result, const std::string &filename) { + result.clear(); + + fstream fs(filename, fstream::in); + if (fs.fail()) { + string msg = "Could not open file "; + msg += filename; + throw ios_base::failure(msg); + } + + fs.exceptions(fstream::badbit); + while (!fs.eof()) { + char buf[512]; + fs.read(buf, sizeof(buf)); + result.append(buf, fs.gcount()); + } + + fs.close(); +} + +int main(int argc, char **argv) { + // check that we have appropriate # of args + if (argc < 2) { + cerr << "Usage " << argv[0] << ": [ input file ]" << endl; + return 1; + } + const string input_file(argv[1]); + int err_code = 1; + + try { + string attrlist_str; + getFile(attrlist_str, input_file); + vector attr_list_strings = oabe::split(attrlist_str, '\n'); + + for (auto p : attr_list_strings) { + cout << "Input: " << p << endl; + std::unique_ptr attrList = createAttributeList(p); + if(attrList != nullptr) { + cout << "AttrList Full: " << attrList->toString() << endl; + cout << "AttrList Compact: " << attrList->toCompactString() << endl; + } else { + cerr << "AttrList is NULL!" << endl; + } + cout << endl; + } + err_code = 0; + } catch (const std::ios_base::failure& e) { + // invalid input file specified + cerr << e.what() << endl; + } + + return err_code; +} diff --git a/src/fuzz_policy.cpp b/src/fuzz_policy.cpp new file mode 100644 index 00000000..9c690a70 --- /dev/null +++ b/src/fuzz_policy.cpp @@ -0,0 +1,133 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file fuzz_policy.cpp +/// +/// \brief This isolates policy parsing for fuzzing +/// using afl-fuzz and similar tools. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace oabe; + +void getFile(std::string &result, const std::string &filename) { + result.clear(); + + fstream fs(filename, fstream::in); + if (fs.fail()) { + string msg = "Could not open file "; + msg += filename; + throw ios_base::failure(msg); + } + + fs.exceptions(fstream::badbit); + while (!fs.eof()) { + char buf[512]; + fs.read(buf, sizeof(buf)); + result.append(buf, fs.gcount()); + } + + fs.close(); +} + +size_t getFileLen(const std::string &filename) { + FILE *f = fopen(filename.c_str(), "r"); + if (!f) { + string msg("Could not open file: "); + msg += filename; + throw ios_base::failure(msg); + } + if (fseek(f, 0, SEEK_END) != 0) { + throw ios_base::failure("fseek failed"); + } + ssize_t result = ftell(f); + if (result < 0) { + throw ios_base::failure("ftell failed"); + } + if ((uint64_t)result > SIZE_MAX) { + throw ios_base::failure("file is too large"); + } + return (size_t)result; +} + +void putFile(const std::string &contents, const std::string &filename) { + fstream fs(filename, fstream::out | fstream::trunc); + + if (fs.fail()) { + string msg("Could not open file "); + msg += filename; + throw ios_base::failure(msg); + } + fs.exceptions(fstream::badbit | fstream::failbit); + + fs << contents; + fs.close(); +} + + +int main(int argc, char **argv) { + // check that we have appropriate # of args + if (argc < 2) { + cerr << "Usage " << argv[0] << ": [ input file ]" << endl; + return 1; + } + const string input_file(argv[1]); + int err_code = 1; + + try { + string policy_str; + getFile(policy_str, input_file); + vector policy_strings = oabe::split(policy_str, '\n'); + + for (auto p : policy_strings) { + cout << "Input: " << p << endl; + std::unique_ptr policy = createPolicyTree(p); + if(policy != nullptr) { + cout << "Policy Full: " << policy->toString() << endl; + cout << "Policy Compact: " << policy->toCompactString() << endl; + } else { + cerr << "Policy is NULL!" << endl; + } + cout << endl; + } + err_code = 0; + } catch (const std::ios_base::failure& e) { + // invalid input file specified + cerr << e.what() << endl; + } + + return err_code; +} diff --git a/src/include/openabe/keys/zkdf.h b/src/include/openabe/keys/zkdf.h new file mode 100644 index 00000000..87291897 --- /dev/null +++ b/src/include/openabe/keys/zkdf.h @@ -0,0 +1,73 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zkdf.h +/// +/// \brief Key derivation function. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZKDF_H__ +#define __ZKDF_H__ + +#undef HMAC +#include +#include +#include + +/// +/// @class OpenABEKDF +/// +/// @brief Class for a Key Derivation Function +/// Approved Alternative 1: NIST SP 800-56A (Section 5.8.1) +/// +namespace oabe { + +class OpenABEKDF : public ZObject { +private: + uint8_t hashPrefix; + uint32_t hashLen; + uint32_t maxInputLen; + +public: + OpenABEKDF(uint8_t hashPrefix = KDF_HASH_FUNCTION_PREFIX, + uint32_t hashLen = SHA2_BITLEN, + uint32_t maxInputLen = OpenABE_MAX_KDF_BITLENGTH); + ~OpenABEKDF(); + + OpenABEByteString DeriveKey(OpenABEByteString &Z, uint32_t keyBitLen, OpenABEByteString &metadata); +}; + +/// +/// @brief OpenABEPBKDF wrapper for Password-based Key Derivation Function +/// (As described in RFC 2898) +OpenABEByteString OpenABEPBKDF(OpenABEByteString &password, uint32_t keydataLenBytes, + OpenABEByteString &salt, int iterationCount = OpenABE_KDF_ITERATION_COUNT); + +} + +#endif // __ZKDF_H__ diff --git a/src/include/openabe/keys/zkey.h b/src/include/openabe/keys/zkey.h new file mode 100644 index 00000000..0338eedd --- /dev/null +++ b/src/include/openabe/keys/zkey.h @@ -0,0 +1,94 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zkey.h +/// +/// \brief Abstract base class for key and parameter types. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZKEY_H__ +#define __ZKEY_H__ + +#include + +typedef enum OpenABEKeyType_ { + OpenABEKEY_NONE, + OpenABEKEY_SK_ENC, + OpenABEKEY_PK_ENC, + OpenABEKEY_CP_ENC, + OpenABEKEY_KP_ENC, + OpenABEKEY_MA_ENC, + OpenABEKEY_PK_SIG, +} OpenABEKeyType; + +/// \class OpenABEKey +/// \brief Abstract base class class for keys and parameters +namespace oabe { + +class OpenABEKey : public OpenABEContainer { +protected: + // 32-bytes for representing OpenABEKey Header information as follows: + // 1 bytes for the library version + uint8_t libraryVersion; + // 1 byte for the curve identifier + uint8_t curveID; + // 1 byte for algorithm/scheme ID + uint8_t algorithmID; + // 32 bytes for UID + OpenABEByteString uid; + // remaining bytes for string ID + std::string ID; + // the key type ID + OpenABEKeyType key_type; + // key is a public or private key + bool isPrivate; + +public: + OpenABEKey(); + OpenABEKey(const OpenABECurveID curveID, uint8_t algorithmID, const std::string ID, OpenABEByteString *uid = NULL); + ~OpenABEKey(); + + void setAsPrivate() { isPrivate = true; } + void getHeader(OpenABEByteString &header); + uint8_t getCurveID() { return this->curveID; } + uint8_t getAlgorithmID() { return this->algorithmID; } + uint8_t getLibID() { return this->libraryVersion; } + OpenABEByteString& getUID() { return this->uid; } + std::string getID() { return this->ID; } + OpenABEKeyType getKeyType() { return this->key_type; } + + virtual OpenABE_ERROR exportKeyToBytes(OpenABEByteString &output); + virtual OpenABE_ERROR loadKeyFromBytes(OpenABEByteString &input); + +}; + +OpenABEKeyType OpenABE_KeyTypeFromAlgorithmID(uint8_t algorithmID); +const std::string OpenABE_KeyTypeToString(OpenABEKeyType key_type); +} + +#endif // __ZKEY_H__ diff --git a/src/include/openabe/keys/zkeystore.h b/src/include/openabe/keys/zkeystore.h new file mode 100644 index 00000000..d35c219e --- /dev/null +++ b/src/include/openabe/keys/zkeystore.h @@ -0,0 +1,91 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zkeystore.h +/// +/// \brief Class definition for the OpenABE keystore. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZKEYSTORE_H__ +#define __ZKEYSTORE_H__ + +#include +#include + +namespace oabe { + +// Data structures + +typedef enum _zKeyType { + KEY_TYPE_PUBLIC, + KEY_TYPE_SECRET +} zKeyType; + +/// \class ZKeystore +/// \brief Keystore class for the OpenABE. Stores public and secret parameters +/// and keys, each indexed by a string identifier. +// +class OpenABEKeystore : public ZObject { +public: + OpenABEKeystore(); + ~OpenABEKeystore(); + + OpenABE_ERROR addKey(const std::string name, + const std::shared_ptr& component, + zKeyType keyType); + std::shared_ptr getPublicKey(const std::string keyID); + std::shared_ptr getSecretKey(const std::string keyID); + std::shared_ptr getKey(const std::string keyID); + + bool checkSecretKey(const std::string keyID); + OpenABE_ERROR deleteKey(const std::string keyID); + + bool validateNewParamsID(const std::string &keyID); + // search/extract key references +#if 0 + const std::vector getSecretKeyIDs() const; +#endif + // import/export routines + std::shared_ptr parseKeyHeader(const std::string keyID, + OpenABEByteString &keyBlob, + OpenABEByteString &outputKeyBytes); + std::shared_ptr constructKeyFromBytes(const std::string &keyID, + OpenABEByteString &keyBlob, + OpenABEByteString &keyBytes); + OpenABE_ERROR exportKeyToBytes(const std::string keyID, OpenABEByteString &exportedKey); + +protected: + std::map> pubKeys; + std::map> secKeys; +}; + +typedef std::pair KeyRef; + +} + +#endif // __ZKEYSTORE_H__ diff --git a/src/include/openabe/keys/zpkey.h b/src/include/openabe/keys/zpkey.h new file mode 100644 index 00000000..b528a667 --- /dev/null +++ b/src/include/openabe/keys/zpkey.h @@ -0,0 +1,64 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zpkey.h +/// +/// \brief Data structures for storing and manipulating ECDSA +/// signing and verification keys. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZPKEY_H__ +#define __ZPKEY_H__ + +#include +#include + +namespace oabe { + +class OpenABEPKey: public OpenABEKey { +private: + bool isPrivate; + EVP_PKEY *pkey; + bool bioToString(std::string& s, BIO* bio); + +public: + OpenABEPKey(bool isPrivate); + OpenABEPKey(const EC_KEY *ec_key, bool isPrivate, EC_GROUP *group = NULL); + ~OpenABEPKey(); + + EVP_PKEY *getPkey() { return this->pkey; } + + // pkeyToString (does export) + OpenABE_ERROR exportKeyToBytes(OpenABEByteString &output); + // stringToPkey (does import) + OpenABE_ERROR loadKeyFromBytes(OpenABEByteString &input); +}; + +} + +#endif // __ZPKEY_H__ diff --git a/src/include/openabe/keys/zsymkey.h b/src/include/openabe/keys/zsymkey.h new file mode 100644 index 00000000..542c536f --- /dev/null +++ b/src/include/openabe/keys/zsymkey.h @@ -0,0 +1,144 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zsymkey.h +/// +/// \brief Class definition for storing and manipulating +/// the symmetric enc OpenABE keys and ciphertexts. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZSYMKEY_H__ +#define __ZSYMKEY_H__ + +#include +#include +#include +#include +#include + +namespace oabe { +/// +/// Macro definitions +/// +#define IV_STR "IV" +#define CT_STR "Ciphertext" +#define TG_STR "Tag" + +/// +/// @class OpenABESymKey +/// +/// @brief Class for storing and manipulating symmetric encryption keys. +/// + +class OpenABESymKey : public OpenABEKey { +protected: + OpenABEByteString m_keyData; + +public: + // Constructors/destructors + OpenABESymKey(); + ~OpenABESymKey(); + + // Methods + std::string toString(); + uint8_t *getInternalPtr() { return (uint8_t *)&((this->m_keyData)[0]); } + uint32_t getLength() { return this->m_keyData.size(); } + OpenABEByteString& getKeyBytes() { return (this->m_keyData); } + + bool hashToSymmetricKey(GT &input, uint32_t keyLen, + OpenABEHashFunctionType hashType = OpenABE_DEFAULT_HASH_FUNCTION_TYPE); + bool generateSymmetricKey(uint32_t keyLen); + void setSymmetricKey(OpenABEByteString &key); + + OpenABE_ERROR exportKeyToBytes(OpenABEByteString &output); + OpenABE_ERROR loadKeyFromBytes(OpenABEByteString &input); + friend bool operator==(const OpenABESymKey&, const OpenABESymKey&); +}; + + +/// +/// @class OpenABESymKeyEnc +/// +/// @brief Class for performing symmetric key encryption using AES in CBC mode +/// + +class OpenABESymKeyEnc : ZObject { +private: + int seclevel; + std::string guid, keyStr; + uint8_t iv[AES_BLOCK_SIZE+1]; + AES_KEY *key; + bool status, iv_set; + +public: + OpenABESymKeyEnc(std::string key); + OpenABESymKeyEnc(int securitylevel, std::string key); + OpenABESymKeyEnc(int securitylevel, uint8_t *iv, std::string key); + ~OpenABESymKeyEnc(); + + void chooseRandomIV(); + std::string encrypt(uint8_t *plaintext, uint32_t plaintext_len); + std::string decrypt(std::string ciphertext); + bool getDecryptionStatus() { return status; } +}; + +/// +/// @class OpenABESymKeyAuthEncStream +/// +/// @brief Class for streaming encryption and decryption using AES in GCM mode +/// + +class OpenABESymKeyAuthEncStream : ZObject { +private: + EVP_CIPHER *cipher; + EVP_CIPHER_CTX *ctx; + OpenABEByteString the_iv, aad; + + std::shared_ptr key; + bool aad_set, init_enc_set, init_dec_set; + size_t total_ct_len, updateEncCount, updateDecCount; + +public: + OpenABESymKeyAuthEncStream(int securitylevel, const std::shared_ptr& key); + ~OpenABESymKeyAuthEncStream(); + + void initAddAuthData(uint8_t *aad, uint32_t aad_len); + OpenABE_ERROR setAddAuthData(void); + + OpenABE_ERROR encryptInit(OpenABEByteString *iv); + OpenABE_ERROR encryptUpdate(OpenABEByteString *plaintextBlock, OpenABEByteString *ciphertext); + OpenABE_ERROR encryptFinalize(OpenABEByteString* ciphertext, OpenABEByteString *tag); + + OpenABE_ERROR decryptInit(OpenABEByteString *iv, OpenABEByteString *tag); + OpenABE_ERROR decryptUpdate(OpenABEByteString *ciphertextBlock, OpenABEByteString *plaintext); + OpenABE_ERROR decryptFinalize(OpenABEByteString *plaintext); +}; + +} + +#endif /* ifdef __ZSYMKEY_H__ */ diff --git a/src/include/openabe/low/abe/zcontextcpwaters.h b/src/include/openabe/low/abe/zcontextcpwaters.h new file mode 100644 index 00000000..4863b842 --- /dev/null +++ b/src/include/openabe/low/abe/zcontextcpwaters.h @@ -0,0 +1,68 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextcpwaters.h +/// +/// \brief Class definition for CP-ABE schemes. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZCONTEXTCPWATERS_H__ +#define __ZCONTEXTCPWATERS_H__ + +/// +/// @class OpenABEContextCPWaters +/// +/// @brief Implementation of the Waters '09 CP-ABE encryption scheme. +/// +namespace oabe { + +class OpenABEContextCPWaters : public OpenABEContextABE { +public: + // Constructors/destructors + OpenABEContextCPWaters(std::unique_ptr rng); + ~OpenABEContextCPWaters(); + bool debug; + + OpenABE_ERROR generateParams(const std::string groupParams, + const std::string &mpkID, + const std::string &mskID); + + OpenABE_ERROR generateDecryptionKey(OpenABEFunctionInput *keyInput, const std::string &keyID, + const std::string &mpkID, const std::string &mskID, + const std::string &gpkID, const std::string &GID); + + OpenABE_ERROR encryptKEM(OpenABERNG *rng, const std::string &mpkID, const OpenABEFunctionInput *encryptInput, + uint32_t keyByteLen, const std::shared_ptr& key, OpenABECiphertext *ciphertext); + + OpenABE_ERROR decryptKEM(const std::string &mpkID, const std::string &keyID, OpenABECiphertext *ciphertext, + uint32_t keyByteLen, const std::shared_ptr& key); +}; + +} + +#endif /* ifdef __ZCONTEXTCPWATERS_H__ */ diff --git a/src/include/openabe/low/abe/zcontextkpgpsw.h b/src/include/openabe/low/abe/zcontextkpgpsw.h new file mode 100644 index 00000000..266388ee --- /dev/null +++ b/src/include/openabe/low/abe/zcontextkpgpsw.h @@ -0,0 +1,75 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextkpgpsw.h +/// +/// \brief Class definition for the KP-ABE [GPSW '06] scheme. +/// +/// \source [GPSW 06, Sec 5] and [PTMW 06, Sec 2.2 + Appendix B] +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZCONTEXTKPGPSW_H__ +#define __ZCONTEXTKPGPSW_H__ + +/// +/// @class OpenABEContextKPGPSW +/// +/// @brief Implementation of the GPSW '06 KP-ABE encryption scheme. +/// +namespace oabe { + +class OpenABEContextKPGPSW : public OpenABEContextABE { +public: + // Constructors/destructors + OpenABEContextKPGPSW(std::unique_ptr rng); + ~OpenABEContextKPGPSW(); + bool debug; + + // Main functions + OpenABE_ERROR generateParams(OpenABESecurityLevel securityLevel, + const std::string &mpkID, + const std::string &mskID); + + OpenABE_ERROR generateParams(const std::string groupParams, + const std::string &mpkID, + const std::string &mskID); + + OpenABE_ERROR generateDecryptionKey(OpenABEFunctionInput *keyInput, const std::string &keyID, + const std::string &mpkID, const std::string &mskID, + const std::string &gpkID, const std::string &GID); + + OpenABE_ERROR encryptKEM(OpenABERNG *rng, const std::string &mpkID, const OpenABEFunctionInput *encryptInput, + uint32_t keyByteLen, const std::shared_ptr& key, OpenABECiphertext *ciphertext); + + OpenABE_ERROR decryptKEM(const std::string &mpkID, const std::string &keyID, OpenABECiphertext *ciphertext, + uint32_t keyByteLen, const std::shared_ptr& key); +}; + +} + +#endif /* ifdef __ZCONTEXTKPGPSW_H__ */ diff --git a/src/include/openabe/low/pke/zcontextpke.h b/src/include/openabe/low/pke/zcontextpke.h new file mode 100644 index 00000000..e7deb250 --- /dev/null +++ b/src/include/openabe/low/pke/zcontextpke.h @@ -0,0 +1,135 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextpke.h +/// +/// \brief Class definition for public-key encryption schemes. +/// +/// \source One-pass DH KEM (in section 6.2.2.2 of NIST SP 800-56A) +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZCONTEXTPKE_H__ +#define __ZCONTEXTPKE_H__ + +/// +/// @class OpenABEContextPKE +/// +/// @brief Abstract class for public-key encryption schemes. +/// +namespace oabe { + +class OpenABEContextPKE : public OpenABEContext { +public: + // Constructors/destructors + OpenABEContextPKE(); + ~OpenABEContextPKE(); + + OpenABE_ERROR initializeCurve(const std::string groupParams); + OpenABE_ERROR generateParams(OpenABESecurityLevel securityLevel); + virtual bool validatePublicKey(const std::shared_ptr& key) = 0; + virtual bool validatePrivateKey(const std::shared_ptr& key) = 0; + + virtual OpenABE_ERROR generateParams(const std::string groupParams) = 0; + + virtual OpenABE_ERROR generateDecryptionKey(const std::string &keyID, + const std::string &pkID, + const std::string &skID) = 0; + + virtual OpenABE_ERROR encryptKEM(OpenABERNG *rng, const std::string &pkID, + OpenABEByteString *senderID, uint32_t keyBitLen, + const std::shared_ptr& key, + OpenABECiphertext *ciphertext) = 0; + + virtual OpenABE_ERROR decryptKEM(const std::string &pkID, const std::string &skID, + OpenABECiphertext *ciphertext, uint32_t keyBitLen, + const std::shared_ptr& key) = 0; +}; + +/// +/// @class OpenABEContextOPDH +/// +/// @brief Implementation derived from the One-Pass Diffie-Hellman Key Agreement scheme. +/// NIST SP 800-56A Recommendation for Pair-Wise Key Establishment Schemes Using +/// Discrete-Logarithm Cryptography: Section 6.2.2.2 +/// + +class OpenABEContextOPDH : public OpenABEContextPKE { +public: + // Constructors/destructors + OpenABEContextOPDH(std::unique_ptr rng); + ~OpenABEContextOPDH(); + + bool validatePublicKey(const std::shared_ptr& key); + bool validatePrivateKey(const std::shared_ptr& key); + + OpenABE_ERROR generateParams(const std::string groupParams); + OpenABE_ERROR generateDecryptionKey(const std::string &keyID, + const std::string &pkID, + const std::string &skID); + + OpenABE_ERROR encryptKEM(OpenABERNG *rng, const std::string &pkID, + OpenABEByteString *senderID, uint32_t keyBitLen, + const std::shared_ptr& key, OpenABECiphertext *ciphertext); + + OpenABE_ERROR decryptKEM(const std::string &pkID, const std::string &keyID, + OpenABECiphertext *ciphertext, uint32_t keyBitLen, + const std::shared_ptr& key); +}; + + +/// +/// @class OpenABEContextSchemePKE +/// +/// @brief Abstract class for PKE schemes. +/// + +class OpenABEContextSchemePKE : public ZObject { +private: + std::unique_ptr m_KEM_; + +public: + OpenABEContextSchemePKE(std::unique_ptr kem); + ~OpenABEContextSchemePKE(); + + OpenABE_ERROR exportKey(const std::string &keyID, OpenABEByteString &keyBlob); + OpenABE_ERROR loadPublicKey(const std::string &keyID, OpenABEByteString &keyBlob); + OpenABE_ERROR loadPrivateKey(const std::string &keyID, OpenABEByteString &keyBlob); + OpenABE_ERROR deleteKey(const std::string &keyID); + + OpenABE_ERROR generateParams(const std::string groupParams); + + OpenABE_ERROR keygen(const std::string &keyID, const std::string &pkID, const std::string &skID); + OpenABE_ERROR encrypt(OpenABERNG *rng, const std::string &pkID, const std::string &senderpkID, + const std::string& plaintext, OpenABECiphertext *ciphertext); + OpenABE_ERROR decrypt(const std::string &pkID, const std::string &skID, + std::string &plaintext, OpenABECiphertext *ciphertext); +}; + +} + +#endif // __ZCONTEXTPKE_H__ diff --git a/src/include/openabe/low/pksig/zcontextpksig.h b/src/include/openabe/low/pksig/zcontextpksig.h new file mode 100644 index 00000000..ff86eaa0 --- /dev/null +++ b/src/include/openabe/low/pksig/zcontextpksig.h @@ -0,0 +1,91 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextpksig.h +/// +/// \brief Class definition for OpenABE context PKSIG schemes. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZCONTEXTPKSIG_H__ +#define __ZCONTEXTPKSIG_H__ + +#include + +namespace oabe { + +class OpenABEContextPKSIG : public OpenABEContext { +protected: + EC_GROUP *group; + bool validateParams(const std::string ¶msID) { return true; }; + bool validatePkey(EVP_PKEY* pkey, bool expectPrivate); + +public: + // Constructors/destructors + OpenABEContextPKSIG(); + ~OpenABEContextPKSIG(); + + OpenABE_ERROR initializeCurve(const std::string groupParams); + bool validatePublicKey(const std::shared_ptr& key); + bool validatePrivateKey(const std::shared_ptr& key); + + OpenABE_ERROR generateParams(const std::string groupParams); + OpenABE_ERROR keygen(const std::string &pkID, const std::string &skID); + OpenABE_ERROR sign(OpenABEPKey *privKey, OpenABEByteString *message, OpenABEByteString *signature); + OpenABE_ERROR verify(OpenABEPKey *pubKey, OpenABEByteString *message, OpenABEByteString *signature); +}; + + +/// +/// @class OpenABEContextSchemePKSIG +/// +/// @brief Abstract scheme context for PKSIG. +/// + +class OpenABEContextSchemePKSIG : ZObject { +private: + std::unique_ptr m_PKSIG; + +public: + OpenABEContextSchemePKSIG(std::unique_ptr pksig); + ~OpenABEContextSchemePKSIG(); + + OpenABE_ERROR exportKey(const std::string &keyID, OpenABEByteString &keyBlob); + OpenABE_ERROR loadPublicKey(const std::string &keyID, OpenABEByteString &keyBlob); + OpenABE_ERROR loadPrivateKey(const std::string &keyID, OpenABEByteString &keyBlob); + OpenABE_ERROR deleteKey(const std::string &keyID); + + OpenABE_ERROR generateParams(const std::string groupParams); + OpenABE_ERROR keygen(const std::string &pkID, const std::string &skID); + OpenABE_ERROR sign(const std::string &skID, OpenABEByteString *message, OpenABEByteString *signature); + OpenABE_ERROR verify(const std::string &pkID, OpenABEByteString *message, OpenABEByteString *signature); +}; + +} + +#endif // __ZCONTEXTPKSIG_H__ + diff --git a/src/include/openabe/low/ske/zcontextske.h b/src/include/openabe/low/ske/zcontextske.h new file mode 100644 index 00000000..5411b87c --- /dev/null +++ b/src/include/openabe/low/ske/zcontextske.h @@ -0,0 +1,95 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextske.h +/// +/// \brief Class definition for OpenABE context symmetric-key encryption schemes. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZCONTEXTSKE_H__ +#define __ZCONTEXTSKE_H__ + +/// +/// @class OpenABEContextSchemeStreamSKE +/// +/// @brief Class for SKE schemes (authenticated encryption). +/// +namespace oabe { + +class OpenABEContextSchemeStreamSKE : public ZObject { +private: + OpenABEByteString aad; + OpenABEKeystore m_Keystore_; + OpenABESymKeyAuthEncStream *m_AuthEncStream; + OpenABESymKeyAuthEncStream *m_AuthDecStream; + +public: + OpenABEContextSchemeStreamSKE(); + ~OpenABEContextSchemeStreamSKE(); + + OpenABE_ERROR keygen(const std::string &keyID); + OpenABE_ERROR exportKey(const std::string &keyID, + OpenABEByteString &keyBlob, + const std::string password); + OpenABE_ERROR loadPrivateKey(const std::string &keyID, + OpenABEByteString &keyBlob, + const std::string password); + OpenABE_ERROR deleteKey(const std::string &keyID); + + OpenABE_ERROR encryptInit(const std::string &skID, OpenABEByteString *iv); + OpenABE_ERROR encryptUpdate(OpenABEByteString *plaintextBlock, OpenABEByteString *ciphertext); + OpenABE_ERROR encryptFinalize(OpenABEByteString* ciphertext, OpenABEByteString *tag); + + OpenABE_ERROR decryptInit(const std::string &skID, OpenABEByteString *iv, OpenABEByteString *tag); + OpenABE_ERROR decryptUpdate(OpenABEByteString *ciphertextBlock, OpenABEByteString *plaintext); + OpenABE_ERROR decryptFinalize(OpenABEByteString *plaintext); +}; + + +/// +/// Utility functions -- managing symmetric keys in OpenABE +/// Note: this is independent of the keys managed and used in each scheme context +/// + +OpenABE_ERROR OpenABE_storeSymmetricKey(OpenABEKeystore *gKeystore, + const std::string keyID, + const std::shared_ptr& key); +OpenABE_ERROR OpenABE_exportKey(OpenABEKeystore *gKeystore, + const std::string keyID, + OpenABEByteString *outputKeyBlob); +OpenABE_ERROR OpenABE_loadSymmetricKey(OpenABEKeystore *gKeystore, + const std::string keyID, + OpenABEByteString *skeyBlob); +std::shared_ptr OpenABE_getSymmetricKey(OpenABEKeystore *gKeystore, + const std::string keyID); +OpenABE_ERROR OpenABE_deleteSymmetricKey(OpenABEKeystore *gKeystore, + const std::string keyID); + +} + +#endif // __ZCONTEXTSKE_H__ diff --git a/src/include/openabe/openabe.h b/src/include/openabe/openabe.h new file mode 100644 index 00000000..89218a9b --- /dev/null +++ b/src/include/openabe/openabe.h @@ -0,0 +1,268 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file openabe.h +/// +/// \brief Main header file for the Zeutro Toolkit (OpenABE). +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZTOOLKIT_H__ +#define __ZTOOLKIT_H__ + +#include +#include + +#define SAFE_MALLOC(size) malloc(size) +#define SAFE_FREE(val) free(val) +#define SAFE_DELETE(ref) \ + if (ref != NULL) { \ + delete ref; \ + ref = NULL; \ + } + +#define OpenABE_LOG_ERROR(str) (std::cerr << "ERROR: " << str << std::endl) + +#ifdef DEBUG + #define DEBUG_ELEMENT_PRINTF(...) element_printf(__VA_ARGS__) + #define OpenABE_LOG_AND_THROW(str, err) \ + OpenABE_LOG_ERROR((str)); \ + throw(err); +#define OpenABE_LOG(str) \ + OpenABE_LOG_ERROR((str)); + +#else + #define DEBUG_ELEMENT_PRINTF(...) + #define OpenABE_LOG_AND_THROW(str, err) \ + throw(err); + #define OpenABE_LOG(str) /* do nothing */ +#endif + +/// @typedef OpenABE_STATE +/// +/// @brief Enumeration of global states for the Zeutro toolkit library + +typedef enum _OpenABE_STATE { + OpenABE_STATE_UNINITIALIZED = 0, + OpenABE_STATE_ERROR = 1, + OpenABE_STATE_READY = 2 +} OpenABE_STATE; + +/// @typedef OpenABE_SCHEME +/// +/// @brief Enumeration of supported FE schemes + +typedef enum _OpenABE_SCHEME { + OpenABE_SCHEME_NONE = 0, + OpenABE_SCHEME_PKSIG_ECDSA = 60, + OpenABE_SCHEME_AES_GCM = 70, + OpenABE_SCHEME_PK_OPDH = 100, + OpenABE_SCHEME_CP_WATERS = 101, + OpenABE_SCHEME_KP_GPSW = 102, + OpenABE_SCHEME_CP_WATERS_CCA = 201, + OpenABE_SCHEME_KP_GPSW_CCA = 202 +} OpenABE_SCHEME; + +// +// hash function prefix definitions +#define CCA_HASH_FUNCTION_ONE 0x1A +#define CCA_HASH_FUNCTION_TWO 0x1F +#define SCHEME_HASH_FUNCTION 0x2A +#define KDF_HASH_FUNCTION_PREFIX 0x2B + +#define OpenABE_MAX_KDF_BITLENGTH 0xFFFFFFFF +// +// Types and data structures +// + +typedef uint32_t OpenABESecurityLevel; + +// +// Core library header files +// + +#include +#include +#include +#include +#include +#if defined(OS_REDHAT_LINUX) + #include + #include + using ::max_align_t; +#endif +#include +extern "C" { +#include +} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace oabe { + +#if defined(BP_WITH_OPENSSL) +const std::string DEFAULT_MATH_LIB = "OpenSSL"; +#else /* WITH RELIC */ +const std::string DEFAULT_MATH_LIB = "RELIC"; +#endif +const std::string DEFAULT_BP_PARAM = "BN_P254"; +//const std::string DEFAULT_BP_PARAM = "BN_P382"; +const std::string DEFAULT_EC_PARAM = "NIST_P256"; + +/// +/// scheme identifiers +/// + +#define OpenABE_EC_DSA "EC-DSA" +#define OpenABE_PK_ENC "PK-ENC" +#define OpenABE_CP_ABE "CP-ABE" +#define OpenABE_KP_ABE "KP-ABE" +#define OpenABE_MA_ABE "MA-ABE" + +/// +/// Utility functions +/// + +void InitializeOpenABE(); +void InitializeOpenABEwithoutOpenSSL(); +void ShutdownOpenABE(); +void AssertLibInit(); + +const char *OpenABE_errorToString(OpenABE_ERROR err); +const uint32_t OpenABE_getLibraryVersion(); + +// creates KEM context for PKE & ABE schemes +OpenABEContextPKE *OpenABE_createContextPKE(std::unique_ptr *rng, + OpenABE_SCHEME scheme_type); +OpenABEContextABE *OpenABE_createContextABE(std::unique_ptr *rng, + OpenABE_SCHEME scheme_type); + +// PKE scheme context API +std::unique_ptr +OpenABE_createContextPKESchemeCCA(OpenABE_SCHEME scheme_type); +std::unique_ptr +OpenABE_createABEContextForKEM(OpenABE_SCHEME scheme_type); + +// CPA scheme context API +std::unique_ptr +OpenABE_createContextABESchemeCPA(OpenABE_SCHEME scheme_type); + +// CCA scheme context API +std::unique_ptr +OpenABE_createContextABESchemeCCA(OpenABE_SCHEME scheme_type); + +// CCA scheme context API with amortization support +std::unique_ptr +OpenABE_createContextABESchemeCCAWithATZN(OpenABE_SCHEME scheme_type); + +// PKSIG scheme context API +std::unique_ptr OpenABE_createContextPKSIGScheme(); + +// curve to/from string conversion functions +OpenABECurveID OpenABE_getCurveID(uint8_t id); +OpenABE_SCHEME OpenABE_getSchemeID(uint8_t id); +// convert strings to/from OpenABE_SCHEME +const std::string OpenABE_convertSchemeIDToString(OpenABE_SCHEME schemeID); +OpenABE_SCHEME OpenABE_convertStringToSchemeID(const std::string id); + +OpenABECurveID OpenABE_convertStringToCurveID(const std::string paramsID); +std::string OpenABE_convertCurveIDToString(OpenABECurveID id); +void OpenABE_setGroupObject(std::shared_ptr &group, uint8_t id); + +/// +/// OpenABE initialization per thread +/// +class OpenABEStateContext { +public: + /*! \brief Initialize OpenABE per thread + * + * The following function needs to be called exactly once at the + * beginning of any OpenABE-using thread except for the thread that + * calls OpenABE_initialize. This must be done in a thread before any + * OpenABE functionality is invoked in that thread, otherwise, your + * program may crash arbitrarily. + */ + void initializeThread(); + + /*! \brief Shutdown OpenABE per thread + * + * The following function needs to be called exactly once at the + * end of any OpenABE-using thread except for the thread that calls + * OpenABE_shutdown. This should be done before the destruction of + * the thread. If you forget to call this function, it is invoked + * in the destructor of the OpenABE state context. + */ + void shutdownThread(); + + OpenABEStateContext() : isInitialized_(false) { + // initializeThread() on constructor initialization + initializeThread(); + isInitialized_ = true; + } + + ~OpenABEStateContext() { + // in case user forgets to call shutdownThread() + if (isInitialized_) { + shutdownThread(); + } + } + +private: + bool isInitialized_; +}; +} + +#endif /* __ZTOOLKIT_H__ */ diff --git a/src/include/openabe/openssl_init.h b/src/include/openabe/openssl_init.h new file mode 100644 index 00000000..06c9dc37 --- /dev/null +++ b/src/include/openabe/openssl_init.h @@ -0,0 +1,56 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file openssl_init.h +/// +/// \brief Initialize and cleanup OpenSSL +/// +/// \author Alan Dunn +/// + +#ifndef __OPENSSL_INIT_H__ +#define __OPENSSL_INIT_H__ + +/*! \brief Initialize OpenSSL + * + * This function assumes it has complete responsibility for + * initializing OpenSSL and may not work correctly if other functions + * have already done this. + * + * Note: This function is not yet Windows compatible. + * + * Note: This function is only guaranteed to work with recent versions + * of OpenSSL (tested on version 1.0.1 or 1.1.0). + */ +void openSslInitialize(); + +/*! \brief Cleanup OpenSSL + * + * @see openSslInitialize + */ +void openSslCleanup(); + +#endif diff --git a/src/include/openabe/tools/zlsss.h b/src/include/openabe/tools/zlsss.h new file mode 100644 index 00000000..921c1554 --- /dev/null +++ b/src/include/openabe/tools/zlsss.h @@ -0,0 +1,131 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zlsss.h +/// +/// \brief Class definition files for a secret sharing context. +/// Includes all routines necessary for secret sharing in the OpenABE. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZLSSS_H__ +#define __ZLSSS_H__ + +#include +#include + +namespace oabe { + +/// \class ZLSSSElement +/// \brief Individual element of a secret sharing structure. +class OpenABELSSSElement : public ZObject { +protected: + std::string m_Prefix, m_Label; + ZP m_Element; + +public: + OpenABELSSSElement() { } + OpenABELSSSElement(std::string label, ZP &element); + OpenABELSSSElement(const OpenABELSSSElement ©) + : m_Prefix(copy.prefix()), m_Label(copy.label()), m_Element(copy.element()) { } + + // Public methods + std::string label() const { return this->m_Label; } + std::string prefix() const { return this->m_Prefix; } + ZP element() const { return this->m_Element; } + + // This method allows you to use the STL count() method to count the + // number of entries that match a given label. Note that it only + // compares to m_Label. + bool operator==(const std::string &label) { return (label == this->m_Label); } + friend std::ostream& operator<<(std::ostream& s, const OpenABELSSSElement& z) { + OpenABELSSSElement z2(z); + // note that label includes the prefix implicitly + s << z2.m_Label << " -> " << z2.m_Element << "\n"; + return s; + } +}; + +/// \typedef OpenABELSSSRowMap +/// \brief Key/value map of results in an LSSS +typedef std::map OpenABELSSSRowMap; + +/// \typedef OpenABELSSSRowMapIterator +/// \brief Iterator for vector of results in an LSSS +typedef OpenABELSSSRowMap::iterator OpenABELSSSRowMapIterator; + +/// \class ZLSSS +/// \brief Secret sharing class. + +class OpenABELSSS : public ZObject { +protected: + OpenABEPairing *m_Pairing; + OpenABERNG *m_RNG; + OpenABELSSSRowMap m_ResultMap; + bool debug; + ZP zero, iPlusOne, indexPlusOne; + std::map m_AttrCount; + + // Protected methods + void performSecretSharing(const OpenABEPolicy *policy, ZP &elt); + bool performCoefficientRecovery(OpenABEPolicy *policy, OpenABEAttributeList *attrList); + + void addShareToResults(OpenABETreeNode *treeNode, ZP &elt); + bool clearExistingResults() { this->m_ResultMap.clear(); return true; } + inline std::string makeUniqueLabel(const OpenABETreeNode *treeNode); + inline ZP evaluatePolynomial(std::vector &coefficients, uint32_t x); + + void iterativeShareSecret(OpenABETreeNode *treeNode, ZP &elt); + bool iterativeCoefficientRecover(OpenABETreeNode *treeNode, ZP &inCoeff); + inline ZP calculateCoefficient(OpenABETreeNode *treeNode, uint32_t index, uint32_t threshold, uint32_t total); + +public: + OpenABELSSS(OpenABEPairing *pairing, OpenABERNG *rng); + ~OpenABELSSS(); + + // Public secret sharing and recovery methods + void shareSecret(const OpenABEFunctionInput *input, ZP &elt); + bool recoverCoefficients(OpenABEPolicy *policy, OpenABEAttributeList *attrList); + + // Methods for obtaining the rows + OpenABELSSSRowMap& getRows() { return m_ResultMap; } + +#ifndef OpenABE_NO_TEST_ROUTINES + // + // Test routine we use to make sure secret sharing is working + // + ZP LSSStestSecretRecovery(const OpenABELSSSRowMap& coefficients, const OpenABELSSSRowMap& shares); +#endif // OpenABE_NO_TEST_ROUTINES +}; + +bool iterativeScanTree(OpenABETreeNode *treeNode, OpenABEAttributeList *attributeList); +bool determineIfNodeShouldBeMarked(uint32_t threshold, OpenABETreeNode *node); +std::pair checkIfSatisfied(OpenABEPolicy *policy, OpenABEAttributeList *attr_list, bool reset_flags=true); + +} + +#endif // __ZLSSS_H__ diff --git a/src/include/openabe/tools/zprng.h b/src/include/openabe/tools/zprng.h new file mode 100644 index 00000000..7dac10b3 --- /dev/null +++ b/src/include/openabe/tools/zprng.h @@ -0,0 +1,206 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zprng.h +/// +/// \brief Class definition for a pseudorandom generator. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZPRNG_H__ +#define __ZPRNG_H__ + +#include +#include +#include + +#define OpenABE_CTR_DRBG_BLOCKSIZE 16 /* Cipher Block size */ +#define OpenABE_CTR_DRBG_KEYSIZE_BYTES 32 /* Cipher Key size in bytes */ +#define OpenABE_CTR_DRBG_KEYSIZE_BITS ( OpenABE_CTR_DRBG_KEYSIZE_BYTES * 8 ) +#define OpenABE_CTR_DRBG_SEEDLEN ( OpenABE_CTR_DRBG_KEYSIZE_BYTES + OpenABE_CTR_DRBG_BLOCKSIZE ) +#define OpenABE_CTR_DRBG_NONCELEN 16 /* Default nonce length */ +#define OpenABE_CTR_DRBG_ENTROPYLEN 32 /* Amount of entropy used per seed by default + (32 with SHA-256, 48 with SHA-512, etc) */ + +#define OpenABE_CTR_DRBG_RESEED_INTERVAL 10000 /* Interval before re-seed is performed by default */ +#define OpenABE_CTR_DRBG_MAX_INPUT_LENGTH 256 /* Maximum number of additional input bytes */ +#define OpenABE_CTR_DRBG_MAX_REQUEST 1024 /* Maximum number of requested bytes per call */ +#define OpenABE_CTR_DRBG_MAX_SEED_INPUT 384 /* Maximum size of (re)seed buffer */ + +#define OpenABE_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /* The entropy source failed. */ +#define OpenABE_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /* Too many random requested in single call. */ +#define OpenABE_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /* Input too large (Entropy + additional). */ + + +/// \class OpenABERNG +/// \brief Abstract base class class for generating randomness +namespace oabe { + +class OpenABERNG : public ZObject { +public: + OpenABERNG(); + ~OpenABERNG(); + + virtual void setSeed(OpenABEByteString& nonce) { return; } + virtual int getRandomBytes(uint8_t *buf, size_t buf_len) { + ASSERT_RNG(RAND_bytes(buf, buf_len)); return 1; + } + virtual int getRandomBytes(OpenABEByteString *buf, size_t buf_len) { + buf->clear(); + buf->fillBuffer(0, buf_len); + ASSERT_RNG(RAND_bytes(buf->getInternalPtr(), buf_len)); + return 1; + } +}; + +struct OpenABECtrDrbg_ { + uint8_t key[OpenABE_CTR_DRBG_KEYSIZE_BYTES]; + uint8_t counter[AES_BLOCK_SIZE]; /* counter (V) - default: 256-bit counter */ + int reseed_counter, reseed_interval; + size_t entropy_len; + + // Callbacks (Entropy) + int (*entropy_callback)(void *, uint8_t *, size_t); + // context for the entropy function + void *entropy_src; +}; +typedef std::shared_ptr OpenABECtrDrbg; + +/*! + * \brief CTR_DRBG update state + * + * \param ctx CTR_DRBG object reference + * \param additional additional data to update state + * \param add_len length of additional data + * + * \note If add_len is greater than OpenABE_CTR_DRBG_MAX_SEED_INPUT, + * only the first OpenABE_CTR_DRBG_MAX_SEED_INPUT bytes are used, + * the remaining bytes are discarded. + */ +void ctr_drbg_update(OpenABECtrDrbg& ctx, const uint8_t *additional, size_t add_len); + +/*! + * \brief CTR_DRBG re-seeding (extracts data from entropy source) + * + * \param ctx CTR_DRBG object reference + * \param additional additional data to add to state (Can be NULL) + * \param len length of additional data + * + * \return 0 if successful, or + * OpenABE_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_reseed(OpenABECtrDrbg& ctx, const uint8_t *additional, size_t len); + +/*! + * \brief CTR_DRBG generate random with additional update input + * + * \param ctx CTR_DRBG object reference + * \param output Buffer to fill + * \param output_len Length of the buffer + * \param additional Additional data to update with (Can be NULL) + * \param add_len Length of additional data + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \return 0 if successful, or + * OpenABE_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * OpenABE_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int ctr_drbg_generate_random_with_add(OpenABECtrDrbg& ctx, uint8_t *output, size_t output_len, + const uint8_t *additional, size_t add_len); +/*! + * \brief CTR_DRBG initial seeding + * Seed and setup entropy source for future reseeds. + * + * Note: Personalization data can be provided in addition to the more generic + * entropy source to try to make each instantiation unique. + * + * \param ctx CTR_DRBG object to be seeded + * \param entropy_callback Entropy callback (entropy_buf, buffer to fill, buffer + * length) + * \param entropy_buf Entropy context + * \param person_str Personalization string (Device specific identifiers) + * (Can be NULL) + * \param len Length of personalization data + * + * \return 0 if successful, or OpenABE_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_init_seed(OpenABECtrDrbg& ctx, + int (*entropy_callback)(void *, uint8_t *, size_t), + void *entropy_buf, + const uint8_t *person_str, + size_t len); + +/// \class OpenABECtrDrbgContext +/// \brief Class/Context implementation for CTR_DRBG NIST Standard +/// Reference: NIST SP 800-90A, Rev 1. +// Section 10.2 titled "DRBG mechanisms based on Block Ciphers" +class OpenABECtrDrbgContext { +private: + OpenABECtrDrbg ctx_; + OpenABEByteString short_entropy_; + std::mutex lock_; + +public: + OpenABECtrDrbgContext(OpenABEByteString &entropy); + OpenABECtrDrbgContext(const uint8_t *entropy, uint32_t entropy_len); + ~OpenABECtrDrbgContext(); + + // for nist self test + void initSeed(int (*entropy_callback)(void *, uint8_t *, size_t), + const uint8_t *nonce, size_t nonce_len); + // uses short_entropy + void initSeed(const uint8_t *nonce, size_t nonce_len); + + int reSeed(const uint8_t *buf_ptr, size_t buf_len); + int reSeed(OpenABEByteString *buf); + + int getRandomBytes(uint8_t *buf, size_t buf_len); + int getRandomBytes(OpenABEByteString *buf, size_t buf_len); +}; + +/// \class OpenABECTR_DRBG +/// \brief Thin wrapper around the OpenABECtrDrbgContext +class OpenABECTR_DRBG : public OpenABERNG { +private: + bool isInit_; + std::unique_ptr ctrDrbgContext_; + +public: + OpenABECTR_DRBG(OpenABEByteString &entropy); + OpenABECTR_DRBG(uint8_t *key, uint32_t key_len); + ~OpenABECTR_DRBG() { }; + + void setSeed(OpenABEByteString& nonce); + int getRandomBytes(uint8_t *buf, size_t buf_len); + int getRandomBytes(OpenABEByteString *buf, size_t buf_len); +}; + + +} + +#endif /* ifdef __ZPRNG_H__ */ diff --git a/src/include/openabe/utils/zandroid.h b/src/include/openabe/utils/zandroid.h new file mode 100644 index 00000000..7b0a55ba --- /dev/null +++ b/src/include/openabe/utils/zandroid.h @@ -0,0 +1,62 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +// +/// \file zandroid.h +/// +/// \brief Header for Android-specific modifications. +/// +/// \author Michael Rushanan and J. Ayo Akinyele +/// + +#ifndef __ZANDROID_H__ +#define __ZANDROID_H__ + +#include +#include +#include + +#ifdef ANDROID + +namespace std { +// Handling issue with missing std::to_string method in Android. +// https://code.google.com/p/android/issues/detail?id=82791 +// +// Solution: well documented on the internet for numerous compilers. +template +inline string to_string(T value) { + ostringstream os_strstream; + os_strstream << value; + return os_strstream.str(); +} + +inline int stoi(string integer) { + return atoi(integer.c_str()); +} + +} +#endif + +#endif // __ZANDROID_H__ diff --git a/src/include/openabe/utils/zattributelist.h b/src/include/openabe/utils/zattributelist.h new file mode 100644 index 00000000..2e8f3860 --- /dev/null +++ b/src/include/openabe/utils/zattributelist.h @@ -0,0 +1,87 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zattributelist.h +/// +/// \brief Subclass of OpenABEFunctionInput that represents ABE attribute lists. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZATTRIBUTELIST_H__ +#define __ZATTRIBUTELIST_H__ + +#define EQUALS '=' +#define NUM_HASH '#' +#define WHITESPACE ' ' +#define ATTR_SEP '|' +namespace oabe { + +/// +/// @class OpenABEAttributeList +/// +/// @brief Subclass of OpenABEFunctionInput that represents attributes. +/// +class OpenABEAttributeList : public OpenABEFunctionInput { +protected: + std::vector m_Attributes; + std::vector m_OriginalAttributes; + void setAttributes(std::vector& attr_list, + std::vector& orig_attr_list, + std::set& prefix_list); + +public: + // Constructors/destructors + OpenABEAttributeList(); + OpenABEAttributeList(const OpenABEAttributeList ©); + OpenABEAttributeList(uint32_t numArgs, std::vector args); + virtual ~OpenABEAttributeList(); + + void getStringList(std::vector &attrStrings); + bool hasOrigAttributes() const { return (this->m_OriginalAttributes.size() > 0); } + void syncOrigAttributes(const std::string& prefix, OpenABEAttributeList& attrList); + bool matchAttribute(const std::string &attribute); + bool addAttribute(std::string attribute); + + friend std::ostream& operator<<(std::ostream&, const OpenABEAttributeList&); + const std::vector* getAttributeList() const { return &this->m_Attributes; } + const std::vector* getOriginalAttributeList() const { return &this->m_OriginalAttributes; } + OpenABEAttributeList* clone() const { return new OpenABEAttributeList(*this); } + std::string toString() const; + std::string toCompactString() const; + void serialize(OpenABEByteString &result) const; + void deserialize(const OpenABEByteString &input); + bool isEqual(ZObject*) const; + friend class Driver; + +//private: +// static bool isNumeric(const std::string s); +}; + +std::unique_ptr createAttributeList(const std::string& s); +} + +#endif /* ifdef __ZATTRIBUTELIST_H__ */ diff --git a/src/include/openabe/utils/zbenchmark.h b/src/include/openabe/utils/zbenchmark.h new file mode 100644 index 00000000..ae5f9b60 --- /dev/null +++ b/src/include/openabe/utils/zbenchmark.h @@ -0,0 +1,86 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zattributelist.h +/// +/// \brief Benchmark utility interface +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZBENCHMARK_H__ +#define __ZBENCHMARK_H__ + +#include +#include +#include +#include + +#define MAX_LIST 10000000 + +class Benchmark { +public: + Benchmark() { initBench = true; sum = 0.0; iterationCount = 0; }; + ~Benchmark() { }; + void start(); + void stop(); + double computeTimeInMilliseconds(); + int getTimeInMicroseconds(); + std::string getRawResultString(); + double getAverage(); + +private: + std::chrono::system_clock::time_point startT, endT; + double sum; + int iterationCount; + std::stringstream ss; + bool initBench; +}; + +class ListStr { +public: + ListStr(void); + ~ListStr(); + ListStr(const ListStr&); + void append(std::string&); + void append(std::string); + void insert(int, std::string&); + void insert(int, std::string); + int length(); + std::string printAtIndex(int index); + int searchKey(std::string index); + std::string& operator[](const int index); + ListStr& operator=(const ListStr&); + friend std::ostream& operator<<(std::ostream&, const ListStr&); + +private: + int index; + std::map list; +}; + +bool CheckEqual(std::string value1, std::string value2); + +#endif diff --git a/src/include/openabe/utils/zbytestring.h b/src/include/openabe/utils/zbytestring.h new file mode 100644 index 00000000..29564e5d --- /dev/null +++ b/src/include/openabe/utils/zbytestring.h @@ -0,0 +1,501 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zbytestring.h +/// +/// \brief Generic class for handling byte strings. These strings can +/// include null (0) characters. Otherwise this class is +/// similar to a std::string. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZBYTESTRING_H__ +#define __ZBYTESTRING_H__ + +#include +#include +#include +#include +#include + +#include "zcryptoutils.h" +#include "zconstants.h" + +#define HEX_CHARS "0123456789abcdefABCDEF" +#define BYTESTRING 0x1D +#define DEBUG_VAR(a,b) std::cerr << a << b << std::endl; + +/// \class OpenABEByteString +/// \brief Generic container for manipulating a vector of bytes. +/// May be subclassed for specific schemes. +typedef enum PACK_TYPE { + PACK_NONE = 0x00, + PACK_8 = 0xA1, + PACK_16 = 0xB2, + PACK_32 = 0xC3, + PACK_64 = 0xD4 +} PackType; + +namespace oabe { + +class OpenABEByteString : public ZObject, public std::vector { + +public: + OpenABEByteString& operator+=(const OpenABEByteString &concat) { + this->insert(this->end(), concat.begin(), concat.end()); + return *this; + } + + OpenABEByteString& operator+=(const std::string concat) { + this->insert(this->end(), concat.begin(), concat.end()); + return *this; + } + + OpenABEByteString& appendArray(uint8_t input[], uint32_t size) { + this->insert(this->end(), &input[0], &input[size]); + return *this; + } + + OpenABEByteString operator+(OpenABEByteString &concat) { + OpenABEByteString result; + result.insert(result.end(), this->begin(), this->end()); + result.insert(result.end(), concat.begin(), concat.end()); + return result; + } + + OpenABEByteString operator+(std::string concat) { + OpenABEByteString result; + uint32_t size = concat.size(); + result.insert(result.end(), this->begin(), this->end()); + result.insert(result.end(), ((uint8_t*) concat.c_str())[0], ((uint8_t*)concat.c_str())[size]); + return result; + } + + OpenABEByteString& operator=(const std::string &rhs) { + this->clear(); + this->insert(this->end(), rhs.begin(), rhs.end()); + return *this; + } + + OpenABEByteString& operator^=(OpenABEByteString &rhs) { + if (this->size() != rhs.size()) { + THROW_ERROR(OpenABE_ERROR_INVALID_INPUT); + } else { + uint8_t *lhs_ptr = this->getInternalPtr(); + uint8_t *rhs_ptr = rhs.getInternalPtr(); + for(size_t i = 0; i < this->size(); i++) { + lhs_ptr[i] = this->at(i) ^ rhs_ptr[i]; + } + return *this; + } + } + + uint8_t *getInternalPtr() { + return &((*this)[0]); + } + + void zeroize() { + size_t b_len = this->size(); + if (b_len > 0) { + void *b = &((*this)[0]); + OpenABEZeroize(b, b_len); + } + this->clear(); + } + + void eraseAll() { + this->erase(this->begin(), this->end()); + } + + OpenABEByteString getSubset(size_t start_pos, size_t num_bytes) { + OpenABEByteString result; + uint8_t *ptr = this->getInternalPtr(); + if((start_pos + num_bytes) <= this->size()) { + // copy the subset + result.appendArray((uint8_t*) (ptr + start_pos), num_bytes); + } + return result; + } + + void fillBuffer(uint8_t byte, uint32_t len) { + // clear buffer + this->clear(); + for(size_t i = 0; i < len; i++) { + // fill with the given byte + this->push_back(byte); + } + } + + void insertFirstByte(uint8_t byte) { + this->insert(this->begin(), byte); + } + + OpenABEByteString* clone() const { + return new OpenABEByteString(*this); + } + + std::string toHex() const { + std::stringstream ss; + int hex_len = 2; + char hex[hex_len+1]; + std::memset(hex, 0, hex_len+1); + + for (std::vector::const_iterator it = this->begin(); + it != this->end(); ++it) { + sprintf(hex, "%02X", *it); + ss << hex; + } + return ss.str(); + } + + std::string toLowerHex() const { + std::stringstream ss; + int hex_len = 2; + char hex[hex_len+1]; + std::memset(hex, 0, hex_len+1); + + for (std::vector::const_iterator it = this->begin() ; it != this->end(); ++it) { + sprintf(hex, "%02x", *it); + ss << hex; + } + return ss.str(); + } + + bool fromHex(std::string s) { + if((s.find_first_not_of(HEX_CHARS) != std::string::npos) || + (s.size() % 2 != 0)) { + return false; + } + + std::string hex_str; + std::stringstream ss; + int tmp; + + this->clear(); + for (size_t i = 0; i < s.size(); i += 2) { + hex_str = s[i]; + hex_str += s[i+1]; + + ss << hex_str; + ss >> std::hex >> tmp; + this->push_back(tmp & 0xFF); + ss.clear(); + } + + return true; + } + + void fromString(const std::string& concat) { + this->clear(); + this->insert(this->end(), concat.begin(), concat.end()); + } + + const std::string toString() { + std::stringstream ss; + for (std::vector::iterator it = this->begin() ; it != this->end(); ++it) { + const unsigned char str = *it; + ss << str; + } + return ss.str(); + } + + // constant time comparison for bytestring objects + friend bool operator==(const OpenABEByteString& lhs, const OpenABEByteString& rhs) { + if (lhs.size() != rhs.size()) + return false; + int rc = 0; + for (size_t i = 0; i < lhs.size(); i++) { + rc |= (lhs.at(i) ^ rhs.at(i)); + } + /* 0 => lhs == rhs, > 0 => lhs != rhs */ + return (rc == 0) ? true : false; + } + + friend std::ostream& operator<<(std::ostream& s, const OpenABEByteString& z) { + OpenABEByteString z2(z); + for (std::vector::iterator it = z2.begin() ; it != z2.end(); ++it) { + s << *it; + } + return s; + } + + void serialize(OpenABEByteString& result) const { + result.clear(); + result.pack32bits((uint32_t) this->size()); + result.insertFirstByte(BYTESTRING); + result += *this; + } + + void deserialize(OpenABEByteString &input) { + uint32_t len = 0; + size_t hdrLen = 5; + if (input.size() > hdrLen) { + for (size_t i = 1; i <= sizeof(uint32_t); i++) { + len <<= 8; + len += input.at(i); + } + + if(input.size() == (len + hdrLen)) { + *this = input.getSubset(hdrLen, len); + } else { + THROW_ERROR(OpenABE_ERROR_DESERIALIZATION_FAILED); + } + } else { + THROW_ERROR(OpenABE_ERROR_DESERIALIZATION_FAILED); + } + } + + bool isEqual(ZObject* z) const { + OpenABEByteString *z1 = dynamic_cast(z); + if(z1 != NULL) { + return *z1 == *this; + } + return false; + } + + void pack8bits(uint8_t byte) { + this->push_back(byte); + } + + void pack16bits(uint16_t bytes) { + uint8_t tmp_buf[sizeof(uint16_t)]; + tmp_buf[1] = (bytes & 0x00FF); + tmp_buf[0] = (bytes & 0xFF00) >> 8; + this->appendArray(tmp_buf, sizeof(uint16_t)); + return; + } + + void pack32bits(uint32_t bytes) { + uint8_t tmp_buf[sizeof(uint32_t)]; + uint32_t x = bytes; + for (int i = sizeof(uint32_t); i > 0; i--) { + tmp_buf[i-1] = (x & 0xFF); + x >>= 8; + } + this->appendArray(tmp_buf, sizeof(uint32_t)); + return; + } + + void setFirstBytes(uint32_t bytes) { + uint8_t tmp_buf[sizeof(uint32_t)]; + uint32_t x = bytes; + for (int i = sizeof(uint32_t); i > 0; i--) { + tmp_buf[i-1] = (x & 0xFF); + x >>= 8; + } + if(this->size() >= sizeof(uint32_t)) { + (*this)[0] = tmp_buf[0]; + (*this)[1] = tmp_buf[1]; + (*this)[2] = tmp_buf[2]; + (*this)[3] = tmp_buf[3]; + } else { + this->appendArray(tmp_buf, sizeof(uint32_t)); + } + } + + void pack(uint8_t *buf, uint32_t buf_len) { + this->pack32bits(buf_len); + this->appendArray(buf, buf_len); + } + + void pack(OpenABEByteString &buf) { + uint32_t buf_size = buf.size(); + if(buf_size == 0) { + THROW_ERROR(OpenABE_ERROR_INVALID_INPUT); + } + this->pack32bits(buf_size); + this->appendArray(buf.getInternalPtr(), buf_size); + } + + void smartPack(OpenABEByteString& buf) { + // determine whether 8 or 16 or 32-bits are needed to pack the buffer + // as a function of the entire size of the buffer + if(buf.size() > UINT16_MAX) { + // pack as 32-bit + uint32_t buf_size = buf.size(); + this->push_back(PACK_32); + this->pack32bits(buf_size); + } else if(buf.size() > UINT8_MAX) { + // all we need is 16-bits + uint16_t buf_size = buf.size(); + this->push_back(PACK_16); + this->pack16bits(buf_size); + } else if (buf.size() > 0) { + // all we need is 8-bits + uint8_t buf_size = buf.size(); + this->push_back(PACK_8); + this->pack8bits(buf_size); + } else { + THROW_ERROR(OpenABE_ERROR_INVALID_INPUT); + } + this->appendArray(buf.getInternalPtr(), buf.size()); + return; + } + + OpenABEByteString smartUnpack(size_t *index) { + size_t buf_len = this->size(); + if(*index + 1 > buf_len) { + DEBUG_VAR("Index: ", *index); + DEBUG_VAR("Buf Len: ", buf_len); + THROW_ERROR(OpenABE_ERROR_INDEX_OUT_OF_BOUNDS); + } + + PackType pack_type = (PackType) this->at(*index); + *index += 1; + if(pack_type == PACK_32) { + return this->unpack(index); + } else if(pack_type == PACK_16) { + return this->unpack16bits(index); + } else if(pack_type == PACK_8) { + return this->unpack8bits(index); + } else { + std::cerr << "Pack type: " << pack_type << std::endl; + THROW_ERROR(OpenABE_ERROR_INVALID_PACK_TYPE); + } + OpenABEByteString buf; + return buf; + } + + OpenABEByteString unpack8bits(size_t *index) { + size_t index2 = *index; + OpenABEByteString buf; + size_t buf_len = this->size(); + if(index2 >= buf_len || (index2 + 1) > buf_len) { + /* we've gone past the end of the buffer so stop */ + DEBUG_VAR("Index: ", index2); + DEBUG_VAR("Buf Len: ", buf_len); + THROW_ERROR(OpenABE_ERROR_INDEX_OUT_OF_BOUNDS); + } + uint16_t len = this->at(index2); + // 1 byte for 8-bit type rep + if(len > buf_len || (index2 + len + 1) > buf_len) { + DEBUG_VAR("Len: ", len); + DEBUG_VAR("Index: ", index2); + DEBUG_VAR("Buf Len: ", buf_len); + THROW_ERROR(OpenABE_ERROR_INDEX_OUT_OF_BOUNDS); + } + index2 += 1; + + for(size_t i = 0; i < len; i++) { + buf.push_back(this->at(index2)); + index2++; + } + *index = index2; + return buf; + } + + OpenABEByteString unpack16bits(size_t *index) { + size_t index2 = *index; + OpenABEByteString buf; + size_t buf_len = this->size(); + + if (index2 >= buf_len || (index2 + 2) > buf_len) { + DEBUG_VAR("Index: ", index2); + DEBUG_VAR("Buf Len: ", buf_len); + THROW_ERROR(OpenABE_ERROR_INDEX_OUT_OF_BOUNDS); + } + uint16_t len = 0; + len |= this->at(index2+1); + len |= (this->at(index2) << 8); + + // 2 byte for 16-bit type rep + if(len > buf_len || (index2 + len + 2) > buf_len) { + DEBUG_VAR("Len: ", len); + DEBUG_VAR("Index: ", index2); + DEBUG_VAR("Buf Len: ", buf_len); + THROW_ERROR(OpenABE_ERROR_INDEX_OUT_OF_BOUNDS); + } + index2 += 2; + for(size_t i = 0; i < len; i++) { + buf.push_back(this->at(index2)); + index2++; + } + *index = index2; + return buf; + } + + OpenABEByteString unpack(size_t *index) { + size_t index2 = *index; + OpenABEByteString buf; + size_t buf_len = this->size(); + + if (index2 >= buf_len || (index2 + 4) > buf_len) { + DEBUG_VAR("Index: ", index2); + DEBUG_VAR("Buf Len: ", buf_len); + THROW_ERROR(OpenABE_ERROR_INDEX_OUT_OF_BOUNDS); + } + uint32_t len = 0; + len |= (this->at(index2) << 24); + len |= (this->at(index2+1) << 16); + len |= (this->at(index2+2) << 8); + len |= this->at(index2+3); + + // 4 byte for 32-bit type rep + if(len > buf_len || (index2 + len + 4) > buf_len) { + DEBUG_VAR("Len: ", len); + DEBUG_VAR("Index: ", index2); + DEBUG_VAR("Buf Len: ", buf_len); + THROW_ERROR(OpenABE_ERROR_INDEX_OUT_OF_BOUNDS); + } + index2 += 4; + for (size_t i = 0; i < len; i++) { + buf.push_back(this->at(index2)); + index2++; + } + *index = index2; + return buf; + } + + void unpack(size_t *index, OpenABEByteString & buf) { + size_t index2 = *index; + size_t buf_len = this->size(); + if (index2 >= buf_len || (index2 + 4) > buf_len) { + THROW_ERROR(OpenABE_ERROR_INDEX_OUT_OF_BOUNDS); + } + uint32_t len = 0; + len |= (this->at(index2) << 24); + len |= (this->at(index2+1) << 16); + len |= (this->at(index2+2) << 8); + len |= this->at(index2+3); + + // 4 byte for 32-bit type rep + if(len > buf_len || (index2 + len + 4) > buf_len) { + THROW_ERROR(OpenABE_ERROR_INDEX_OUT_OF_BOUNDS); + } + index2 += 4; + for (size_t i = 0; i < len; i++) { + buf.push_back(this->at(index2)); + index2++; + } + *index = index2; + return; + } +}; + +} + +#endif // __ZBYTESTRING_H__ diff --git a/src/include/openabe/utils/zciphertext.h b/src/include/openabe/utils/zciphertext.h new file mode 100644 index 00000000..ee860471 --- /dev/null +++ b/src/include/openabe/utils/zciphertext.h @@ -0,0 +1,88 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zciphertext.h +/// +/// \brief Class definition files for a functional encryption ciphertext. +/// This may be subclassed for specific FE schemes. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZCIPHERTEXT_H__ +#define __ZCIPHERTEXT_H__ + +#include + +/// \class ZCiphertext +/// \brief Generic container for Functional Encryption ciphertexts. +/// May be subclassed for specific schemes. +namespace oabe { + +class OpenABECiphertext : public OpenABEContainer { +protected: + // 32-bytes for representing OpenABECiphertext Header information as follows: + // 1 bytes for the library version + uint8_t libraryVersion; + // 1 byte for the curve identifier + uint8_t curveID; + // 1 byte for algorithm/scheme ID + uint8_t algorithmID; + // 32 bytes for UID + OpenABEByteString uid; + // whether the uid has been set externally + // default is false + bool uid_set_extern; + +public: + OpenABECiphertext(); + OpenABECiphertext(std::shared_ptr group); + OpenABECiphertext(const OpenABEByteString& uid); + ~OpenABECiphertext(); + + void setHeader(OpenABECurveID curveID, OpenABE_SCHEME scheme_type, OpenABERNG *rng); + void setHeader(OpenABECurveID curveID, OpenABE_SCHEME scheme_type, OpenABEByteString &uid); + void getHeader(OpenABEByteString &header); + + void setSchemeType(OpenABE_SCHEME scheme_type) { this->algorithmID = scheme_type; } + OpenABE_SCHEME getSchemeType() { return (OpenABE_SCHEME) this->algorithmID; } + uint8_t getCurveID() { return this->curveID; } + uint8_t getAlgorithmID() { return this->algorithmID; } + uint8_t getLibID() { return this->libraryVersion; } + OpenABEByteString& getUID() { return this->uid; } + + // export and import methods for ciphertext components + // this includes the OpenABE header and the contents of the ciphertext + void exportToBytes(OpenABEByteString &output); + void loadFromBytes(OpenABEByteString &input); + + void exportToBytesWithoutHeader(OpenABEByteString& output); + void loadFromBytesWithoutHeader(OpenABEByteString& input); +}; + +} + +#endif // __ZCIPHERTEXT_H__ diff --git a/src/include/openabe/utils/zconstants.h b/src/include/openabe/utils/zconstants.h new file mode 100644 index 00000000..fe2f713b --- /dev/null +++ b/src/include/openabe/utils/zconstants.h @@ -0,0 +1,127 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zconstants.h +/// +/// \brief Main header file for the Zeutro Functional Encryption Toolkit +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZCONSTANTS_H__ +#define __ZCONSTANTS_H__ + +// +// Constants +// + +#define OpenABE_LIBRARY_VERSION 170 // Library version 1.7 +#define MIN_BYTE_LEN 32 +#define DEFAULT_SECURITY_LEVEL 128 +#define DEFAULT_AES_SEC_LEVEL MIN_BYTE_LEN*8 // AES-256 +#define SALT_LEN MIN_BYTE_LEN // 256-bits (minimum is 64-bits) +#define HASH_LEN MIN_BYTE_LEN // 256-bits +#define SEED_LEN MIN_BYTE_LEN +#define UID_LEN 16 // 128-bit UID length +#define DEFAULT_SYM_KEY_BYTES MIN_BYTE_LEN // 256-bit keys +#define DEFAULT_SYM_KEY_BITS DEFAULT_SYM_KEY_BYTES*8 +#define SHA256_LEN 32 // SHA-256 +#define OpenABE_KDF_ITERATION_COUNT 10000 +#define MAX_BUFFER_SIZE 512 +#define MAX_INT_BITS 32 // For numerical attributes (in policy/attribute list) + +// Data structures // OpenABE_ELEMENT_UINT = 0x2D, +typedef enum _OpenABEElementType { + OpenABE_NONE_TYPE = 0x00, + OpenABE_ELEMENT_INT = 0xA1, + OpenABE_ELEMENT_ZP = 0xB1, + OpenABE_ELEMENT_G1 = 0xB2, + OpenABE_ELEMENT_G2 = 0xB3, + OpenABE_ELEMENT_GT = 0xB4, + OpenABE_ELEMENT_ZP_t = 0xC1, + OpenABE_ELEMENT_G_t = 0xC2, + OpenABE_ELEMENT_POLICY = 0x7A, + OpenABE_ELEMENT_ATTRIBUTES = 0x7C, // this is ATTR_SEP '|' in hex + OpenABE_ELEMENT_BYTESTRING = 0x1D, +} OpenABEElementType; + +/// @typedef OpenABECurveID +/// +/// @brief Enumeration all the curve identifiers supported + +typedef enum _OpenABECurveID { + OpenABE_NONE_ID = 0x00, + OpenABE_NIST_P256_ID = 0x32, + OpenABE_NIST_P384_ID = 0x5A, + OpenABE_NIST_P521_ID = 0xB7, + OpenABE_BN_P158_ID = 0x61, + OpenABE_BN_P254_ID = 0x6F, + OpenABE_BN_P256_ID = 0x73, + OpenABE_KSS_508_ID = 0x3C, + OpenABE_BN_P382_ID = 0xE4, + OpenABE_BN_P638_ID = 0x8D +} OpenABECurveID; + +// Data structures + +typedef enum _zGroupType { + GROUP_NONE, + GROUP_G1, + GROUP_G2, + GROUP_GT, + GROUP_ZP +} zGroupType; + +#define NO_COMPRESS 0 +#define COMPRESS 1 +#define BINARY 2 +#define DEC 10 +#define HEXADECIMAL 16 +#define MAX_BYTES 1024 +#define SHA1_BITLEN 160 // only used with PBKDF2 +#define SHA2_BITLEN 256 +#define HASH_FUNCTION_STRINGS "0" +#define HASH_FUNCTION_STR_TO_Zr_CRH "1" +#define HASH_FUNCTION_Zr_TO_G1_ROM "2" +#define HASH_FUNCTION_Zr_TO_G2_ROM "3" + +// Macros + +#define ASSERT_GROUP(G, A, B) if ( (A) != (G) || (B) != (G) ) throw oabe::OpenABE_ERROR_WRONG_GROUP; +#define ASSERT_RNG(R) if ( (R) < 1 ) throw oabe::OpenABE_ERROR_RAND_INSUFFICIENT; +#define ASSERT_PAIRING(P) if ( (P) == NULL ) throw oabe::OpenABE_ERROR_WRONG_GROUP; +#define ASSERT_NOTNULL(A) if ( (A) == NULL ) throw oabe::OpenABE_ERROR_INVALID_INPUT; +#define ASSERT_MESSAGE(A, B, C) if ( (A) == false ) { string tmp_s = B; fprintf(stderr, "%s:%s:%d: %s - '%s'\n", __FILE__, __FUNCTION__, __LINE__, tmp_s.c_str(), OpenABE_errorToString(C)); throw C; } +#define ASSERT(A, B) if ( (A) == false ) { fprintf(stderr, "%s:%s:%d: '%s'\n", __FILE__, __FUNCTION__, __LINE__, OpenABE_errorToString(B)); throw B; } +#define THROW_ERROR(B) fprintf(stderr, "%s:%s:%d: '%s'\n", __FILE__, __FUNCTION__, __LINE__, OpenABE_errorToString(B)); throw B; + +#define MALLOC_CHECK_OUT_OF_MEMORY(ptr) \ + if(!ptr) { \ + fprintf(stderr, __FILE__ ": Out of Memory, Line %d\n", __LINE__); \ + exit(1); \ + } + +#endif /* ifdef __ZCONSTANTS_H__ */ diff --git a/src/include/openabe/utils/zcontainer.h b/src/include/openabe/utils/zcontainer.h new file mode 100644 index 00000000..547c5240 --- /dev/null +++ b/src/include/openabe/utils/zcontainer.h @@ -0,0 +1,91 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontainer.h +/// +/// \brief Class definition files for a generic container. Used +/// for keys and ciphertexts. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZCONTAINER_H__ +#define __ZCONTAINER_H__ + +#include + +namespace oabe { +class ZP; +class G; +} + +/// \class OpenABEContainer +/// \brief Generic container for Functional Encryption data structures. +/// May be subclassed for specific schemes. +namespace oabe { + +class OpenABEContainer : protected ZObject { +protected: + std::shared_ptr group; + std::map val; + void deserialize(OpenABEByteString &blob); + void deserialize(std::string &blob); + void deserializeElement(std::string key, OpenABEByteString& value); + void serialize(OpenABEByteString &result) const; + // void serializeAsTuple(std::vector& keys, OpenABEByteString &result) const; + +public: + OpenABEContainer(); + OpenABEContainer(std::shared_ptr group); + virtual ~OpenABEContainer(); + + void setGroup(std::shared_ptr group) { this->group = group; } + void setComponent(const std::string &name, const ZObject *component); + void setComponent(const std::string &name, ZObject component); + ZObject* getComponent(const std::string &name); + OpenABE_ERROR deleteComponent(const std::string name); + // Some helper methods for getting components of specific types + ZP* getZP(const std::string &name) { return dynamic_cast(this->getComponent(name)); } + G1* getG1(const std::string &name) { return dynamic_cast(this->getComponent(name)); } + G2* getG2(const std::string &name) { return dynamic_cast(this->getComponent(name)); } + GT* getGT(const std::string &name) { return dynamic_cast(this->getComponent(name)); } + + ZP_t* getZP_t(const std::string &name) { return dynamic_cast(this->getComponent(name)); } + G_t* getG_t(const std::string &name) { return dynamic_cast(this->getComponent(name)); } + + OpenABEByteString* getByteString(const std::string &name) { return dynamic_cast(this->getComponent(name)); } + OpenABEUInteger* getInteger(const std::string &name) { return dynamic_cast(this->getComponent(name)); } + uint32_t numComponents(); + OpenABE_ERROR zeroize(); + + std::vector getKeys(); + friend bool operator==(const OpenABEContainer&, const OpenABEContainer&); +}; + +inline std::string OpenABEMakeElementLabel(std::string base, std::string unique) { return base + "_" + unique; } + +} +#endif // __ZCONTAINER_H__ diff --git a/src/include/openabe/utils/zcryptoutils.h b/src/include/openabe/utils/zcryptoutils.h new file mode 100644 index 00000000..16aa04b6 --- /dev/null +++ b/src/include/openabe/utils/zcryptoutils.h @@ -0,0 +1,90 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcryptoutils.h +/// +/// \brief Miscellaneous cryptographic utilities. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZCRYPTOUTILS_H__ +#define __ZCRYPTOUTILS_H__ + +namespace oabe { + +/// @typedef OpenABEHashFunctionType +/// +/// @brief Enumeration of supported hash function types + +typedef enum _OpenABEHashFunctionType { + HASH_FUNCTION_TYPE_SHA1 = 0, + HASH_FUNCTION_TYPE_SHA256 = 1, + HASH_FUNCTION_TYPE_SHA384 = 2, + HASH_FUNCTION_TYPE_SHA512 = 3 +} OpenABEHashFunctionType; + +// +// Default hash function is SHA256, but this can be +// overridden from build options +// + +#ifndef OpenABE_DEFAULT_HASH_FUNCTION_TYPE +#define OpenABE_DEFAULT_HASH_FUNCTION_TYPE HASH_FUNCTION_TYPE_SHA256 +#endif + +// forward declare GT (for now) +class GT; +// hashing GT elements into a bytestring +bool OpenABEUtilsHashToString(GT &input, uint32_t keyLen, + OpenABEByteString &result, + OpenABEHashFunctionType hashType = OpenABE_DEFAULT_HASH_FUNCTION_TYPE); +std::string OpenABEHashKey(const std::string attr_key); +// compute keyed hash +void OpenABEComputeHash(OpenABEByteString& key, OpenABEByteString& input, OpenABEByteString& output); +// generate a salted hash from the given password and store into the variable 'hash' +void generateHash(std::string& hash, const std::string& password); +// check password against a given 'salted hash' +bool checkPassword(const std::string& hash, const std::string& password); +// encrypt a given blob and password +OpenABE_ERROR encryptUnderPassword(const std::string password, OpenABEByteString &inputBlob, OpenABEByteString &encOutputBlob); +// decrypt a given blob using password +OpenABE_ERROR decryptUnderPassword(const std::string password, OpenABEByteString &inputCTBlob, OpenABEByteString &plainOutputBlob); + +/*! \brief Calculates a SHA-256 hash + * + * @param[in] value The value to digest + * @param[out] digest The digest + * @throws zeutro::crypto::CryptoException value is empty or an + * internal error occured + */ +void sha256ToHex(std::string& hex_digest, const std::string& value); +void sha256(std::string &digest, uint8_t *val, size_t val_len); +void sha256(uint8_t *digest, uint8_t *val, size_t val_len); +void sha256(std::string& digest, const std::string& value); + +} +#endif // __ZCRYPTOUTILS_H__ diff --git a/src/include/openabe/utils/zdriver.h b/src/include/openabe/utils/zdriver.h new file mode 100644 index 00000000..89d0cd1b --- /dev/null +++ b/src/include/openabe/utils/zdriver.h @@ -0,0 +1,205 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zdriver.h +/// +/// \brief Class definition for OpenABE policy parser. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZDRIVER_H__ +#define __ZDRIVER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define COLON ':' +#define FLEXINT "_flexint_" +#define EXPINT "_expint" +#define POLICY_PREFIX "[0]: " +#define ATTRLIST_PREFIX "[1]: " +#define ASSIGN_EQ "=" +#define MONTH_KEYWORD "month" +#define DAY_KEYWORD "day" +#define YEAR_KEYWORD "year" +#define TIME_KEYWORD "time" +#define EPOCH_YEAR 1970 + +#define MONTH_BITS 4 +#define DAY_BITS 8 +#define YEAR_BITS 16 + +static const uint32_t max_4bits = 0xf; +static const uint32_t max_8bits = 0xff; +static const uint32_t max_16bits = 0xffff; +static const uint32_t max_32bits = 0xffffffff; +//static const uint32_t max_64bits = 0xffffffffffffffff; + +/** The namespace is used to encapsulate the three parser classes + * oabe::Parser, oabe::Scanner and oabe::Driver */ +namespace oabe { + +class OpenABEPolicy; +class OpenABEAttributeList; +class OpenABETreeNode; +class OpenABEUInteger; +/** The Driver class brings together all components. It creates an instance of + * the Parser and Scanner classes and connects them. Then the input stream is + * fed into the scanner object and the parser gets it's token + * sequence. Furthermore the driver object is available in the grammar rules as + * a parameter. Therefore the driver class contains a reference to the + * structure into which the parsed data is saved. */ +class Driver { +public: + Driver(bool); + ~Driver(); + + /// enable debug output in the flex scanner + bool trace_scanning; + + /// enable debug output in the bison parser + bool trace_parsing; + + /// stream name (file or input stream) used for error messages. + std::string streamname; + + /** Invoke the scanner and parser for a stream. + * @param in input stream + * @param sname stream name for error messages + * @return true if successfully parsed + */ + bool parse_stream(std::istream& in, + const std::string& sname = "stream input"); + + /** Invoke the scanner and parser on an input string. + * @param input input string + * @param sname stream name for error messages + * @return true if successfully parsed + */ + bool parse_string(const std::string& prefix, const std::string& input, + const std::string& sname = "string stream"); + + /** Invoke the scanner and parser on a file. Use parse_stream with a + * std::ifstream if detection of file reading errors is required. + * @param filename input file name + * @return true if successfully parsed + */ + // bool parse_file(const std::string& filename); + + // To demonstrate pure handling of parse errors, instead of + // simply dumping them on the standard error output, we will pass + // them to the driver using the following two member functions. + + /** Error handling with associated line number. This can be modified to + * output the error e.g. to a dialog box. */ + void error(const class location& l, const std::string& m); + + /** General error handling. This can be modified to output the error + * e.g. to a dialog box. */ + // void error(const std::string& m); + + /** Pointer to the current lexer instance, this is used to connect the + * parser to the scanner. It is used in the yylex macro. */ + class Scanner* lexer; + + /* helper functions */ + std::unique_ptr getPolicy() { return std::move(this->final_policy); } + std::unique_ptr getAttributeList() { return std::move(this->final_attrlist); } + void set_policy(OpenABETreeNode *subtree); + void set_attrlist(std::vector *list); + OpenABETreeNode* leaf_node(const std::string &c); + bool parse_attribute(const std::string& c); + std::vector* leaf_attr(const std::string& c); + std::vector* concat_attr(std::vector *attr1, std::vector *attr2); + std::vector* attr_num(const std::string &c, OpenABEUInteger *number); + std::vector* set_date_in_attrlist(const std::string& prefix, const std::string& month, + OpenABEUInteger *m, OpenABEUInteger *d, OpenABEUInteger *y); + OpenABETreeNode* kof2_tree(int k, OpenABETreeNode *l, OpenABETreeNode *r); + OpenABETreeNode* kofn_tree(uint32_t threshold_k, std::vector& attributeList); + + OpenABEUInteger* create_expint(uint32_t value, uint16_t bits); + OpenABEUInteger* create_flexint(uint32_t value); + OpenABETreeNode* eq_policy(const std::string &c, OpenABEUInteger *number); + OpenABETreeNode* lt_policy(const std::string &c, OpenABEUInteger *number); + OpenABETreeNode* gt_policy(const std::string &c, OpenABEUInteger *number); + OpenABETreeNode* le_policy(const std::string &c, OpenABEUInteger *number); + OpenABETreeNode* ge_policy(const std::string &c, OpenABEUInteger *number); + OpenABETreeNode* range_policy(const std::string& c, OpenABEUInteger *min_num, OpenABEUInteger *max_num); + OpenABETreeNode* range_incl_policy(const std::string& c, OpenABEUInteger *min_num, OpenABEUInteger *max_num); + OpenABETreeNode* set_date_in_policy(const std::string& prefix, OpenABEUInteger *m, OpenABEUInteger *d, OpenABEUInteger *y); + OpenABETreeNode* gt_date_in_policy(const std::string& prefix, OpenABEUInteger *m, OpenABEUInteger *d, OpenABEUInteger *y); + OpenABETreeNode* ge_date_in_policy(const std::string& prefix, OpenABEUInteger *m, OpenABEUInteger *d, OpenABEUInteger *y); + OpenABETreeNode* lt_date_in_policy(const std::string& prefix, OpenABEUInteger *m, OpenABEUInteger *d, OpenABEUInteger *y); + OpenABETreeNode* le_date_in_policy(const std::string& prefix, OpenABEUInteger *m, OpenABEUInteger *d, OpenABEUInteger *y); + OpenABETreeNode* range_date_in_policy(const std::string& prefix, OpenABEUInteger *m, OpenABEUInteger *min_d, + OpenABEUInteger *max_d, OpenABEUInteger *y); + std::ostream& print(std::ostream &stream); + +private: + // counter for every attribute that occurs in the tree + std::map attr_count; + // records the subset of attributes that are indeed duplicated + std::set attr_dup, attr_prefix, date_prefix; + std::vector orig_attributes; + // store the original input (in case it includes comparison operators) + std::string original_input; + + bool debug, isPolicy; + std::unique_ptr final_policy; + std::unique_ptr final_attrlist; + // helper functions for non-numerical attributes + OpenABETreeNode* bit_marker_list(bool flex, bool gt, std::string attr, int bits, uint32_t value); + OpenABETreeNode* cmp_policy(OpenABEUInteger* number, bool gt, std::string attr); + OpenABETreeNode* flexint_leader(bool gt, std::string attr, uint32_t value); +}; + +std::pair check_attribute(const std::string& c); +uint32_t validate_date(const std::string& prefix, OpenABEUInteger *m, OpenABEUInteger *d, OpenABEUInteger *y); +void validate_range_date(const std::string& prefix, OpenABEUInteger *m, OpenABEUInteger *min_d, + OpenABEUInteger *max_d, OpenABEUInteger *y); +OpenABEUInteger* create_expint(uint32_t value, uint16_t bits); +OpenABEUInteger* create_flexint(uint32_t value); +bool checkValidBit(uint32_t value, uint32_t bits); +OpenABEUInteger* get_month(const std::string& month); +bool assign_stmt(std::vector &attributeList, const std::string &c, OpenABEUInteger &number); +std::string bit_marker(bool flex, std::string base, int bit, int val, int bit_count); +inline std::string MakeUniqueLabel(const std::string base, + const std::string keyword, + std::string unique) +{ + return base + "_" + keyword + "_" + unique; +} + +} + +#endif // __ZDRIVER_H__ diff --git a/src/include/openabe/utils/zerror.h b/src/include/openabe/utils/zerror.h new file mode 100644 index 00000000..2ee547b1 --- /dev/null +++ b/src/include/openabe/utils/zerror.h @@ -0,0 +1,112 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zerror.h +/// +/// \brief Error code definitions for the OpenABE. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZERROR_H__ +#define __ZERROR_H__ + +// +// Constants +// +namespace oabe { + +typedef enum _OpenABE_ERROR { + OpenABE_NOERROR = 0, + OpenABE_ERROR_INVALID_CONTEXT = 2, + OpenABE_ERROR_INVALID_CIPHERTEXT = 3, + OpenABE_ERROR_INVALID_GROUP_PARAMS = 4, + OpenABE_ERROR_INVALID_PARAMS = 5, + OpenABE_ERROR_INVALID_KEY = 6, + OpenABE_ERROR_OUT_OF_MEMORY = 7, + OpenABE_ERROR_INVALID_INPUT = 8, + OpenABE_ERROR_ENCRYPTION_ERROR = 9, + OpenABE_ERROR_UNKNOWN_SCHEME = 10, + OpenABE_ERROR_LIBRARY_NOT_INITIALIZED = 11, + OpenABE_ERROR_NO_SECRET_PARAMS = 12, + OpenABE_ERROR_NO_PUBLIC_PARAMS = 13, + OpenABE_ERROR_NOT_IMPLEMENTED = 14, + OpenABE_ERROR_BUFFER_TOO_SMALL = 15, + OpenABE_ERROR_WRONG_GROUP = 16, + OpenABE_ERROR_INVALID_PARAMS_ID = 17, + OpenABE_ERROR_ELEMENT_NOT_FOUND = 18, + OpenABE_ERROR_SECRET_SHARING_FAILED = 19, + OpenABE_ERROR_INVALID_POLICY = 20, + OpenABE_ERROR_INVALID_RNG = 21, + OpenABE_ERROR_SIGNATURE_FAILED = 22, + OpenABE_ERROR_WRONG_USER_PARAM = 23, + OpenABE_ERROR_INVALID_LENGTH = 24, + OpenABE_ERROR_SERIALIZATION_FAILED = 25, + OpenABE_ERROR_INVALID_LIBVERSION = 26, + OpenABE_ERROR_RAND_INSUFFICIENT = 27, + OpenABE_ERROR_UNEXPECTED_EXTRA_BYTES = 28, + OpenABE_ERROR_IN_USE_ALREADY = 29, + OpenABE_ERROR_INVALID_KEY_HEADER = 30, + OpenABE_ERROR_INVALID_CIPHERTEXT_HEADER = 31, + OpenABE_ERROR_DECRYPTION_FAILED = 32, + OpenABE_ERROR_VERIFICATION_FAILED = 33, + OpenABE_ERROR_DIVIDE_BY_ZERO = 34, + OpenABE_ERROR_CTR_DRB_NOT_INITIALIZED = 35, + OpenABE_ERROR_ELEMENT_NOT_INITIALIZED = 36, + OpenABE_ERROR_DESERIALIZATION_FAILED = 37, + OpenABE_ERROR_INVALID_CURVE_ID = 38, + OpenABE_ERROR_INVALID_SCHEME_ID = 39, + OpenABE_ERROR_INVALID_KEY_BODY = 40, + OpenABE_ERROR_INVALID_CIPHERTEXT_BODY = 41, + OpenABE_ERROR_SYNTAX_ERROR_IN_PARSER = 42, + OpenABE_ERROR_CLASS_NOT_INITIALIZED = 43, + OpenABE_ERROR_INVALID_PACK_TYPE = 44, + OpenABE_ERROR_INVALID_ATTRIBUTE_STRUCTURE = 45, + OpenABE_ERROR_INDEX_OUT_OF_BOUNDS = 46, + OpenABE_ERROR_MISSING_SENDER_PUBLIC_KEY = 47, + OpenABE_ERROR_MISSING_RECEIVER_PRIVATE_KEY = 48, + OpenABE_ERROR_MISSING_RECEIVER_PUBLIC_KEY = 49, + OpenABE_ERROR_MISSING_AUTHORITY_ID_IN_ATTR = 50, + OpenABE_ERROR_INVALID_ATTRIBUTE_LIST = 51, + OpenABE_ERROR_INVALID_RANGE_NUMBERS = 52, + OpenABE_ERROR_INVALID_MISMATCH_BITS = 53, + OpenABE_ERROR_INVALID_PREFIX_SPECIFIED = 54, + OpenABE_ERROR_INVALID_DATE_SPECIFIED = 55, + OpenABE_ERROR_INVALID_DATE_BEFORE_EPOCH = 56, + OpenABE_ERROR_ORDER_NOT_SPECIFIED = 57, + OpenABE_ERROR_INVALID_POLICY_TREE = 58, + OpenABE_ERROR_KEYGEN_FAILED = 59, + OpenABE_ERROR_NO_PLAINTEXT_SPECIFIED = 60, + OpenABE_ERROR_INVALID_TAG_LENGTH = 61, + OpenABE_ERROR_UNKNOWN = 99, + OpenABE_INVALID_INPUT_TYPE = 100 +} OpenABE_ERROR; + +const char* OpenABE_errorToString(OpenABE_ERROR error); + +} + +#endif // __ZERROR_H__ diff --git a/src/include/openabe/utils/zexception.h b/src/include/openabe/utils/zexception.h new file mode 100644 index 00000000..0557226c --- /dev/null +++ b/src/include/openabe/utils/zexception.h @@ -0,0 +1,79 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zexception.h +/// +/// \brief Convenience exception functionality +/// +/// \author Alan Dunn and J. Ayo Akinyele +/// + +#ifndef __ZEXCEPTION_H__ +#define __ZEXCEPTION_H__ + +#include +#include + +namespace oabe { + +/*! \brief Exception that improves ease of creating new exceptions + * + * New exceptions that want to have a message need only inherit from + * MessageException and call its constructor. See + * zeutro::crypto::CryptoException for example use. + */ +class MessageException : public std::exception { +public: + MessageException(const std::string& msg) : msg_(msg) {} + ~MessageException() throw () {} + + const char* what() const throw() { + return msg_.c_str(); + } + +protected: + std::string msg_; +}; + +class CryptoException : public MessageException { +public: + CryptoException(const std::string& msg) : + MessageException(msg) {} +}; + +/*! + * \brief Exception for the ZCryptoBox interface + */ +class ZCryptoBoxException : public MessageException { +public: + ZCryptoBoxException(const std::string& msg) : + MessageException(msg) {} +}; + + +} + +#endif diff --git a/src/include/openabe/utils/zfunctioninput.h b/src/include/openabe/utils/zfunctioninput.h new file mode 100644 index 00000000..a68524b2 --- /dev/null +++ b/src/include/openabe/utils/zfunctioninput.h @@ -0,0 +1,92 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zfunctioninput.h +/// +/// \brief Abstract base class for various kinds of function inputs. +/// This generalize attribute lists, policies, etc. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZFUNCTIONINPUT_H__ +#define __ZFUNCTIONINPUT_H__ + +#include +#include + +namespace oabe { + +class OpenABECiphertext; +/// @typedef OpenABEFunctionInputType +/// +/// @brief Enumerates constant values corresponding to given function +/// input types, e.g., policies, attribute lists. + +typedef enum _OpenABEFunctionInputType { + FUNC_INVALID_INPUT = 0, + FUNC_POLICY_INPUT = 1, + FUNC_ATTRLIST_INPUT = 2 +} OpenABEFunctionInputType; + +/// +/// @class OpenABEFunctionInput +/// +/// @brief Abstract base class for inputs to the Functional Encryption +/// schemes. This includes such data types as policies, attribute +/// lists, strings and DFA descriptions (for RLE). +/// + +class OpenABEFunctionInput : public ZObject { +protected: + OpenABEFunctionInputType m_Type; + std::set m_prefixSet; + +public: + // Constructors/destructors + OpenABEFunctionInput(); + virtual ~OpenABEFunctionInput() = 0; + bool includesPrefix(const std::string prefix) { + std::set::iterator it; + it = m_prefixSet.find(prefix); + // true if iterator ptr *not* at end of set + // otherwise, false + return (it != m_prefixSet.end()); + } + + const std::set& getPrefixSet() { return this->m_prefixSet; } + OpenABEFunctionInputType getFunctionType() const { return this->m_Type; } + virtual std::string toString() const = 0; + virtual std::string toCompactString() const = 0; +}; + +// perform deep copy of a function input +std::unique_ptr copyFunctionInput(const OpenABEFunctionInput& input); +std::unique_ptr getFunctionInput(OpenABECiphertext *ciphertext); + +} + +#endif /* ifdef __ZFUNCTIONINPUT_H__ */ diff --git a/src/include/openabe/utils/zinteger.h b/src/include/openabe/utils/zinteger.h new file mode 100644 index 00000000..07fd8280 --- /dev/null +++ b/src/include/openabe/utils/zinteger.h @@ -0,0 +1,140 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zinteger.h +/// +/// \brief Class definition files for integers. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZINTEGER_H__ +#define __ZINTEGER_H__ + +#ifndef openabe_ZObject_h +#include "zobject.h" +#endif + +#ifndef __ZCONSTANTS_H__ +#include "zconstants.h" +#endif + +#include "zbytestring.h" + +#include + +namespace oabe { + +/// \class OpenABEUInteger +/// \brief Generic container for unsigned integers. +class OpenABEUInteger : public ZObject { +public: + OpenABEUInteger(const OpenABEUInteger& val) { + this->m_Val = val.m_Val; + this->m_Bits = val.m_Bits; + } + // defines expressive integers + OpenABEUInteger(uint32_t val) { + this->m_Val = val; + this->m_Bits = 0; + } + // defines explicit integers + OpenABEUInteger(uint32_t val, uint16_t bits) { + this->m_Val = val; + this->m_Bits = bits; + } + + bool isFlexInt() { return (this->m_Bits == 0 || this->m_Bits == MAX_INT_BITS); } + OpenABEUInteger* clone() const { return new OpenABEUInteger(*this); } + uint32_t getVal() const { return this->m_Val; } + uint16_t getBits() const { return this->m_Bits; } + void setBits(uint16_t bits) { this->m_Bits = bits; } + friend std::ostream& operator<<(std::ostream& s, const OpenABEUInteger& z) { + OpenABEUInteger z2(z); + s << z2.m_Val; + if(z2.m_Bits > 0 && z2.m_Bits < MAX_INT_BITS) { + s << "#" << std::to_string(z2.m_Bits); + } + return s; + } + + OpenABEUInteger& operator+=(int x) { + this->m_Val = this->m_Val + x; + return *this; + } + + OpenABEUInteger& operator-=(int x) { + this->m_Val = this->m_Val - x; + return *this; + } + + void serialize(OpenABEByteString& result) const { + result.clear(); + // insert the type + result.insertFirstByte(OpenABE_ELEMENT_INT); + // pack the unsigned integer + uint32_t x = this->m_Val; + int bitLen = sizeof(uint32_t); + uint8_t b[sizeof(uint32_t)] = {0}; + for(int i = bitLen-1; i >= 0; i--) { + b[i] = (x & 0xFF); // record last byte + x >>= 8; // shift right by 8-bits + } + result.appendArray(b, bitLen); + } + + void deserialize(OpenABEByteString& input) { + uint32_t x = 0; + int bitLen = sizeof(uint32_t); + ASSERT(input.at(0) == OpenABE_ELEMENT_INT, OpenABE_ERROR_SERIALIZATION_FAILED); + for(int i = 1; i <= bitLen; i++) { + x <<= 8; // shift left by 8-bits + x += input.at(i); // add byte at position i + } + this->m_Val = x; + } + + bool isEqual(ZObject* z) const { + OpenABEUInteger *z1 = dynamic_cast(z); + if(z1 != NULL) { + return z1->getVal() == this->getVal() && z1->getBits() == this->getBits(); + } + return false; + } + + friend bool operator==(const OpenABEUInteger& x, const OpenABEUInteger& y) { + return x.getVal() == y.getVal() && x.getBits() == y.getBits(); + } + +private: + uint32_t m_Val; + uint16_t m_Bits; +}; + +} + +#endif // __ZINTEGER_H__ + diff --git a/src/include/openabe/utils/zkeymgr.h b/src/include/openabe/utils/zkeymgr.h new file mode 100644 index 00000000..e2737bb3 --- /dev/null +++ b/src/include/openabe/utils/zkeymgr.h @@ -0,0 +1,114 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zkeystore.h +/// +/// \brief Class definition for the OpenABE keystore. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZKEYMGR_H__ +#define __ZKEYMGR_H__ + +#include +#include +#include + +namespace oabe { + +struct _OpenABEMetadata { + /* add as many fields as necessary */ + std::string userId; + bool isCached, isExpired; + /* include creationDate, expirationDate, */ + /* attribute list or policy string */ + OpenABEFunctionInputType inputType; + std::unique_ptr input; + OpenABE_SCHEME schemeID; + OpenABECurveID curveID; + OpenABEByteString keyBlob; + uint64_t keyExpirationDate; +}; + +#define MAX_KEYS_PER_USER 20 +typedef std::shared_ptr<_OpenABEMetadata> OpenABEMetadata; + +struct OpenABEKeyQuery { + bool isEfficient, frequentlyAccessed; + uint64_t currentTime; + std::string userId; + /* add other search query ideas here -- + * advanced --> find key for subset of ciphertexts */ +}; + +/// \class ZKeystoreManager +/// \brief Keystore Manager class for OpenABEKeys. Stores keys and metadata +/// about the key + +class OpenABEKeystoreManager : OpenABEKeystore { +public: + OpenABEKeystoreManager(); + ~OpenABEKeystoreManager(); + + std::pair getKeyCommand(const std::string& userId, const std::string& keyID); + bool storeWithKeyIDCommand(const std::string& userId, const std::string keyID, + OpenABEByteString& keyBlob, uint64_t keyExpireDate, + bool canCacheKey = false); + const std::string storeWithKeyPrefixCommand(const std::string& userId, const std::string keyPrefix, + OpenABEByteString& keyBlob, uint64_t keyExpireDate, + bool canCacheKey = false); + + // tries to find a decryption key that can decrypt one ciphertext + const std::string searchKeyCommand(OpenABEKeyQuery* query, OpenABEFunctionInput *func_input); + // deletes keys that satisfy the query (excludes efficiency check though) + std::vector deleteKeyCommand(OpenABEKeyQuery* query); + + // set the passphrase (used to encrypt DB on disk) + void setPassphrase(const std::string& programId, const std::string& userId, const std::string& passphrase); + // get active user map + std::map getActiveUsers(); + int getUserKeyCount(const std::string& userId); + +protected: + std::vector filterKeys(const std::string& userId, OpenABEFunctionInputType type); + std::vector getKeyIds(const std::string& userId, uint64_t currentTime = 0); + void rankKeyAlgorithm(std::vector& keyIDs, OpenABEKeyQuery* query); + std::pair testAKey(OpenABEMetadata& key, OpenABEFunctionInput* funcInput); + std::mutex ks_lock_; + const std::string searchKey(OpenABEKeyQuery* query, OpenABEFunctionInput *funcInput); + std::map keyMetadata_; + std::map keyCounter_; + std::map keyPassphrase_, activeUsers_; + std::map keyLoaded_; +}; + +std::unique_ptr getFunctionInput(OpenABEKey *key); +OpenABEFunctionInputType getFunctionInputType(OpenABEKey *key); + +} + +#endif // __ZKEYMGR_H__ diff --git a/src/include/openabe/utils/zpolicy.h b/src/include/openabe/utils/zpolicy.h new file mode 100644 index 00000000..3fafdf43 --- /dev/null +++ b/src/include/openabe/utils/zpolicy.h @@ -0,0 +1,198 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zpolicy.h +/// +/// \brief Class definition for OpenABE policy which is a subclass +/// of OpenABEFunctionInput (represents ABE policies). +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZPOLICY_H__ +#define __ZPOLICY_H__ + +#include +#include +#include +#include + +#include "openabe/zobject.h" +#include "openabe/utils/zfunctioninput.h" + +namespace oabe { + +// forward declare +class OpenABEByteString; +#define PREFIX_SEP ':' + +typedef enum _zGateType { + GATE_TYPE_NONE = 0, + GATE_TYPE_LEAF, + GATE_TYPE_AND, + GATE_TYPE_OR, + GATE_TYPE_THRESHOLD, + GATE_TYPE_XOR, + GATE_TYPE_NOT, + GATE_TYPE_NAND, + GATE_TYPE_NOR, + GATE_TYPE_XNOR +} zGateType; + +/// +/// @class OpenABETreeNode +/// +/// @brief Helper class that describes a single node in a policy tree. +/// + +class OpenABETreeNode : public ZObject { +protected: + zGateType m_nodeType; + uint32_t m_thresholdValue; + uint32_t m_numSubnodes; + bool m_Mark; + int m_Satisfied; + std::vector m_Subnodes; + std::string m_Prefix; + std::string m_Label; + int m_Index; + +public: + // Constructors/destructors + OpenABETreeNode(); + OpenABETreeNode(std::string label, std::string prefix = "", int index = 0); + OpenABETreeNode(OpenABETreeNode *copy); + ~OpenABETreeNode(); + bool m_Visited; + + uint32_t getNumSubnodes() { return this->m_Subnodes.size(); } + const bool getMark() const { return this->m_Mark; } + const int getNumSatisfied() const { return this->m_Satisfied; } + bool setMark(bool mark, int satisfied) { + this->m_Mark = mark; + this->m_Satisfied = satisfied; + return mark; + } + const uint32_t getNodeType() const { return this->m_nodeType; } + void setNodeType(zGateType type) { this->m_nodeType = type; } + OpenABETreeNode* getSubnode(uint32_t index); + + void addSubnode(OpenABETreeNode* subnode); + void setLabel(const std::string label) { this->m_Label = label; } + const std::string& getPrefix() const { return this->m_Prefix; } + const std::string& getLabel() const { return this->m_Label; } + const std::string getCompleteLabel() const { + if(this->m_Prefix != "") { + std::string full_label(this->m_Prefix + PREFIX_SEP); + full_label += this->m_Label; + return full_label; + } else { + return this->m_Label; + } + } + const int getIndex() const { return this->m_Index; } + void setThresholdValue(uint32_t k) { if (this->m_Subnodes.size() > 0) { this->m_thresholdValue = k; } } + uint32_t getThresholdValue(); + std::string toString(); +}; + +/// +/// @class OpenABEPolicy +/// +/// @brief Subclass of OpenABEFunctionInput that represents ABE policies. +/// + +class OpenABEPolicy : public OpenABEFunctionInput { +protected: + std::unique_ptr m_rootNode; + bool m_hasDuplicates, m_enabledRevocation; + std::map m_attrDuplicateCount; + std::set m_attrCompleteSet; + std::string m_originalInputString; + +public: + // Constructors/destructors + OpenABEPolicy(); + OpenABEPolicy(const OpenABEPolicy ©); + virtual ~OpenABEPolicy(); + + void setRootNode(OpenABETreeNode* subtree); + OpenABETreeNode *getRootNode() const { return this->m_rootNode.get(); } + OpenABEPolicy* clone() const { return new OpenABEPolicy(*this); } + void serialize(OpenABEByteString &result) const; + bool isEqual(ZObject* z) const { + return false; + } + OpenABEPolicy& operator=(const OpenABEPolicy &rhs); + std::string toString() const { + return this->m_rootNode->toString(); + } + void setCompactString(const std::string& input) { + m_originalInputString = input; + } + std::string toCompactString() const { + return m_originalInputString; + } + + // methods for storing/retrieving duplicate node info + bool hasDuplicateNodes() const { return this->m_hasDuplicates; } + void setDuplicateInfo(std::map& attr_count, std::set& attr_list); + void setPrefixSet(std::set& prefix_set); + void getDuplicateInfo(std::map& attr_count) const { + attr_count = this->m_attrDuplicateCount; + } + bool getRevocationStatus() { return this->m_enabledRevocation; } + void enableRevocation() { this->m_enabledRevocation = true; } + + std::set& getAttrCompleteSet() { + return this->m_attrCompleteSet; + } + +#if 0 + void ConstructTestPolicy(); +#endif + friend std::ostream& operator<<(std::ostream& s, const OpenABEPolicy& z) { + s << z.getRootNode()->toString(); + return s; + } + + void deserialize(const OpenABEByteString &input); +}; + +// split a string based on a delimiter and return a vector +std::vector split(const std::string &s, char delim); +// print the string of the internal tree node gate +const char* OpenABETreeNode_ToString(zGateType type); +std::unique_ptr createPolicyTree(std::string s); +// reset all the flags in a policy tree +bool resetFlags(OpenABETreeNode *root); +// use to add an attribute at the OpenABEPolicy structure +std::unique_ptr addToRootOfInput( + zGateType type, + const std::string attribute, OpenABEPolicy* policy); +} + +#endif /* ifdef __ZPOLICY_H__ */ diff --git a/src/include/openabe/utils/zscanner.h b/src/include/openabe/utils/zscanner.h new file mode 100644 index 00000000..b26768e0 --- /dev/null +++ b/src/include/openabe/utils/zscanner.h @@ -0,0 +1,91 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zscanner.h +/// +/// \brief Class definition for zpolicy scanner. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZSCANNER_H__ +#define __ZSCANNER_H__ + +// Flex expects the signature of yylex to be defined in the macro YY_DECL, and +// the C++ parser expects it to be declared. We can factor both as follows. + +#ifndef YY_DECL + +#define YY_DECL \ + oabe::Parser::token_type \ + oabe::Scanner::lex( \ + oabe::Parser::semantic_type* yylval, \ + oabe::Parser::location_type* yylloc \ + ) +#endif + +#ifndef __FLEX_LEXER_H +#define yyFlexLexer OpenABEFlexLexer +#include +#undef yyFlexLexer +#endif + +#include + +#define EXPINT_KEYWORD "expint" + +namespace oabe { + +/** Scanner is a derived class to add some extra function to the scanner + * class. Flex itself creates a class named yyFlexLexer, which is renamed using + * macros to ZtkFlexLexer. However we change the context of the generated + * yylex() function to be contained within the Scanner class. This is required + * because the yylex() defined in ZtkFlexLexer has no parameters. */ +class Scanner : public OpenABEFlexLexer +{ +public: + /** Create a new scanner object. The streams arg_yyin and arg_yyout default + * to cin and cout, but that assignment is only made when initializing in + * yylex(). */ + Scanner(std::istream* arg_yyin = 0, + std::ostream* arg_yyout = 0); + + /** Required for virtual functions */ + virtual ~Scanner(); + + /** This is the main lexing function. It is generated by flex according to + * the macro declaration YY_DECL above. The generated bison parser then + * calls this virtual function to fetch new tokens. */ + virtual Parser::token_type lex(Parser::semantic_type* yylval, + Parser::location_type* yylloc); + + /** Enable debug output (via arg_yyout) if compiled into the scanner. */ + void set_debug(bool b); +}; + +} // namespace oabe + +#endif // OpenABE_SCANNER_H diff --git a/src/include/openabe/utils/zx509.h b/src/include/openabe/utils/zx509.h new file mode 100644 index 00000000..a7747c50 --- /dev/null +++ b/src/include/openabe/utils/zx509.h @@ -0,0 +1,194 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zx509.h +/// +/// \brief X.509 certificate handling functionality +/// +/// \author Alan Dunn and J. Ayo Akinyele +/// + +#ifndef __ZX509__ +#define __ZX509__ + +#include +#include +#include +#include + +/* All this functionality assumes the OpenSSL library has already been + initialized */ +#define SERIAL_BITS 128 +#define DAYS 30 +#define CRL_UPDATE_SCHED DAYS*24*60*60 + +namespace oabe { + +class KeyCertifier; +class DistinguishedName { +public: + DistinguishedName(); + ~DistinguishedName(); + + static void makeDistinguishedName( + DistinguishedName& dn, + const std::vector>& rdnPairs); + +private: + class Impl; + std::unique_ptr ptr_; + + friend class KeyCertifier; +}; + +/*! \brief Generate X509 certificates for public signature keys + */ +class KeyCertifier { +public: + /*! \brief Create a certifier from a private key + * + * @param[out] certifier The resultant key certifier + * @param[in] privateKey A private key previously generated by a + * zeutro::crypto::SignatureKeypairGenerator + * @throws zeutro::crypto::CryptoException if key is misformatted + */ + static void fromKeyString(KeyCertifier& certifier, + const std::string& privateKey); + + // Note: 1461 days = 4 * 365 days + 1 day for a leap year. This + // makes the default validity a fixed number of years without + // having to figure out the right number of days based on the + // current year. + + /*! \brief Generate a signed certificate for a public key + * + * @param[out] cert A PEM-encoded X509 certificate certifying + * publicKey + * @param[in] publicKey A public key previously generated by a + * zeutro::crypto::SignatureKeypairGenerator + * @param[in] commonName A common name to use in the subject in + * the resultant X509 certificate (i.e. for + * identifying the different certificates) + * @param[in] daysValid The number of days from the current time + * at which the certificate should be set to + * expire + */ + void generateCertificate(std::string& cert, + const std::string& publicKey, + const std::string& commonName, + int daysValid=1461); + + /*! \brief Generate a signed certificate for a public key + * + * @param[out] cert A PEM-encoded X509 certificate certifying + * publicKey + * @param[in] publicKey A public key previously generated by a + * zeutro::crypto::SignatureKeypairGenerator + * @param[in] issuerDn The distinguished name of the certificate + * issuer + * @param[in] subjectDn The distinguished name of the certificate + * subject + * @param[in] daysValid The number of days from the current time + * at which the certificate should be set to + * expire + */ + void generateCertificate(std::string& cert, + const std::string& publicKey, + const DistinguishedName& issuerDn, + const DistinguishedName& subjectDn, + int daysValid=1461); + + ~KeyCertifier(); + +protected: + EVP_PKEY* privateKey_; + + static bool addDnToX509Name(const DistinguishedName& dn, + X509_NAME* name); +}; + +/*! \brief Generate self-signed CA certificate that serves as signer + * for all certificates generated from KeyCertifiers + * + * @param[out] cert A PEM-encoded X509 certificate certifying the + * public portion of privateKey + * @param[in] privateKey A private key previously generated by a + * zeutro::crypto::SignatureKeypairGenerator + * @param[in] daysValid The number of days from the current time + * at which the certificate should be set to + * expire + */ +void certifyKeyAsCA(std::string& cert, + const std::string& privateKey, + int daysValid=1461); + +/*! \brief Get the first common name in the subject out of a + * certificate + * + * @param[out] commonName set to common name as a UTF-8 string + * @return 1 if OK and common name returned, 0 if no common name, -1 on error + */ +int getFirstSubjectCommonName(std::string &commonName, X509* cert); + +/*! \brief Get the serial number of a certificate + * + * @param[out] serialNumber set to the serial number as a byte string + * @return 1 if OK and serial number returned, 0 if no serial number, -1 on error + */ +int getSerialNumber(OpenABEByteString& serial, X509* cert); + +/*! \brief Generate X509 certificate revocation list management + */ +class CertRevList { +public: + CertRevList(const std::string& crl_path); + ~CertRevList(); + + void setStartCrlNumber(int crlNumber) { + crlNumber_ = crlNumber; + } + + void createNewCrl(const std::string& ca_cert, const std::string& ca_privKey); + bool loadCrlFile(); + bool revokeCertificate(const std::string& client_cert); + + bool isRevoked(const std::string& client_cert); + bool isRevoked(X509 *cert); + bool loadRevokedList(); + +private: + std::string crl_path_; + X509_CRL* crl_; + long int crlNumber_; + + void writeCrlFile(); + std::vector revList_; + bool revListSet_; +}; + +} + +#endif diff --git a/src/include/openabe/zcontext.h b/src/include/openabe/zcontext.h new file mode 100644 index 00000000..92d4474d --- /dev/null +++ b/src/include/openabe/zcontext.h @@ -0,0 +1,78 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontext.h +/// +/// \brief Abstract base class for encryption scheme contexts. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZCONTEXT_H__ +#define __ZCONTEXT_H__ + +namespace oabe { + +class OpenABEEllipticCurve; +class OpenABEPairing; +class OpenABEKeystore; + +/// @class OpenABEContext +/// +/// @brief Main context class for Zeutro toolkit. This class contains all state related +/// to a given scheme. Applications may initialize as many OpenABEContext instances +/// as they wish. +/// + +class OpenABEContext : public ZObject { +protected: + std::unique_ptr m_RNG_; + std::unique_ptr m_Pairing_; + std::unique_ptr m_EllipticCurve_; + std::unique_ptr m_Keystore_; + OpenABESecurityLevel m_SecurityLevel; + OpenABE_SCHEME algID; + +public: + // Constructors/destructors + OpenABEContext(); + virtual ~OpenABEContext(); + + // Main functions + OpenABEKeystore *getKeystore() { return this->m_Keystore_.get(); } + OpenABERNG *getRNG() { return this->m_RNG_.get(); } + // extract higher-level group objects + OpenABEPairing *getPairing() { return this->m_Pairing_.get(); } + OpenABEEllipticCurve *getECCurve() { return this->m_EllipticCurve_.get(); } + + OpenABE_SCHEME getAlgorithmID() { return this->algID; } + virtual OpenABE_ERROR initializeCurve(const std::string groupParams) = 0; + OpenABE_ERROR loadUserSecretParams(const std::string &skID, const std::string &sk); +}; + +} + +#endif // __ZCONTEXT_H__ diff --git a/src/include/openabe/zcontextabe.h b/src/include/openabe/zcontextabe.h new file mode 100644 index 00000000..0f622e33 --- /dev/null +++ b/src/include/openabe/zcontextabe.h @@ -0,0 +1,116 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextabe.h +/// +/// \brief Base class definition for OpenABE context ABE schemes +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZCONTEXTABE_H__ +#define __ZCONTEXTABE_H__ + +/// +/// @class OpenABEContextABE +/// +/// @brief Abstract class for ABE-KEM scheme. +/// +namespace oabe { + +class OpenABEContextABE : public OpenABEContext { +public: + // Constructors/destructors + OpenABEContextABE(); + ~OpenABEContextABE(); + + OpenABE_ERROR initializeCurve(const std::string groupParams); + void setSchemeType(OpenABE_SCHEME scheme_type) { this->algID = scheme_type; } + OpenABE_SCHEME getSchemeType() { return this->algID; } +// virtual OpenABE_ERROR generateParams(OpenABESecurityLevel securityLevel, +// const std::string &mpkID, const std::string &mskID) = 0; + virtual OpenABE_ERROR generateParams(const std::string groupParams, + const std::string &mpkID, const std::string &mskID) = 0; + virtual OpenABE_ERROR generateDecryptionKey(OpenABEFunctionInput *keyInput, const std::string &keyID, + const std::string &mpkID, const std::string &mskID, + const std::string &gpkID="", const std::string &GID="") = 0; + virtual OpenABE_ERROR encryptKEM(OpenABERNG *rng, const std::string &mpkID, const OpenABEFunctionInput *encryptInput, + uint32_t keyByteLen, const std::shared_ptr& key, + OpenABECiphertext *ciphertext) = 0; + virtual OpenABE_ERROR decryptKEM(const std::string &mpkID, const std::string &keyID, OpenABECiphertext *ciphertext, + uint32_t keyByteLen, const std::shared_ptr& key) = 0; +}; + + +/// +/// @class OpenABEContextScheme +/// +/// @brief ABE scheme context for CPA security. +/// Specifically, provides support for CP-, KP- and MA-ABE schemes +/// + +class OpenABEContextSchemeCPA : public ZObject { +private: + OpenABE_ERROR loadKey(const std::string &ID, OpenABEByteString &keyBlob, zKeyType keyType); + bool isMAABE; + +protected: + std::unique_ptr m_KEM_; + +public: + OpenABEContextSchemeCPA(std::unique_ptr kem_); + ~OpenABEContextSchemeCPA(); + + void setSchemeType(OpenABE_SCHEME scheme_type) { this->m_KEM_->setSchemeType(scheme_type); } + OpenABE_SCHEME getSchemeType() { return this->m_KEM_->getSchemeType(); } + + OpenABEByteString* getHashKey(const std::string &mpkID); + OpenABE_ERROR exportKey(const std::string &keyID, OpenABEByteString &keyBlob); + OpenABE_ERROR loadMasterPublicParams(const std::string &mpkID, OpenABEByteString &mpkBlob); + OpenABE_ERROR loadMasterSecretParams(const std::string &mskID, OpenABEByteString &mskBlob); + OpenABE_ERROR loadUserSecretParams(const std::string &skID, OpenABEByteString &skBlob); + OpenABE_ERROR deleteKey(const std::string keyID); + bool checkSecretKey(const std::string keyID); + + OpenABE_ERROR generateParams(OpenABESecurityLevel securityLevel, + const std::string &mpkID, const std::string &mskID); + OpenABE_ERROR generateParams(const std::string groupParams, + const std::string &mpkID, const std::string &mskID); + // Methods iff KEM is MA-ABE + OpenABE_ERROR generateGlobalParams(const std::string groupParams, const std::string &gpkID); + OpenABE_ERROR generateAuthorityParams(const std::string &gpkID, const std::string &auth_mpkID, const std::string &auth_mskID); + + OpenABE_ERROR keygen(OpenABEFunctionInput *keyInput, const std::string &keyID, const std::string &mpkID, + const std::string &mskID, const std::string &gpkID="", const std::string &GID=""); + OpenABE_ERROR encrypt(OpenABERNG *rng, const std::string &mpkID, const OpenABEFunctionInput *encryptInput, + OpenABEByteString *plaintext, OpenABECiphertext *ciphertext); + OpenABE_ERROR decrypt(const std::string &mpkID, const std::string &keyID, + OpenABEByteString *plaintext, OpenABECiphertext *ciphertext); +}; + +} + +#endif /* ifdef __ZCONTEXTABE_H__ */ diff --git a/src/include/openabe/zcontextcca.h b/src/include/openabe/zcontextcca.h new file mode 100644 index 00000000..35dcb942 --- /dev/null +++ b/src/include/openabe/zcontextcca.h @@ -0,0 +1,192 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextcca.h +/// +/// \brief Base class implementation for OpenABE context CCA schemes +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZCONTEXTCCA_H__ +#define __ZCONTEXTCCA_H__ + +/// +/// @class OpenABEContextCCA +/// +/// @brief Abstract class for ABE KEM context (CCA security). +/// +namespace oabe { + +class OpenABEContextCCA : public OpenABEContextABE { +protected: + std::unique_ptr abeSchemeContext; + +public: + // Constructors/destructors + OpenABEContextCCA(std::unique_ptr scheme_); + ~OpenABEContextCCA(); + void setSchemeType(OpenABE_SCHEME scheme_type) { this->abeSchemeContext->setSchemeType(scheme_type); } + OpenABE_SCHEME getSchemeType() { return this->abeSchemeContext->getSchemeType(); } + +// virtual OpenABE_ERROR generateParams(OpenABESecurityLevel securityLevel, +// const std::string &mpkID, const std::string &mskID) = 0; + virtual OpenABE_ERROR generateParams(const std::string groupParams, + const std::string &mpkID, const std::string &mskID) = 0; + + // Methods iff KEM is MA-ABE + OpenABE_ERROR generateGlobalParams(const std::string groupParams, const std::string &gpkID); + OpenABE_ERROR generateAuthorityParams(const std::string &gpkID, const std::string &auth_mpkID, const std::string &auth_mskID); + + // export and import methods + OpenABEByteString* getHashKey(const std::string &mpkID); + OpenABE_ERROR exportKey(const std::string &keyID, OpenABEByteString &keyBlob); + OpenABE_ERROR loadMasterPublicParams(const std::string &mpkID, OpenABEByteString &mpkBlob); + OpenABE_ERROR loadMasterSecretParams(const std::string &mskID, OpenABEByteString &mskBlob); + OpenABE_ERROR loadUserSecretParams(const std::string &skID, OpenABEByteString &skBlob); + OpenABE_ERROR deleteKey(const std::string keyID); + bool checkSecretKey(const std::string keyID); +}; + +/// +/// @class OpenABEContextGenericCCA +/// +/// @brief A generic transformation that converts a CPA-secure ABE scheme +/// into one that is CCA-secure. +/// + +class OpenABEContextGenericCCA : public OpenABEContextCCA { +public: + // Constructors/destructors + OpenABEContextGenericCCA(std::unique_ptr scheme); + ~OpenABEContextGenericCCA(); + +// OpenABE_ERROR generateParams(OpenABESecurityLevel securityLevel, +// const std::string &mpkID, const std::string &mskID); + OpenABE_ERROR generateParams(const std::string groupParams, + const std::string &mpkID, const std::string &mskID); + OpenABE_ERROR generateDecryptionKey(OpenABEFunctionInput *keyInput, const std::string &keyID, + const std::string &mpkID, const std::string &mskID, + const std::string &gpkID="", const std::string &GID=""); + OpenABE_ERROR encryptKEM(OpenABERNG *rng, const std::string &mpkID, const OpenABEFunctionInput *encryptInput, + uint32_t keyByteLen, const std::shared_ptr& key, OpenABECiphertext *ciphertext); + OpenABE_ERROR decryptKEM(const std::string &mpkID, const std::string &keyID, + OpenABECiphertext *ciphertext, uint32_t keyByteLen, const std::shared_ptr& key); +}; + + +/// +/// @class OpenABEContextSchemeCCA +/// +/// @brief ABE scheme context for CCA security. +/// + +class OpenABEContextSchemeCCA : public ZObject { +protected: + std::unique_ptr m_KEM_; + +public: + OpenABEContextSchemeCCA(std::unique_ptr kem_); + ~OpenABEContextSchemeCCA(); + + OpenABEKeystore *getKeystore() const { return this->m_KEM_->getKeystore(); } + OpenABE_SCHEME getSchemeType() const { return this->m_KEM_->getSchemeType(); } + + OpenABE_ERROR exportKey(const std::string &keyID, OpenABEByteString &keyBlob); + OpenABE_ERROR loadMasterPublicParams(const std::string &mpkID, OpenABEByteString &mpkBlob); + OpenABE_ERROR loadMasterSecretParams(const std::string &mskID, OpenABEByteString &mskBlob); + OpenABE_ERROR loadUserSecretParams(const std::string &skID, OpenABEByteString &skBlob); + OpenABE_ERROR deleteKey(const std::string keyID); + bool checkSecretKey(const std::string keyID); + +// OpenABE_ERROR generateParams(OpenABESecurityLevel securityLevel, +// const std::string &mpkID, const std::string &mskID); + OpenABE_ERROR generateParams(const std::string groupParams, + const std::string &mpkID, const std::string &mskID); + // Methods iff KEM is MA-ABE + OpenABE_ERROR generateGlobalParams(const std::string groupParams, const std::string &gpkID); + OpenABE_ERROR generateAuthorityParams(const std::string &gpkID, const std::string &auth_mpkID, + const std::string &auth_mskID); + + OpenABE_ERROR keygen(OpenABEFunctionInput *keyInput, const std::string &keyID, const std::string &mpkID, + const std::string &mskID, const std::string &gpkID="", + const std::string &GID=""); + OpenABE_ERROR encrypt(const std::string& mpkID, const OpenABEFunctionInput *encryptInput, + const std::string& plaintext, OpenABECiphertext *ciphertext1, OpenABECiphertext *ciphertext2); + OpenABE_ERROR decrypt(const std::string &mpkID, const std::string &keyID, std::string& plaintext, + OpenABECiphertext *ciphertext1, OpenABECiphertext *ciphertext2); +}; + +/// +/// @class OpenABEContextSchemeCCAWithATZN +/// +/// @brief ABE scheme context for CCA security (for amortized ABE). +/// + +class OpenABEContextSchemeCCAWithATZN : public ZObject { +protected: + std::unique_ptr m_KEM_; + +public: + OpenABEContextSchemeCCAWithATZN(std::unique_ptr kem_); + ~OpenABEContextSchemeCCAWithATZN(); + + OpenABEKeystore *getKeystore() const { return this->m_KEM_->getKeystore(); } + OpenABE_SCHEME getSchemeType() const { return this->m_KEM_->getSchemeType(); } + + OpenABE_ERROR exportKey(const std::string &keyID, OpenABEByteString &keyBlob); + OpenABE_ERROR loadMasterPublicParams(const std::string &mpkID, OpenABEByteString &mpkBlob); + OpenABE_ERROR loadMasterSecretParams(const std::string &mskID, OpenABEByteString &mskBlob); + OpenABE_ERROR loadUserSecretParams(const std::string &skID, OpenABEByteString &skBlob); + OpenABE_ERROR deleteKey(const std::string keyID); + bool checkSecretKey(const std::string keyID); + +// OpenABE_ERROR generateParams(OpenABESecurityLevel securityLevel, +// const std::string &mpkID, +// const std::string &mskID); + OpenABE_ERROR generateParams(const std::string groupParams, + const std::string &mpkID, + const std::string &mskID); + // Methods iff KEM is MA-ABE + OpenABE_ERROR generateGlobalParams(const std::string groupParams, const std::string &gpkID); + OpenABE_ERROR generateAuthorityParams(const std::string &gpkID, + const std::string &auth_mpkID, + const std::string &auth_mskID); + + OpenABE_ERROR keygen(OpenABEFunctionInput *keyInput, const std::string &keyID, const std::string &mpkID, + const std::string &mskID, const std::string &gpkID="", const std::string &GID=""); + std::unique_ptr encrypt(const std::string& mpkID, + const OpenABEFunctionInput *encryptInput, + OpenABECiphertext *ciphertext); + std::unique_ptr decrypt(const std::string &mpkID, + const std::string &keyID, + OpenABECiphertext *ciphertext); +}; + + +} + +#endif /* ifdef __ZCONTEXTCCA_H__ */ diff --git a/src/include/openabe/zcrypto_box.h b/src/include/openabe/zcrypto_box.h new file mode 100644 index 00000000..a4b41074 --- /dev/null +++ b/src/include/openabe/zcrypto_box.h @@ -0,0 +1,202 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcrypto_box.h +/// +/// \brief Thin context wrappers for PKE/PKSIG/ABE (without any advanced features) +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZCRYPTO_BOX__ +#define __ZCRYPTO_BOX__ + +#include +#include + +namespace oabe { + +typedef std::unique_ptr OpenABESymKeyHandlePtr; + +class OpenABECryptoContextBase { +public: + // generate system parameters for default curve selected. + virtual void generateParams() = 0; + virtual void enableKeyManager(const std::string userId) = 0; + + // for CP/KP-ABE + virtual void exportPublicParams(std::string &mpk) = 0; + virtual void exportSecretParams(std::string &msk) = 0; + virtual void importPublicParams(const std::string &keyBlob) = 0; + virtual void importSecretParams(const std::string &keyBlob) = 0; + + // for multi-authority (allow import per authID) + virtual void importPublicParams(const std::string &authID, + const std::string &keyBlob) = 0; + + virtual void importSecretParams(const std::string &authID, + const std::string &keyBlob) = 0; + virtual void importUserKey(const std::string &keyID, + const std::string &keyBlob) = 0; + + virtual void exportUserKey(const std::string &keyID, + std::string &keyBlob) = 0; + virtual bool deleteKey(const std::string &keyID) = 0; +}; + +/*! + * A crypto_box interface for attribute-based encryption. + * Scheme-ID options: "CP-ABE", "KP-ABE", and "MA-ABE". + * Note: This context is CCA-secure by default + * Example usage: + * OpenABECryptoContext cpabe("CP-ABE"); + * cpabe.generateParams(); + * cpabe.keygen("attr1|attr2", "key0"); + * string ct, pt1 = "message", pt2; + * cpabe.encrypt("attr1 and attr2", pt1, ct); + * bool res = cpabe.decrypt("key0", ct, pt2); + * assert(res && pt1 == pt2); + */ +class OpenABECryptoContext : public OpenABECryptoContextBase { +public: + OpenABECryptoContext(const std::string scheme_id, bool base64encode = true); + virtual ~OpenABECryptoContext() {}; + // generate system parameters for default curve selected. + void generateParams(); + void enableKeyManager(const std::string userId); + void enableVerbose(); + + // import/export various params and keys (for multi-authority) + void exportGlobalParams(std::string &globlmpk); + void importGlobalParams(const std::string &keyBlob); + + // for CP/KP-ABE + void exportPublicParams(std::string &mpk); + void exportSecretParams(std::string &msk); + void importPublicParams(const std::string &keyBlob); + void importSecretParams(const std::string &keyBlob); + + // for multi-authority (allow import per authID) + void importPublicParams(const std::string &authID, + const std::string &keyBlob); + + void importSecretParams(const std::string &authID, + const std::string &keyBlob); + void importUserKey(const std::string &keyID, const std::string &keyBlob); + void exportUserKey(const std::string &keyID, std::string &keyBlob); + bool deleteKey(const std::string &keyID); + + void keygen(const std::string &keyInput, const std::string &keyID, + const std::string &authID = "", const std::string &GID = ""); + void encrypt(const std::string encInput, const std::string &plaintext, + std::string &ciphertext); + bool decrypt(const std::string &keyID, const std::string &ciphertext, + std::string &plaintext); + bool decrypt(const std::string &ciphertext, std::string &plaintext); + +private: + std::string userId_; + std::unique_ptr schemeContextCCA_; + std::unique_ptr keyManager_; + OpenABE_SCHEME scheme_type_; + OpenABEFunctionInputType keyInputType_, encInputType_; + bool base64Encode_, debug_, useKeyManager_; +}; + +/*! + * A crypto_box interface for public-key encryption + * (i.e., One-pass DH in Sec 6.2.2.2 of NIST SP800-56A) + * Example usage: + * OpenPKEContext pke; + * pke.keygen("user0"); + * string pt = "message", ct; + * pke.encrypt("user0", pt1, ct); + * bool res = pke.decrypt("user0", ct, pt2); + * assert(res && pt1 == pt2); + */ +class OpenPKEContext { +public: + OpenPKEContext(const std::string ec_id = "NIST_P256", bool base64encode = true); + virtual ~OpenPKEContext() {}; + + void exportPublicKey(const std::string key_id, std::string &keyBlob); + void exportPrivateKey(const std::string key_id, std::string &keyBlob); + + void importPublicKey(const std::string key_id, const std::string &keyBlob); + void importPrivateKey(const std::string key_id, const std::string &keyBlob); + + void keygen(const std::string key_id); + bool encrypt(const std::string receiver_id, const std::string &plaintext, + std::string &ciphertext); + bool decrypt(const std::string receiver_id, const std::string &ciphertext, + std::string &plaintext); + +private: + std::unique_ptr schemeContext_; + std::string ec_id_; + bool base64Encode_; +}; + +/*! + * A crypto_box interface for digital signatures (e.g., NIST EC-DSA) + * Example usage: + * OpenPKSIGContext pksig; + * pksig.keygen("user1"); + * pksig.sign("user1", msg, sig); + * bool res = pksig.verify("user1", msg, sig); + * assert(res); + */ +class OpenPKSIGContext { +public: + OpenPKSIGContext(const std::string ec_id = "NIST_P256", bool base64encode = true); + virtual ~OpenPKSIGContext() {}; + + void exportPublicKey(const std::string key_id, std::string &keyBlob); + void exportPrivateKey(const std::string key_id, std::string &keyBlob); + + void importPublicKey(const std::string key_id, const std::string &keyBlob); + void importPrivateKey(const std::string key_id, const std::string &keyBlob); + + void keygen(const std::string key_id); + void sign(const std::string key_id, const std::string &message, + std::string &signature); + bool verify(const std::string key_id, const std::string &message, + const std::string &signature); + +private: + std::unique_ptr schemeContext_; + std::string ec_id_; + bool base64Encode_; +}; + + +// helper methods to help with using the keystore +//std::pair SearchKeyStore(OpenABEKeystoreManager& key_manager, std::string& id, std::string& ciphertext); + +} + +#endif // __ZCRYPTO_BOX__ + diff --git a/src/include/openabe/zml/zelement.h b/src/include/openabe/zml/zelement.h new file mode 100644 index 00000000..a89533b9 --- /dev/null +++ b/src/include/openabe/zml/zelement.h @@ -0,0 +1,343 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zelement.h +/// +/// \brief Base class definition for ZTK groups (EC/pairings) +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZELEMENT_H__ +#define __ZELEMENT_H__ + +#if defined(BP_WITH_OPENSSL) +#define EC_WITH_OPENSSL +#define BN_WITH_OPENSSL +#endif + +#if defined(BP_WITH_OPENSSL) +#include +#endif + +#if !defined(BP_WITH_OPENSSL) + #include + #include +#endif + +/*************************** BN Definitions *********************/ +#define TRUE 1 +#define FALSE 0 + +#if defined(BN_WITH_OPENSSL) + +/* BEGIN OpenSSL macro definitions */ + +typedef BIGNUM* bignum_t; + +#define zml_bignum_free(b) BN_free(b) +#define zml_bignum_safe_free(b) OPENSSL_free(b) + +#define zml_bignum_fromHex(b, str, len) BN_hex2bn(&b, str) +#define zml_bignum_fromBin(b, ustr, len) BN_bin2bn(ustr, len, b) +#define zml_bignum_toBin(b, str, len) BN_bn2bin(b, str) +#define zml_bignum_setuint(b, x) BN_set_word(b, x) + +// returns 1 if true, otherwise 0 +#define zml_bignum_is_zero(b) BN_is_zero(b) +#define zml_bignum_is_one(b) BN_is_one(b) + +/** BN_is_negative returns 1 if the BIGNUM is negative + * \param a pointer to the BIGNUM object + * \return 1 if a < 0 and 0 otherwise + */ +#define BN_POSITIVE 0 +#define BN_NEGATIVE 1 + +#define BN_CMP_LT -1 +#define BN_CMP_EQ 0 +#define BN_CMP_GT 1 +#define G_CMP_EQ BN_CMP_EQ + +/* END OpenSSL macro definitions */ + +#else + +/* BEGIN RELIC macro definitions (default if BN_WITH_OEPNSSL not set) */ + +typedef bn_t bignum_t; + +#define zml_bignum_free(b) bn_free(b) +#define zml_bignum_safe_free(b) if(b != NULL) free(b) + +#define zml_bignum_fromHex(b, str, len) bn_read_str(b, str, len, 16) +#define zml_bignum_fromBin(b, ustr, len) bn_read_bin(b, ustr, len) +#define zml_bignum_toBin(b, str, len) bn_write_bin(str, len, b) + +#define zml_bignum_setuint(b, x) bn_set_dig(b, x) +// returns 1 if true, otherwise 0 +#define zml_bignum_is_zero(b) bn_is_zero(b) +#define zml_bignum_is_one(b) bn_is_one(b) + +#define BN_CMP_LT CMP_LT +#define BN_CMP_EQ CMP_EQ +#define BN_CMP_GT CMP_GT + +#define BN_POSITIVE BN_POS +#define BN_NEGATIVE BN_NEG +#define G_CMP_EQ CMP_EQ + +int bn_is_one(const bn_t a); +/* END of RELIC macro definitions */ +int zml_check_error(); +void zml_bignum_rand(bignum_t a, bignum_t o); + +#endif + +/*************************** EC Definitions *********************/ + +#if defined(EC_WITH_OPENSSL) + +/* BEGIN OpenSSL macro definitions */ + +typedef EC_POINT* ec_point_t; +typedef EC_GROUP* ec_group_t; + +/* Elliptic curve operations */ +#define ec_point_free(e) EC_POINT_clear_free(e) +#define ec_group_free(g) EC_GROUP_free(g) + +#define ec_point_set_null(e) e = nullptr +#define is_ec_point_null(e) e == nullptr +#define ec_get_ref(a) a +/* END of OpenSSL macro definitions */ + +#else +/* if EC_WITH_OPENSSL not specifically defined, + * then we use RELIC EC operations by default */ + + /* BEGIN RELIC macro definitions */ +typedef ep_t ec_point_t; +typedef void* ec_group_t; + +#define ep_inits(g) \ + ep_null(g); \ + ep_new(g); + +#define ec_point_free(e) ep_free(e) +#define ec_group_free(g) g = NULL; + +#define ec_point_set_null(e) /* do nothing here */ +#define is_ec_point_null(e) false +#define ec_get_ref(a) &a + +/* END of RELIC macro definitions */ +#endif + +// init/clean internal structures +void zml_init(); +void zml_clean(); + +// abstract bignum operations +void zml_bignum_init(bignum_t *a); +void zml_bignum_copy(bignum_t to, const bignum_t from); +int zml_bignum_sign(const bignum_t a); +int zml_bignum_cmp(const bignum_t a, const bignum_t b); +void zml_bignum_setzero(bignum_t a); +int zml_bignum_countbytes(const bignum_t a); +int zml_bignum_mod_inv(bignum_t a, const bignum_t b, const bignum_t o); +void zml_bignum_mod(bignum_t x, const bignum_t o); +void zml_bignum_negate(bignum_t b, const bignum_t o); +void zml_bignum_add(bignum_t r, const bignum_t x, const bignum_t y, const bignum_t o); +void zml_bignum_sub(bignum_t r, const bignum_t x, const bignum_t y); +void zml_bignum_sub_order(bignum_t r, const bignum_t x, const bignum_t y, const bignum_t o); +void zml_bignum_mul(bignum_t r, const bignum_t x, const bignum_t y, const bignum_t o); +void zml_bignum_div(bignum_t r, const bignum_t x, const bignum_t y, const bignum_t o); +void zml_bignum_exp(bignum_t r, const bignum_t x, const bignum_t y, const bignum_t o); + +// logical operators for bignums +void zml_bignum_lshift(bignum_t r, const bignum_t a, int n); +void zml_bignum_rshift(bignum_t r, const bignum_t a, int n); + +// NOTE: must free the memory that is returned from bignum_toHex and bignum_toDec using bignum_safe_free +char *zml_bignum_toHex(const bignum_t b, int *length); +char *zml_bignum_toDec(const bignum_t b, int *length); + +// abstract elliptic curve operations +int ec_group_init(ec_group_t *group, uint8_t id); +void ec_get_order(ec_group_t group, bignum_t order); +void ec_point_init(ec_group_t group, ec_point_t *e); +void ec_point_copy(ec_point_t to, const ec_point_t from); +void ec_point_set_inf(ec_group_t group, ec_point_t p); +int ec_point_cmp(ec_group_t group, const ec_point_t a, const ec_point_t b); +int ec_point_is_inf(ec_group_t group, ec_point_t p); +void ec_get_generator(ec_group_t group, ec_point_t p); +void ec_get_coordinates(ec_group_t group, bignum_t x, bignum_t y, const ec_point_t p); +int ec_convert_to_point(ec_group_t group, ec_point_t p, uint8_t *xstr, int len); +int ec_point_is_on_curve(ec_group_t group, ec_point_t p); +void ec_point_add(ec_group_t g, ec_point_t r, const ec_point_t x, const ec_point_t y); +void ec_point_mul(ec_group_t g, ec_point_t r, const ec_point_t x, const bignum_t y); + +size_t ec_point_elem_len(const ec_point_t g); +void ec_point_elem_in(ec_point_t g, uint8_t *in, size_t len); +void ec_point_elem_out(const ec_point_t g, uint8_t *out, size_t len); + +/*************************** BP Definitions *********************/ + +#if defined(BP_WITH_OPENSSL) + +/* BEGIN OpenSSL macro definitions */ + +typedef BP_GROUP* bp_group_t; +#define bp_group_free(g) BP_GROUP_free(g); + +typedef G1_ELEM* g1_ptr; +typedef G2_ELEM* g2_ptr; +typedef GT_ELEM* gt_ptr; + +#define g_set_null(g) g = nullptr; +#define g1_copy_const G1_ELEM_copy +#define g2_copy_const G2_ELEM_copy +#define gt_copy_const GT_ELEM_copy + +#define g1_element_free G1_ELEM_clear_free +#define g2_element_free G2_ELEM_clear_free +#define gt_element_free GT_clear_free + +#define is_elem_null(e) e == nullptr + +#else +/* if BP_WITH_OPENSSL not specifically defined, + * then we use RELIC EC operations by default */ + + /* BEGIN RELIC macro definitions */ + +// ZTK-specific macros for RELIC +#define bn_inits(b) \ + bn_null(b); \ + bn_new(b); + +#define g1_inits(g) \ + ep_null(g); \ + ep_new(g); + +#define ep2_inits(g) \ + ep2_null(g); \ + ep2_new(g); + +#define fp12_inits(g) \ + fp12_null(g); \ + fp12_new(g); + +#define g1_copy_const CAT(G1_LOWER, copy_const) +#define g2_copy_const CAT(G2_LOWER, copy_const) +#define gt_copy_const CAT(GT_LOWER, copy_const) +#define g1_set_rand CAT(G1_LOWER, set_rand) +#define g2_set_rand CAT(G2_LOWER, set_rand) +#define gt_set_rand CAT(GT_LOWER, set_rand) +#define g1_write_ostream CAT(G1_LOWER, write_ostream) +#define g2_write_ostream CAT(G2_LOWER, write_ostream) +#define gt_write_ostream CAT(GT_LOWER, write_ostream) +#define gt_is_zero CAT(GT_LOWER, is_zero) + +void bn_copy_const(bn_t c, const bn_t a); +void ep_copy_const(ep_t r, const ep_t p); +void fp_copy_const(fp_t c, const fp_t a); +void ep2_copy_const(ep2_t r, const ep2_t p); +void fp2_copy_const(fp2_t c, const fp2_t a); +void fp12_copy_const(fp12_t c, const fp12_t a); +void fp6_copy_const(fp6_t c, const fp6_t a); + +int bn_cmp_const(bn_t a, const bn_t b); +int bn_cmp_abs_const(const bn_t a, const bn_t b); +int bn_cmpn_low_const(const dig_t *a, const dig_t *b, const int size); +int ep_cmp_const(ep_t p, const ep_t q); +int ep2_cmp_const(ep2_t p, const ep2_t q); +int fp12_cmp_const(fp12_t a, const fp12_t b); +int fp6_cmp_const(fp6_t a, const fp6_t b); +int fp2_cmp_const(fp2_t a, const fp2_t b); +int fp_cmp_const(fp_t a, const fp_t b); +int fp_cmpn_low_const(dig_t *a, const dig_t *b); + +typedef void* bp_group_t; +#define bp_group_free(g) g = nullptr; + +typedef ep_t g1_ptr; +typedef ep2_t g2_ptr; +typedef fp12_t gt_ptr; + +#define g_set_null(g) +#define g1_element_free g1_free +#define g2_element_free g2_free +#define gt_element_free gt_free + +#define is_elem_null(e) FALSE +/* END of RELIC macro definitions */ +#endif + +// C helper functions to handle (OpenSSL/RELIC) +int bp_group_init(bp_group_t *group, uint8_t id); +void bp_get_order(bp_group_t group, bignum_t order); + +// ZML abstract methods for G1 +void g1_init(bp_group_t group, g1_ptr *e); +void g1_set_to_infinity(bp_group_t group, g1_ptr *e); +void g1_add_op(bp_group_t group, g1_ptr z, const g1_ptr x, const g1_ptr y); +void g1_sub_op(bp_group_t group, g1_ptr z, const g1_ptr x); +void g1_mul_op(bp_group_t group, g1_ptr z, const g1_ptr x, const bignum_t r); +void g1_rand_op(g1_ptr g); +void g1_map_op(const bp_group_t group, g1_ptr g, uint8_t *msg, int msg_len); + +#if !defined(BP_WITH_OPENSSL) +size_t g1_elem_len(const g1_ptr g); +void g1_elem_in(g1_ptr g, uint8_t *in, size_t len); +void g1_elem_out(const g1_ptr g, uint8_t *out, size_t len); +size_t g2_elem_len(g2_ptr g); +void g2_elem_in(g2_ptr g, uint8_t *in, size_t len); +void g2_elem_out(g2_ptr g, uint8_t *out, size_t len); +size_t gt_elem_len(gt_ptr g, int should_compress); +void gt_elem_in(gt_ptr g, uint8_t *in, size_t len); +void gt_elem_out(gt_ptr g, uint8_t *out, size_t len, int should_compress); +#endif + +// ZML abstract methods for G2 +void g2_init(bp_group_t group, g2_ptr *e); +void g2_set_to_infinity(bp_group_t group, g2_ptr *e); +int g2_cmp_op(bp_group_t group, g2_ptr x, g2_ptr y); +void g2_mul_op(bp_group_t group, g2_ptr z, g2_ptr x, bignum_t r); + +// ZML abstract methods for GT +void gt_init(const bp_group_t group, gt_ptr *e); +void gt_set_to_infinity(bp_group_t group, gt_ptr *e); +void gt_mul_op(const bp_group_t group, gt_ptr z, gt_ptr x, gt_ptr y); +void gt_div_op(const bp_group_t group, gt_ptr z, gt_ptr x, gt_ptr y); +void gt_exp_op(const bp_group_t group, gt_ptr y, gt_ptr x, bignum_t r); +int gt_is_unity_check(const bp_group_t group, gt_ptr r); + +// ZML (pairings & multi-pairings) +void bp_map_op(const bp_group_t group, gt_ptr gt, g1_ptr g1, g2_ptr g2); + +#endif /* ifdef __ZELEMENT_H__ */ diff --git a/src/include/openabe/zml/zelement_bp.h b/src/include/openabe/zml/zelement_bp.h new file mode 100644 index 00000000..97b9691c --- /dev/null +++ b/src/include/openabe/zml/zelement_bp.h @@ -0,0 +1,276 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zelement_bp.h +/// +/// \brief Class definition for a group element. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZELEMENT_BP_H__ +#define __ZELEMENT_BP_H__ + +#if defined(BP_WITH_OPENSSL) +#define BN_WITH_OPENSSL +#define EC_WITH_OPENSSL +#endif + +#include + +extern "C" { +#include +} + +namespace oabe { + +#if !defined(BP_WITH_OPENSSL) +void fp12_write_ostream(std::ostream& os, fp12_t a, int radix); +void fp6_write_ostream(std::ostream& os, fp6_t a, int radix); +void fp2_write_ostream(std::ostream& os, fp2_t a, int radix); +void fp_write_ostream(std::ostream& os, fp_t a, int radix); +void ep2_write_ostream(std::ostream &os, ep2_t p, int radix); +void ep_write_ostream(std::ostream &os, ep_t p, int radix); +#endif + +#ifndef __ZPAIRING_H__ +class OpenABEPairing; +#endif +// forward declaration +class OpenABEByteString; +class OpenABERNG; + +#if !defined(BP_WITH_OPENSSL) +bool checkRelicError(); +#endif + +} + +void ro_error(void); + +void g1_map_op(const bp_group_t group, g1_ptr g, oabe::OpenABEByteString& msg); +const std::string g1_point_to_string(bp_group_t group, const g1_ptr p); +void g1_convert_to_bytestring(bp_group_t group, oabe::OpenABEByteString & s, const g1_ptr p); +void g1_convert_to_point(bp_group_t group, oabe::OpenABEByteString& s, g1_ptr p); + +void g2_convert_to_point(bp_group_t group, oabe::OpenABEByteString& s, g2_ptr p); +const std::string g2_point_to_string(bp_group_t group, const g2_ptr p); +void g2_convert_to_bytestring(bp_group_t group, oabe::OpenABEByteString & s, g2_ptr p); + +void gt_convert_to_point(bp_group_t group, oabe::OpenABEByteString& s, gt_ptr p); +void gt_convert_to_bytestring(bp_group_t group, oabe::OpenABEByteString& s, gt_ptr p, int should_compress); +const std::string gt_point_to_string(const bp_group_t group, gt_ptr p); + +/// \class ZP +/// \brief Class for representing integer elements mod p. + +namespace oabe { + +// retrieve the group field of the BPGroup class +#define GET_BP_GROUP(g) g->group + +/// \class ECGroup +/// \brief Wrapper for managing elliptic curve groups +class BPGroup : public ZGroup { +public: + bp_group_t group; + bignum_t order; + + BPGroup(OpenABECurveID id); + ~BPGroup(); + + void getGroupOrder(bignum_t o); +}; + + +/// \class ZP +/// \brief Class for ZP elements in ZML. +class ZP : public ZObject { +public: + bignum_t m_ZP; + bignum_t order; + bool isInit, isOrderSet; + ZP(); + ZP(uint32_t); + ZP(char*, bignum_t); + ZP(uint8_t*, uint32_t, bignum_t); + ZP(bignum_t y); + ZP(const ZP& w); + + ~ZP(); + ZP& operator+=(const ZP& x); + ZP& operator*=(const ZP& x); + ZP& operator=(const ZP& w); + + std::string getBytesAsString(); + OpenABEByteString getByteString() const; + void getLengthAndByteString(OpenABEByteString &z) const; + void setOrder(const bignum_t o); + void setRandom(OpenABERNG *rng, bignum_t o); + + void setFrom(ZP&, uint32_t); + bool ismember(); + void multInverse(); + + friend ZP power(const ZP&, unsigned int); + friend ZP power(const ZP&, const ZP&); + friend ZP operator-(const ZP&); + friend ZP operator-(const ZP&,const ZP&); + friend ZP operator+(const ZP&,const ZP&); + friend ZP operator*(const ZP&,const ZP&); + friend ZP operator/(const ZP&,const ZP&); + friend ZP operator<<(const ZP&, int); + friend ZP operator>>(const ZP&, int); + + friend std::ostream& operator<<(std::ostream&, const ZP&); + friend bool operator<(const ZP& x, const ZP& y); + friend bool operator<=(const ZP& x, const ZP& y); + friend bool operator>(const ZP& x, const ZP& y); + friend bool operator>=(const ZP& x, const ZP& y); + friend bool operator==(const ZP& x, const ZP& y); + friend bool operator!=(const ZP& x, const ZP& y); + + ZP* clone() const { return new ZP(*this); } + void serialize(OpenABEByteString &result) const; + void deserialize(OpenABEByteString &input); + bool isEqual(ZObject*) const; +}; + +/// \class G1 +/// \brief Class for G1 base field elements in ZML. +class G1 : public ZObject { +public: + g1_ptr m_G1; + bool isInit; + std::shared_ptr bgroup; + + G1(std::shared_ptr bgroup); + G1(const G1& w); + ~G1(); + G1& operator*=(const G1& x); + G1& operator=(const G1& w); + + void setRandom(OpenABERNG *rng); + bool ismember(bignum_t); + G1 exp(ZP); + void multInverse(); + friend G1 operator-(const G1&); + friend G1 operator/(const G1&,const G1&); + friend G1 operator*(const G1&,const G1&); + friend std::ostream& operator<<(std::ostream&, const G1&); + friend bool operator==(const G1& x, const G1& y); + friend bool operator!=(const G1& x,const G1& y); + + G1* clone() const { return new G1(*this); } + void serialize(OpenABEByteString &result) const; + void deserialize(OpenABEByteString &input); + bool isEqual(ZObject*) const; +}; + +/// \class G2 +/// \brief Class for G2 field elements in ZML. +class G2 : public ZObject { +public: + g2_ptr m_G2; + bool isInit; + std::shared_ptr bgroup; + + G2(std::shared_ptr bgroup); + G2(const G2& w); + ~G2(); + G2& operator*=(const G2& x); + G2& operator=(const G2& w); + + void setRandom(OpenABERNG *rng); + bool ismember(bignum_t); + G2 exp(ZP); + + friend G2 operator-(const G2&); + friend G2 operator/(const G2&,const G2&); + friend G2 operator*(const G2&,const G2&); + friend std::ostream& operator<<(std::ostream&, const G2&); + friend bool operator==(const G2& x,const G2& y); + friend bool operator!=(const G2& x,const G2& y); + + G2* clone() const { return new G2(*this); } + void serialize(OpenABEByteString &result) const; + void deserialize(OpenABEByteString &input); + bool isEqual(ZObject*) const; +}; + +/// \class GT +/// \brief Class for GT field elements in RELIC. +class GT : public ZObject { +public: + gt_ptr m_GT; + bool isInit; + std::shared_ptr bgroup; + + GT(std::shared_ptr bgroup); + GT(const GT& w); + ~GT(); + GT& operator*=(const GT& x); + GT& operator=(const GT& x); + + void enableCompression() { shouldCompress_ = true; }; + void disableCompression() { shouldCompress_ = false; }; + //void setRandom(OpenABERNG *rng); + void setIdentity(); + bool isInfinity(); + bool ismember(bignum_t); + GT exp(ZP); + + friend GT operator-(const GT&); + friend GT operator/(const GT&,const GT&); + friend GT operator*(const GT&,const GT&); + friend std::ostream& operator<<(std::ostream& s, const GT&); + friend bool operator==(const GT& x, const GT& y); + friend bool operator!=(const GT& x, const GT& y); + + GT* clone() const { return new GT(*this); } + void serialize(OpenABEByteString &result) const; + void deserialize(OpenABEByteString &input); + bool isEqual(ZObject*) const; + +private: + bool shouldCompress_; +}; + +/// \typedef OpenABEElementList +/// \brief Vector or list of elements +typedef std::vector OpenABEElementList; + +/// \typedef OpenABEElementListIterator +/// \brief Iterator for an OpenABEElementList of rows in an LSSS +typedef OpenABEElementList::iterator OpenABEElementListIterator; + +} + +// pairings definition +void multi_bp_map_op(const bp_group_t group, oabe::GT& gt, + std::vector& g1, std::vector& g2); + +#endif // __ZELEMENT_H__ diff --git a/src/include/openabe/zml/zelement_ec.h b/src/include/openabe/zml/zelement_ec.h new file mode 100644 index 00000000..8bc317e3 --- /dev/null +++ b/src/include/openabe/zml/zelement_ec.h @@ -0,0 +1,177 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zelement_low.h +/// +/// \brief Class definition files for a group element. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZELEMENT_EC_H__ +#define __ZELEMENT_EC_H__ + +#include +#include + +#if defined(EC_WITH_OPENSSL) +#define BN_WITH_OPENSSL +#endif + +#include +extern "C" { +#include +} + +int ec_convert_to_bytestring(const ec_group_t group, + oabe::OpenABEByteString & s, + const ec_point_t p); +std::string ec_point_to_string(ec_group_t group, const ec_point_t p); + +namespace oabe { + +/// \class ZP_t +/// \brief An abstract class for integers (works wih OpenSSL and RELIC unlike ZP) +class ZP_t : public ZObject { +private: + void getByteString(OpenABEByteString &z) const; + +public: + bignum_t m_ZP; + bignum_t order; + + bool isInit, isOrderSet; + ZP_t(); + ZP_t(bignum_t o); + ZP_t(char*); + ZP_t(uint8_t*,uint32_t); + ZP_t(const ZP_t&); + ~ZP_t(); + + ZP_t& operator+=(const ZP_t& x); + ZP_t& operator-=(const ZP_t& x); + ZP_t& operator-=(int x); + ZP_t& operator*=(const ZP_t& x); + ZP_t& operator=(const ZP_t& w) + { + if (isInit) { zml_bignum_copy(this->m_ZP, w.m_ZP); } + if (w.isOrderSet) { zml_bignum_copy(this->order, w.order); } + else ro_error(); + return *this; + } + std::string getBytesAsString(); + OpenABEByteString getByteString(); + + void setRandom(OpenABERNG *rng); + void setZero(); + void set(bignum_t i); + void setOrder(const bignum_t order); + void multInverse(); + friend ZP_t operator-(const ZP_t&); + friend ZP_t operator-(const ZP_t&,const ZP_t&); + friend ZP_t operator+(const ZP_t&,const ZP_t&); + friend ZP_t operator*(const ZP_t&,const ZP_t&); + friend ZP_t operator/(const ZP_t&,const ZP_t&); + + friend std::ostream& operator<<(std::ostream&, const ZP_t&); + friend bool operator<(const ZP_t& x,const ZP_t& y); + friend bool operator<=(const ZP_t& x,const ZP_t& y); + friend bool operator>(const ZP_t& x,const ZP_t& y); + friend bool operator>=(const ZP_t& x,const ZP_t& y); + friend bool operator==(const ZP_t& x,const ZP_t& y); + friend bool operator!=(const ZP_t& x,const ZP_t& y); + + ZP_t* clone() const { return new ZP_t(*this); } + void serialize(OpenABEByteString &result) const; + void deserialize(OpenABEByteString &input); + bool isEqual(ZObject*) const; + +}; + +// Forward declare the elliptic curve point class +class G_t; +// retrieve the group field of teh ECGroup class +#define GET_GROUP(g) g->group + +/// \class ECGroup +/// \brief Wrapper for managing elliptic curve groups +class ECGroup : public ZGroup { +public: + ec_group_t group; + bignum_t order; + + ECGroup(OpenABECurveID id); + ~ECGroup(); + + void getGenerator(ec_point_t g); + void getGroupOrder(bignum_t o); +}; + +/// \class G_t +/// \brief Wrapper for ordinary elliptic curve points +class G_t : public ZObject { +public: + ec_point_t m_G; + std::shared_ptr ecgroup; + bool isInit; + + G_t(); + G_t(std::shared_ptr ecgroup); + G_t(const G_t& w); + ~G_t(); + + G_t& operator=(const G_t& w); + G_t exp(ZP_t&); + void get(ZP_t&, ZP_t&); + + friend G_t operator*(const G_t&, const G_t&); + friend std::ostream& operator<<(std::ostream&, const G_t&); + friend bool operator==(const G_t& x,const G_t& y) { + if(ec_point_cmp(GET_GROUP(x.ecgroup), x.m_G, y.m_G) == G_CMP_EQ) + return true; + else + return false; + } + friend bool operator!=(const G_t& x,const G_t& y) { + if (ec_point_cmp(GET_GROUP(y.ecgroup), x.m_G, y.m_G) != G_CMP_EQ) + return true; + else return false; + } + G_t* clone() const { return new G_t(*this); } + void serialize(OpenABEByteString &result) const; + void deserialize(OpenABEByteString &input); + bool isEqual(ZObject*) const; +}; + +void generateECCurveParameters(EC_GROUP **group, std::string paramid); + +} + +#endif // __ZELEMENT_EC_H__ + + + + diff --git a/src/include/openabe/zml/zelliptic.h b/src/include/openabe/zml/zelliptic.h new file mode 100644 index 00000000..34e85c87 --- /dev/null +++ b/src/include/openabe/zml/zelliptic.h @@ -0,0 +1,80 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zelliptic.h +/// +/// \brief Class definition files for ordinary elliptic curves. +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZELLIPTIC_H__ +#define __ZELLIPTIC_H__ + +/// \class OpenABEEllipticCurve +/// \brief Generic container for NIST elliptic-curve functionality. +namespace oabe { + +class OpenABEEllipticCurve : public ZObject { +public: + OpenABEEllipticCurve(const std::string &ecParams); + OpenABEEllipticCurve(const OpenABEEllipticCurve ©From); + ~OpenABEEllipticCurve(); + ZP_t initZP(); + ZP_t randomZP(OpenABERNG *rng); + G_t initG(); + // curve parameters + G_t getGenerator(); + void getGroupOrder(bignum_t o); + ZP_t getGroupOrder(); + + std::string getECParams() const; + OpenABECurveID getCurveID() const; + bool isAtInfinity(G_t& point); + bool isOnCurve(G_t& point); + std::shared_ptr getGroup() { return this->ecgroup; } + +protected: + OpenABECurveID curveID; + std::shared_ptr ecgroup; + std::string ecParams; +}; + +// Convert a security level (in symmetric-equivalent bits) to pairing params +std::string OpenABE_ECParamsForSecurityLevel(OpenABESecurityLevel securityLevel); + +// elliptic curve creation functions +OpenABEEllipticCurve* OpenABE_createNewEllipticCurve(const std::string &ecParams); + +// Utility functions for curveIDs +std::string OpenABE_convertECCurveIDToString(uint8_t curveID); +OpenABECurveID OpenABE_convertIntToCurveID(uint8_t curveID); +int OpenABE_convertStringToNID(std::string paramsID); +int OpenABE_convertCurveIDToNID(OpenABECurveID id); + +} + +#endif // __ZELLIPTIC_H__ diff --git a/src/include/openabe/zml/zgroup.h b/src/include/openabe/zml/zgroup.h new file mode 100644 index 00000000..a758ccc5 --- /dev/null +++ b/src/include/openabe/zml/zgroup.h @@ -0,0 +1,60 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zgroup.h +/// +/// \brief Base class definition for OpenABE groups (EC/pairings) +/// +/// \author J. Ayo Akinyele +/// + +#ifndef __ZGROUP_H__ +#define __ZGROUP_H__ + +#include + +/// +/// @class ZGroup +/// +/// @brief Abstract group for EC/Pairing operations. +/// +namespace oabe { + +class ZGroup : public ZObject { +public: + ZGroup(OpenABECurveID id); + ~ZGroup(); + OpenABECurveID getCurveID(); + friend std::ostream& operator<<(std::ostream& s, const ZGroup&); + +protected: + OpenABECurveID id; + std::string group_param; +}; + +} + +#endif /* ifdef __ZGROUP_H__ */ diff --git a/src/include/openabe/zml/zpairing.h b/src/include/openabe/zml/zpairing.h new file mode 100644 index 00000000..dc04c143 --- /dev/null +++ b/src/include/openabe/zml/zpairing.h @@ -0,0 +1,87 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zpairing.h +/// +/// \brief Class definition for bilinear maps (or pairings). +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef __ZPAIRING_H__ +#define __ZPAIRING_H__ + +/// \class OpenABEPairing +/// \brief Generic container for pairing functionality. +namespace oabe { + +class OpenABEPairing : public ZObject { +public: + OpenABEPairing(const std::string &pairingParams); + OpenABEPairing(const OpenABEPairing ©From); + ~OpenABEPairing(); + void initZP(ZP& z, uint32_t v); + ZP initZP(); + G1 initG1(); + G2 initG2(); + GT initGT(); + + ZP randomZP(OpenABERNG *rng); + G1 randomG1(OpenABERNG *rng); + G2 randomG2(OpenABERNG *rng); + + OpenABEByteString hashToBytes(uint8_t*, uint32_t); + OpenABEByteString hashFromBytes(OpenABEByteString &buf, uint32_t target_len, uint8_t hash_prefix); + + G1 hashToG1(OpenABEByteString&, std::string); + GT pairing(G1& g1, G2& g2); + void multi_pairing(GT& gt, std::vector& g1, std::vector& g2); + + std::string getPairingParams() const; + OpenABECurveID getCurveID() const; + std::shared_ptr getGroup() { return this->bpgroup; } + bignum_t order; + +protected: + bool isSymmetric; + OpenABECurveID curveID; + std::string pairingParams; + std::shared_ptr bpgroup; +}; + +// Global library initialization and shutdown functions +OpenABE_ERROR zMathInitLibrary(); +OpenABE_ERROR zMathShutdownLibrary(); +// Convert a security level (in symmetric-equivalent bits) to pairing params +std::string OpenABE_pairingParamsForSecurityLevel(OpenABESecurityLevel securityLevel); +// Pairing creation functions +OpenABEPairing* OpenABE_createNewPairing(const std::string &pairingParams); +// Utility functions +OpenABECurveID getPairingCurveID(const std::string ¶msID); + +} + +#endif // __ZPAIRING_H__ diff --git a/src/include/openabe/zobject.h b/src/include/openabe/zobject.h new file mode 100644 index 00000000..7dd22d9c --- /dev/null +++ b/src/include/openabe/zobject.h @@ -0,0 +1,81 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zobject.h +/// +/// \brief Class definition for the abstract OpenABE object. +/// This is subclassed by all OpenABE specific structures. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#ifndef openabe_ZObject_h +#define openabe_ZObject_h + +/// \class ZPublicParams +/// \brief Generic container for scheme public parameters. This class is is subclassed +/// by variants for specific schemes. + +#include +#include +#include +#include + +namespace oabe { + +#ifndef __ZBYTESTRING_H__ +class OpenABEByteString; +#endif + +class ZObject { +public: + ZObject(); + virtual ~ZObject(); + + void addRef(); + void deRef(); + uint32_t getRefCount() { return this->refCount; } + virtual ZObject& operator=(const ZObject &rhs) { return *this; } + virtual ZObject* clone() const { return NULL; } // throw an exception if not implemented + virtual void serialize(OpenABEByteString &result) const { throw OpenABE_ERROR_NOT_IMPLEMENTED; } + virtual bool isEqual(ZObject* z) const { return false; } + +protected: + uint32_t refCount; +}; + +// zeroization +void OpenABEZeroize(void *b, size_t b_len); +// base-64 encoding functions +std::string Base64Encode(unsigned char const* bytes_to_encode, unsigned int in_len); +std::string Base64Decode(std::string const& encoded_string); +bool is_base64(unsigned char c); + +ZObject *deserializeObject(OpenABEByteString); + +} + +#endif diff --git a/src/include/openabe/zsymcrypto.h b/src/include/openabe/zsymcrypto.h new file mode 100644 index 00000000..512d9896 --- /dev/null +++ b/src/include/openabe/zsymcrypto.h @@ -0,0 +1,130 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zsymcrypto.h +/// +/// \brief Class definition for PKE and ABE thin context wrappers +/// +/// \author Alan Dunn and J. Ayo Akinyele +/// + +#ifndef __ZSYMCRYPTO__ +#define __ZSYMCRYPTO__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace oabe { + +namespace crypto { + +/// +/// @class OpenABESymKeyAuthEnc +/// +/// @brief Class for performing authenticated symmetric encryption using AES in GCM mode +/// + +class OpenABESymKeyAuthEnc : ZObject { +private: + EVP_CIPHER *cipher; + uint8_t iv[AES_BLOCK_SIZE+1]; + OpenABEByteString aad; + OpenABEByteString key; + bool aad_set; + uint32_t iv_len; + +public: + OpenABESymKeyAuthEnc(int securitylevel, const std::string& zkey); + OpenABESymKeyAuthEnc(int securitylevel, OpenABEByteString& zkey); + ~OpenABESymKeyAuthEnc(); + + void chooseRandomIV(); + void setAddAuthData(OpenABEByteString &aad); + void setAddAuthData(uint8_t* aad, uint32_t aad_len); + OpenABE_ERROR encrypt(const std::string& plaintext, OpenABEByteString* iv, + OpenABEByteString* ciphertext, OpenABEByteString* tag); + bool decrypt(std::string& plaintext, OpenABEByteString* iv, + OpenABEByteString* ciphertext, OpenABEByteString* tag); +}; + +class OpenABESymKeyHandle { +public: + virtual void encrypt(std::string& ciphertext, + const std::string& plaintext) = 0; + virtual void decrypt(std::string& plaintext, + const std::string& ciphertext) = 0; + virtual void exportRawKey(std::string& key) = 0; + virtual void exportKey(std::string& key) = 0; +}; + +// Implementation of SymmetricKeyHandle +class OpenABESymKeyHandleImpl : public OpenABESymKeyHandle { +public: + void encrypt(std::string& ciphertext, + const std::string& plaintext); + void decrypt(std::string& plaintext, + const std::string& ciphertext); + void exportRawKey(std::string& key); + void exportKey(std::string& key); + + OpenABESymKeyHandleImpl(const std::string& keyBytes, + bool apply_b64_encode = false); + OpenABESymKeyHandleImpl(OpenABEByteString& keyBytes, + OpenABEByteString& authData, + bool apply_b64_encode = false); + virtual ~OpenABESymKeyHandleImpl(); + +protected: + int security_level_; + std::string key_; + bool b64_encode_; + OpenABEByteString authData_; +}; + +// Hash-based key derivation function +void OpenABEComputeHKDF(OpenABEByteString& key, OpenABEByteString& salt, + OpenABEByteString& info, size_t key_len, + OpenABEByteString& output_key); +// generate a random symmetric key +void generateSymmetricKey(std::string& key, uint32_t keyLen); +const std::string printAsHex(const std::string& bin_buf); + +} + +} + +#endif // __ZSYMCRYPTO__ diff --git a/src/keys/zkdf.cpp b/src/keys/zkdf.cpp new file mode 100644 index 00000000..3a8d6cc3 --- /dev/null +++ b/src/keys/zkdf.cpp @@ -0,0 +1,164 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zkdf.cpp +/// +/// \brief Implementation for key derivation functions. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEKDF class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEKDF class. + * + */ + +OpenABEKDF::OpenABEKDF(uint8_t hashPrefix, uint32_t hashLen, uint32_t maxInputLen) + : ZObject() { + // select a hash prefix for KDFs + this->hashPrefix = hashPrefix; + // bitlength of target hash function, H + this->hashLen = hashLen; + // max bitlength of input to hash function + this->maxInputLen = maxInputLen; +} + +/*! + * Destructor for the OpenABEKDF class. + * + */ + +OpenABEKDF::~OpenABEKDF() {} + +/*! + * A concatenated KDF from NIST SP800-56A - Section 5.8.1 for deriving keys. + * Returns the derived key of size keydataLenBytes. + * + * @param[in] the shared key represented as a bytestring. + * @param[in] the number of bits for the returned key. + * @param[in] auxiliary information that is provided as input into the KDF. + * @return A OpenABEByteString object that contains the derived key. + */ + +OpenABEByteString OpenABEKDF::DeriveKey(OpenABEByteString &Z, uint32_t keyBitLen, + OpenABEByteString &metadata) { + // compute number of hash blocks needed (round up) + OpenABEByteString buffer; + uint32_t count = 1; + + // ceiling of keydataLen / hashLen (bitwise) + size_t reps_len = (size_t)ceil(((double)keyBitLen) / this->hashLen); + if (reps_len > OpenABE_MAX_KDF_BITLENGTH) { + throw OpenABE_ERROR_INVALID_LENGTH; + } + + // buffer = counter || hashPrefix || Z || Metadata + buffer.setFirstBytes(count); + buffer.push_back(this->hashPrefix); + buffer.appendArray(Z.getInternalPtr(), Z.size()); + buffer.appendArray(metadata.getInternalPtr(), metadata.size()); + + if (buffer.size() > this->maxInputLen) { + throw OpenABE_ERROR_INVALID_LENGTH; + } + + // set the hash_len + int hash_len = reps_len * this->hashLen; + uint8_t hash[hash_len + 1]; + memset(hash, 0, hash_len + 1); + + uint8_t *hash_ptr = hash; + for (size_t i = 0; i < reps_len; i++) { + // H(count++ || prefix || Z || Metadata) + sha256(hash_ptr, buffer.getInternalPtr(), buffer.size()); + count++; + buffer.setFirstBytes(count); + hash_ptr += this->hashLen; // move ptr by hashLen bytes + } + + uint32_t keydataBytes = keyBitLen / 8; + OpenABEByteString keyMaterial; + keyMaterial.appendArray(hash, keydataBytes); + return keyMaterial; +} + + +/******************************************************************************** + * Implementation of the OpenABEPBKDF wrapper + ********************************************************************************/ + +int PKCS5_PBKDF2_HMAC_SHA256(const char *pass, int passlen, + const unsigned char *salt, int saltlen, int iter, + int keylen, unsigned char *out) { + return PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, EVP_sha256(), + keylen, out); +} + +/*! + * Applies PBKDF2 to a password and salt for a specified number of iterations. + * Returns the derived key of size keydataLenBytes. + * + * @param[in] a password. + * @param[in] the number of bytes for the returned key. + * @param[in] a salt for the given password. + * @param[in] iteration count (DEFAULT = 10000). + * @return A OpenABEByteString object that contains the derived key. + */ + +OpenABEByteString OpenABEPBKDF(OpenABEByteString &password, uint32_t keydataLenBytes, + OpenABEByteString &salt, int iterationCount) { + ASSERT(password.size() > 0, OpenABE_ERROR_INVALID_INPUT); + ASSERT(salt.size() > 0, OpenABE_ERROR_INVALID_INPUT); + ASSERT(keydataLenBytes > 0, OpenABE_ERROR_INVALID_INPUT); + + /* cheap allocation for keydataLenBytes */ + OpenABEByteString outputHash; + outputHash.fillBuffer(0, keydataLenBytes); + /* call PBKDF2 function in OpenSSL */ + PKCS5_PBKDF2_HMAC_SHA256((const char *)password.getInternalPtr(), + password.size(), salt.getInternalPtr(), salt.size(), + iterationCount, (int)keydataLenBytes, + outputHash.getInternalPtr()); + + return outputHash; +} +} diff --git a/src/keys/zkey.cpp b/src/keys/zkey.cpp new file mode 100644 index 00000000..129a7b7a --- /dev/null +++ b/src/keys/zkey.cpp @@ -0,0 +1,168 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zkey.cpp +/// +/// \brief Class implementation for storing/managing all types of OpenABE keys. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __ZKEY_CPP__ + +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEKey class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEKey class. + * + */ + +OpenABEKey::OpenABEKey() : OpenABEContainer() { + this->curveID = OpenABE_NONE_ID; + this->algorithmID = OpenABE_SCHEME_NONE; + this->libraryVersion = OpenABE_LIBRARY_VERSION; + this->ID = ""; + this->key_type = OpenABEKEY_NONE; + this->isPrivate = false; +} + +/*! + * Constructor for the OpenABEKey class. + * + */ + +OpenABEKey::OpenABEKey(const OpenABECurveID curveID, uint8_t algorithmID, const string ID, + OpenABEByteString *uid) + : OpenABEContainer() { + // store the curve identifier + this->curveID = curveID; + // the identifier of the scheme in OpenABE + this->algorithmID = algorithmID; + // current library version + this->libraryVersion = OpenABE_LIBRARY_VERSION; + if (uid != NULL && uid->size() == UID_LEN) { + // random identifier that is public but useful for deriving keys + this->uid = *uid; + } else { + // if 'uid' input is NULL, then just generate an id internally + OpenABERNG rng; + rng.getRandomBytes(&this->uid, UID_LEN); + } + // can be any string to represent the key holder's identification + this->ID = ID; + this->key_type = OpenABE_KeyTypeFromAlgorithmID(algorithmID); + this->isPrivate = false; +} + +/*! + * Destructor for the OpenABEKey class. + * + */ + +OpenABEKey::~OpenABEKey() {} + +/*! + * Obtain the serialized form of the OpenABEKey header. + * + */ + +void OpenABEKey::getHeader(OpenABEByteString &header) { + header.clear(); + header.push_back(this->libraryVersion); + header.push_back(this->curveID); + header.push_back(this->algorithmID); + header += this->uid; + header += this->ID; + return; +} + +OpenABE_ERROR +OpenABEKey::exportKeyToBytes(OpenABEByteString &output) { + output.clear(); + OpenABEByteString keyHeader, keyBytes; + // libVersion || curveID || AlgID || uid || id + this->getHeader(keyHeader); + // serialize the key structure + this->serialize(keyBytes); + // first pack the key header + // then pack the key bytes + output.pack(keyHeader.getInternalPtr(), keyHeader.size()); + output.pack(keyBytes.getInternalPtr(), keyBytes.size()); + // clear the contents of the intermediate buffers + keyHeader.clear(); + keyBytes.clear(); + + return OpenABE_NOERROR; +} + +OpenABE_ERROR +OpenABEKey::loadKeyFromBytes(OpenABEByteString &input) { + this->deserialize(input); + return OpenABE_NOERROR; +} + +OpenABEKeyType OpenABE_KeyTypeFromAlgorithmID(uint8_t algorithmID) { + if (algorithmID == OpenABE_SCHEME_PK_OPDH) + return OpenABEKEY_PK_ENC; + else if (algorithmID == OpenABE_SCHEME_CP_WATERS || + algorithmID == OpenABE_SCHEME_CP_WATERS_CCA) + return OpenABEKEY_CP_ENC; + else if (algorithmID == OpenABE_SCHEME_KP_GPSW || + algorithmID == OpenABE_SCHEME_KP_GPSW_CCA) + return OpenABEKEY_KP_ENC; + else if (algorithmID == OpenABE_SCHEME_PKSIG_ECDSA) + return OpenABEKEY_PK_SIG; + else + return OpenABEKEY_NONE; +} + +const std::string OpenABE_KeyTypeToString(OpenABEKeyType key_type) { + if (key_type == OpenABEKEY_SK_ENC) + return "SymKey"; + else if (key_type == OpenABEKEY_PK_ENC) + return "PubKey"; + else if (key_type == OpenABEKEY_CP_ENC) + return "CP-ABEKey"; + else if (key_type == OpenABEKEY_KP_ENC) + return "KP-ABEKey"; + else if (key_type == OpenABEKEY_PK_SIG) + return "PKSigKey"; + + return "Invalid KeyType"; +} +} diff --git a/src/keys/zkeystore.cpp b/src/keys/zkeystore.cpp new file mode 100644 index 00000000..790f4465 --- /dev/null +++ b/src/keys/zkeystore.cpp @@ -0,0 +1,326 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zkeystore.cpp +/// +/// \brief Class implementation for the OpenABE keystore and keystore manager. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __OpenABEKEYSTORE_CPP__ + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace oabe { + +/******************************************************************************** + * Implementation of the OpenABEKeystore class + ********************************************************************************/ + +/*! + * Constructor for the OpenABEKeystore class. + * + */ + +OpenABEKeystore::OpenABEKeystore(): ZObject() +{ +} + +/*! + * Destructor for the OpenABECiphertext class. + * + */ + +OpenABEKeystore::~OpenABEKeystore() +{ + std::map>::iterator iter; + for (iter = this->pubKeys.begin(); iter != this->pubKeys.end(); ++iter) { + // delete iter->second; + shared_ptr key = iter->second; + if (key != nullptr) { + key->zeroize(); // securely zeroize the keys + key.reset(); // deletes the managed object + } + } + this->pubKeys.clear(); + + for (iter = this->secKeys.begin(); iter != this->secKeys.end(); ++iter) { + // delete iter->second; + shared_ptr key = iter->second; + if (key != nullptr) { + key->zeroize(); // securely zeroize the keys + key.reset(); // deletes the managed object + } + } + this->secKeys.clear(); +} + +/*! + * Insert a key into the keystore. + * + * @param Name of the key + * @param Object containing the key + */ + +OpenABE_ERROR +OpenABEKeystore::addKey(const string name, const shared_ptr& component, zKeyType keyType) +{ + // Insert the key into the public or secret key maps + if (keyType == KEY_TYPE_PUBLIC) { + // Public key/parameter + this->pubKeys[name] = component; + } else if (keyType == KEY_TYPE_SECRET){ + // Secret key/parameter + this->secKeys[name] = component; + } + return OpenABE_NOERROR; +} + +/*! + * Retrieve a key from the keystore + * (searches for both public and secret) + * + * @param Identifier of the key + * @return Object containing the key, or NULL if not found + */ + +shared_ptr +OpenABEKeystore::getKey(const string keyID) { + shared_ptr result = nullptr; + + // Look in the public keys list + result = this->pubKeys[keyID]; + if (result != nullptr) { + return result; + } + // Look in the secret keys list + result = this->secKeys[keyID]; + if (result != nullptr) { + return result; + } + // Did not find the selected key + return nullptr; +} + +/*! + * Check whether an existing key has a specific + * keyID in the keystore. + * + * @param Identifier of the key + * @return true or false + */ +bool +OpenABEKeystore::checkSecretKey(const string keyID) { + if(this->secKeys.count(keyID) != 0) + return true; + return false; +} + + +/*! + * Retrieve a public key from the keystore. + * + * @param Identifier of the key + * @return Object containing the key, or NULL if not found + */ + +shared_ptr +OpenABEKeystore::getPublicKey(const string keyID) { + shared_ptr result; + + // Look in the public keys list + result = this->pubKeys[keyID]; + if (result != NULL) { + return result; + } + // Did not find the selected key + return nullptr; +} + +/*! + * Retrieve a secret key from the keystore. + * + * @param Identifier of the key + * @return Object containing the key, or NULL if not found + */ + +shared_ptr +OpenABEKeystore::getSecretKey(const string keyID) { + shared_ptr result; + + // Look in the secret keys list + result = this->secKeys[keyID]; + if (result != nullptr) { + return result; + } + // Did not find the selected key + return nullptr; +} + +#if 0 +/*! + * Retrieve references to secret key in the keystore. + * + * @return A vector of key references + */ + +const vector +OpenABEKeystore::getSecretKeyIDs() const { + vector keyRefs; + + std::map>::const_iterator iter; + for (iter = this->secKeys.begin(); iter != this->secKeys.end(); ++iter) { + keyRefs.push_back(iter->first); + } + // list will be empty if no secret keys in the keystore + return keyRefs; +} +#endif + + +/*! + * Delete a key from the keystore. + * + * @param[in] keyID - Identifier of the key + * @return - An error code (OpenABE_ERROR_INVALID_KEY) or OpenABE_NOERROR + */ + +OpenABE_ERROR +OpenABEKeystore::deleteKey(const string keyID) { + // Find the key and destroy it + shared_ptr key = this->getKey(keyID); + if (key != nullptr) { + key->zeroize(); + bool foundInPubKey = false, foundInSecKey = false; + // Remove key/value from our internal store via the iterator + map>::iterator iter1 = this->pubKeys.find(keyID); + map>::iterator iter2 = this->secKeys.find(keyID); + + if(iter1 != this->pubKeys.end()) { + this->pubKeys.erase(iter1); + foundInPubKey = true; + } + + if(iter2 != this->secKeys.end()) { + this->secKeys.erase(iter2); + foundInSecKey = true; + } + + // make sure key existed in one of two lists + // otherwise return an invalid key error + if(!foundInPubKey && !foundInSecKey) { + return OpenABE_ERROR_INVALID_KEY; + } + } + return OpenABE_NOERROR; +} + +/*! + * Verify that a given parameter ID is not already present in the keystore. + * + * @param[in] keyID - Identifier of the key + * @return - true if the key is /not/ present + */ + +bool +OpenABEKeystore::validateNewParamsID(const string &keyID) { + return (this->getKey(keyID) == nullptr); +} + + +OpenABE_ERROR +OpenABEKeystore::exportKeyToBytes(const string keyID, OpenABEByteString &exportedKey) { + shared_ptr key = this->getKey(keyID); + if (key == nullptr) { + return OpenABE_ERROR_INVALID_INPUT; + } + + exportedKey.clear(); + key->exportKeyToBytes(exportedKey); + return OpenABE_NOERROR; +} + +shared_ptr +OpenABEKeystore::parseKeyHeader(const std::string keyID, OpenABEByteString &keyBlob, OpenABEByteString &outputKeyBytes) { + shared_ptr key = nullptr; + + // parse the result into a OpenABEKey structure + // parses the header and the body from PKE keys + key = this->constructKeyFromBytes(keyID, keyBlob, outputKeyBytes); + if(key == nullptr) { + THROW_ERROR(OpenABE_ERROR_INVALID_INPUT); + } + + return key; +} + + +shared_ptr +OpenABEKeystore::constructKeyFromBytes(const string &keyID, OpenABEByteString &keyBlob, OpenABEByteString &keyBytes) { + size_t hdrLen = 3 + UID_LEN; + shared_ptr key = nullptr; + + try { + if(keyBlob.size() < hdrLen) { THROW_ERROR(OpenABE_ERROR_INVALID_LENGTH); } + OpenABEByteString keyHeader; + size_t index = 0; + // convert to OpenABEByteStrings + keyHeader = keyBlob.unpack(&index); + + if(keyHeader.size() >= hdrLen) { + // check that lib version correct + ASSERT(keyHeader.at(0) <= OpenABE_LIBRARY_VERSION, OpenABE_ERROR_INVALID_LIBVERSION); + + OpenABECurveID curveID = OpenABE_getCurveID(keyHeader.at(1)); + uint8_t algID = OpenABE_getSchemeID(keyHeader.at(2)); + OpenABEByteString uid = keyHeader.getSubset(3, UID_LEN); + OpenABEByteString id = keyHeader.getSubset(hdrLen, keyHeader.size()-hdrLen); + + // alloc/construct the key + key.reset(new OpenABEKey(curveID, algID, id.toString(), &uid)); + // return the serialized form of the key structure + keyBytes.clear(); + keyBytes = keyBlob.unpack(&index); + } + else { + THROW_ERROR(OpenABE_ERROR_INVALID_KEY_HEADER); + } + } catch(OpenABE_ERROR &error) { + cerr << "OpenABEKeystore::constructKeyFromBytes: " << OpenABE_errorToString(error) << endl; + } + return key; +} + +} diff --git a/src/keys/zpkey.cpp b/src/keys/zpkey.cpp new file mode 100644 index 00000000..19858412 --- /dev/null +++ b/src/keys/zpkey.cpp @@ -0,0 +1,232 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zpkey.cpp +/// +/// \brief Implementation for storing OpenABE keys for PKSIG schemes. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEPKey class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEPKey class. + * + */ +OpenABEPKey::OpenABEPKey(bool isPrivate) : OpenABEKey() { + this->pkey = NULL; + this->isPrivate = isPrivate; +} + +/*! + * Constructor for the OpenABEPKey class. + * + */ +OpenABEPKey::OpenABEPKey(const EC_KEY *ec_key, bool isPrivate, EC_GROUP *group) + : OpenABEKey() { + EC_KEY *new_eckey = NULL; + EC_GROUP *new_group = NULL; + this->pkey = EVP_PKEY_new(); + this->isPrivate = isPrivate; + string error_msg = ""; + // check whether private or public key + if (this->isPrivate) { + // set as the EC_KEY (private key) of the pkey + // no need to copy since it'll be owned by the pkey + EVP_PKEY_assign_EC_KEY(this->pkey, ec_key); + } else { + ASSERT_NOTNULL(group); + // create a new EC_GROUP from the group of eckey, this + // will also copy over the ASN1 flag + new_group = EC_GROUP_dup(group); + if (!new_group) { + goto error; + } + + new_eckey = EC_KEY_new(); + if (!new_eckey) { + goto error; + } + + if (EC_KEY_set_group(new_eckey, new_group) == 0) { + goto error; + } + + // makes a copy of the public key + if (!EC_KEY_set_public_key(new_eckey, EC_KEY_get0_public_key(ec_key))) { + error_msg = "EC_KEY_set_public_key failed"; + goto error; + } + + // set the EC_KEY field of the EVP_PKEY + EVP_PKEY_assign_EC_KEY(this->pkey, new_eckey); + if (new_group != NULL) { + EC_GROUP_free(new_group); + } + } + return; +error: + if (new_eckey != NULL) { + EC_KEY_free(new_eckey); + } + + if (new_group != NULL) { + EC_GROUP_free(new_group); + } + + if (error_msg != "") { + OpenABE_LOG(error_msg); + } + + throw OpenABE_ERROR_ELEMENT_NOT_INITIALIZED; +} + +/*! + * Destructor for the OpenABEPKey class. + * + */ +OpenABEPKey::~OpenABEPKey() { + if (this->pkey != NULL) { + EVP_PKEY_free(this->pkey); + } +} + + +OpenABE_ERROR +OpenABEPKey::exportKeyToBytes(OpenABEByteString &output) { + OpenABE_ERROR result = OpenABE_ERROR_INVALID_INPUT; + BIO *pkey_out = nullptr; + string pkey_text, s; + stringstream ss; + + ASSERT_NOTNULL(this->pkey); + + pkey_out = BIO_new(BIO_s_mem()); + if (!pkey_out) { + goto out; + } + + if (this->isPrivate) { + // write private key + if (!PEM_write_bio_PKCS8PrivateKey(pkey_out, this->pkey, NULL, NULL, 0, + NULL, NULL)) { + goto out; + } + } else { + // write public key + if (!PEM_write_bio_PUBKEY(pkey_out, this->pkey)) { + goto out; + } + } + + // Unfortunately Thrift requires a signature key to be in OpenSSL + // format, so we keep that format exactly. If you look in the + // history for this file, you will find some metadata we kept with + // keys that we could reinstate by patching Thrift. + if (!bioToString(s, pkey_out)) { + goto out; + } + output = s; + result = OpenABE_NOERROR; + +out: + if (pkey_out) { + BIO_free(pkey_out); + } + + return result; +} + +OpenABE_ERROR +OpenABEPKey::loadKeyFromBytes(OpenABEByteString &input) { + OpenABE_ERROR result = OpenABE_NOERROR; + BIO *bio = NULL; + + // cout << "Serialized Key:\n" << input.toString() << endl; + + bio = BIO_new_mem_buf((void *)input.getInternalPtr(), input.size()); + if (!bio) { + result = OpenABE_ERROR_INVALID_INPUT; + goto out; + } + + if (this->pkey != NULL) { + EVP_PKEY_free(this->pkey); + this->pkey = NULL; + } + + if (this->isPrivate) { + this->pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + } else { + this->pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + } + ASSERT_NOTNULL(this->pkey); + + if (!this->pkey) { + result = OpenABE_ERROR_DESERIALIZATION_FAILED; + goto out; + } + +out: + if (bio) { + BIO_free(bio); + } + + return result; +} + +bool OpenABEPKey::bioToString(string &s, BIO *bio) { + bool result = false; + char buf[512]; + int rc; + + s.clear(); + while ((rc = BIO_read(bio, buf, sizeof(buf))) > 0) { + char *end = buf; + end += rc; + s.append(buf, end); + } + + if (BIO_eof(bio)) { + result = true; + } + return result; +} + +} diff --git a/src/keys/zsymkey.cpp b/src/keys/zsymkey.cpp new file mode 100644 index 00000000..3e7a4551 --- /dev/null +++ b/src/keys/zsymkey.cpp @@ -0,0 +1,522 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zsymkey.cpp +/// +/// \brief Implementation for storing and manipulating +/// the symmetric enc OpenABE keys +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __OpenABESYMKEY_CPP__ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABESymKey class + ********************************************************************************/ +namespace oabe { +/*! + * Constructor for the OpenABESymKey class. + * + */ +OpenABESymKey::OpenABESymKey() : OpenABEKey() {} + +/*! + * Destructor for the STKSymKey class. + * + */ +OpenABESymKey::~OpenABESymKey() { + // Zeroize contents of key buffer + this->m_keyData.zeroize(); +} + +OpenABE_ERROR OpenABESymKey::loadKeyFromBytes(OpenABEByteString &input) { + if (input.size() == 0) { + return OpenABE_ERROR_INVALID_LENGTH; + } + this->m_keyData = input; + return OpenABE_NOERROR; +} + +OpenABE_ERROR OpenABESymKey::exportKeyToBytes(OpenABEByteString &output) { + output = this->m_keyData; + return OpenABE_NOERROR; +} + +/*! + * Debugging function. Outputs a symmetric key in a human-readable + * string format. Don't use this in production code! + * + * @return Key as a formatted string. + */ +string OpenABESymKey::toString() { return this->m_keyData.toHex(); } + +/*! + * Hashes a group element into a symmetric key. + * + * @throw An exception if there's an error. + */ + +bool OpenABESymKey::hashToSymmetricKey(GT &input, uint32_t keyLen, + OpenABEHashFunctionType hashType) { + this->m_keyData.clear(); + // Hash the element into the key + return OpenABEUtilsHashToString(input, keyLen, this->m_keyData, hashType); +} + +bool OpenABESymKey::generateSymmetricKey(uint32_t keyLen) { + // Clear the original key + OpenABERNG rng; + rng.getRandomBytes(&this->m_keyData, (int)keyLen); + return true; +} + +void OpenABESymKey::setSymmetricKey(OpenABEByteString &key) { + this->m_keyData.clear(); + this->m_keyData = key; +} + +bool operator==(const OpenABESymKey &lhs, const OpenABESymKey &rhs) { + return (lhs.m_keyData.size() == rhs.m_keyData.size() && + lhs.m_keyData == lhs.m_keyData); +} + +/******************************************************************************** + * Implementation of the OpenABESymKeyEnc class + ********************************************************************************/ + +OpenABESymKeyEnc::OpenABESymKeyEnc(string key) : ZObject() { + this->seclevel = DEFAULT_SECURITY_LEVEL; + this->keyStr = key; + this->key = (AES_KEY *)malloc(sizeof(AES_KEY)); + MALLOC_CHECK_OUT_OF_MEMORY(this->key); + memset(this->iv, 0, AES_BLOCK_SIZE + 1); + this->iv_set = false; + this->status = false; +} + +OpenABESymKeyEnc::OpenABESymKeyEnc(int securitylevel, string key) : ZObject() { + this->seclevel = securitylevel; + this->keyStr = key; + this->key = (AES_KEY *)malloc(sizeof(AES_KEY)); + MALLOC_CHECK_OUT_OF_MEMORY(this->key); + memset(this->iv, 0, AES_BLOCK_SIZE + 1); + this->iv_set = false; + this->status = false; +} + +OpenABESymKeyEnc::OpenABESymKeyEnc(int securitylevel, uint8_t *iv, string key) + : ZObject() { + /* copy iv and key into */ + this->seclevel = securitylevel; + memset(this->iv, 0, AES_BLOCK_SIZE + 1); + memcpy(this->iv, iv, AES_BLOCK_SIZE + 1); + this->iv_set = true; + this->keyStr = key; + this->key = (AES_KEY *)malloc(sizeof(AES_KEY)); + MALLOC_CHECK_OUT_OF_MEMORY(this->key); + this->status = false; +} + +OpenABESymKeyEnc::~OpenABESymKeyEnc() { SAFE_FREE(this->key); } + +void OpenABESymKeyEnc::chooseRandomIV() { + if (!this->iv_set) { + ASSERT_RNG(RAND_bytes(this->iv, AES_BLOCK_SIZE)); + } +} + +// an 32-bit length field means we can encrypt 4GB files +string OpenABESymKeyEnc::encrypt(uint8_t *plaintext, uint32_t plaintext_len) { + // select a new IV + this->chooseRandomIV(); + // base-64 encode and serialize IV + string iv_encoded = Base64Encode(this->iv, AES_BLOCK_SIZE); + + // instantiate AES_KEY + AES_set_encrypt_key((uint8_t *)this->keyStr.c_str(), this->seclevel, + this->key); + + // compute ciphertext size and round to nearest block + int ct_len = + (int)ceil((plaintext_len + sizeof(uint32_t)) / (double)(AES_BLOCK_SIZE)) * + AES_BLOCK_SIZE; + uint8_t plaintext2[ct_len + 1]; + memset(plaintext2, 0, ct_len + 1); + + // big-endian + plaintext2[3] = (plaintext_len & 0x000000FF); + plaintext2[2] = (plaintext_len & 0x0000FF00) >> 8; + plaintext2[1] = (plaintext_len & 0x00FF0000) >> 16; + plaintext2[0] = (plaintext_len & 0xFF000000) >> 24; + memcpy((uint8_t *)(plaintext2 + sizeof(uint32_t)), plaintext, plaintext_len); + // cout << "PT=> " << debug_print_as_hex(plaintext2, ct_len) << endl; + + // encrypt ciphertext using AES_CBC_128 (for now) + uint8_t ct[ct_len + 1]; + memset(ct, 0, ct_len + 1); + AES_cbc_encrypt(plaintext2, ct, ct_len, this->key, this->iv, AES_ENCRYPT); + string ct_encoded = Base64Encode(ct, ct_len); + + // cout << "...AES Encrypt...\n"; + // cout << "IV=> " << iv_encoded << endl; + // cout << "CT=> " << debug_print_as_hex(ct, ct_len) << endl; + // cout << "...AES Encrypt...\n"; + + return iv_encoded + ":" + ct_encoded; +} + +string OpenABESymKeyEnc::decrypt(string ciphertext) { + // deserialize ciphertext blob (split on ':') + vector list = split(ciphertext, ':'); + if (list.size() != 2) { + status = false; + return ""; + } + string IV = Base64Decode(list[0]); + if (IV.size() != AES_BLOCK_SIZE) { + status = false; + return ""; + } + string ct = Base64Decode(list[1]); + size_t ct_len = ct.size(); + + if (!this->iv_set) { + // if IV was not set in the constructor, use IV in ciphertext + memset(this->iv, 0, AES_BLOCK_SIZE); + memcpy(this->iv, IV.c_str(), AES_BLOCK_SIZE); + } + + // cout << "...AES Decrypt...\n"; + // cout << "IV=> " << debug_print_as_hex(this->iv, AES_BLOCK_SIZE) << endl; + // cout << "CT=> " << debug_print_as_hex((uint8_t*) ct.c_str(), ct_len) << + // endl; + + // instantiate AES_KEY + AES_set_decrypt_key((uint8_t *)this->keyStr.c_str(), this->seclevel, + this->key); + + uint8_t plaintext[ct_len + 1]; + memset(plaintext, 0, ct_len + 1); + AES_cbc_encrypt((uint8_t *)ct.c_str(), plaintext, ct_len, this->key, this->iv, + AES_DECRYPT); + + // cout << "PT=> " << debug_print_as_hex(plaintext, ct_len) << endl; + // cout << "...AES Decrypt...\n"; + uint32_t len = 0; + len |= (plaintext[0] << 24); + len |= (plaintext[1] << 16); + len |= (plaintext[2] << 8); + len |= plaintext[3]; + + if (len > ct_len) { + status = false; + return "ACCESS DENIED\n"; + } + string plaintext2 = string((char *)(plaintext + sizeof(uint32_t)), len); + status = true; + return plaintext2; +} + +/******************************************************************************** + * Implementation of the OpenABESymKeyAuthEncStream class + ********************************************************************************/ + +OpenABESymKeyAuthEncStream::OpenABESymKeyAuthEncStream( + int securitylevel, const std::shared_ptr &key) + : ZObject() { + if (securitylevel == DEFAULT_AES_SEC_LEVEL) { + this->cipher = (EVP_CIPHER *)EVP_aes_256_gcm(); + // cout << "cipher_block_size: " << EVP_CIPHER_block_size(this->cipher) << + // endl; + } + this->key = key; + this->aad_set = false; + this->init_enc_set = false; + this->init_dec_set = false; + this->total_ct_len = -1; + this->updateEncCount = -1; + this->updateDecCount = -1; + this->ctx = NULL; +} + +OpenABESymKeyAuthEncStream::~OpenABESymKeyAuthEncStream() { + if (this->ctx != NULL) + EVP_CIPHER_CTX_free(this->ctx); +} + +void OpenABESymKeyAuthEncStream::initAddAuthData(uint8_t *aad, uint32_t aad_len) { + if (this->init_enc_set || this->init_dec_set) { + if (aad == NULL) { + // fill AAD buffer with 0's + this->aad.fillBuffer(0, AES_BLOCK_SIZE); + } else { + this->aad.appendArray(aad, aad_len); + } + this->aad_set = true; + } +} + +OpenABE_ERROR OpenABESymKeyAuthEncStream::setAddAuthData() { + /* specify the additional authentication data (aad) */ + uint8_t *aad_ptr = this->aad.getInternalPtr(); + int aad_len = this->aad.size(); + int ct_len = 0; + + if (this->init_enc_set && this->aad_set) { + EVP_EncryptUpdate(this->ctx, NULL, &ct_len, aad_ptr, aad_len); + ASSERT(ct_len == aad_len, OpenABE_ERROR_INVALID_INPUT); + } else if (this->init_dec_set && this->aad_set) { + EVP_DecryptUpdate(this->ctx, NULL, &ct_len, aad_ptr, aad_len); + ASSERT(ct_len == aad_len, OpenABE_ERROR_INVALID_INPUT); + } else { + return OpenABE_INVALID_INPUT_TYPE; + } + + return OpenABE_NOERROR; +} + +OpenABE_ERROR OpenABESymKeyAuthEncStream::encryptInit(OpenABEByteString *iv) { + OpenABE_ERROR result = OpenABE_NOERROR; + try { + if (!this->init_enc_set) { + /* can't mix encryptInit AND decryptInit at the same time */ + ASSERT(!this->init_dec_set, OpenABE_ERROR_INVALID_INPUT); + this->ctx = EVP_CIPHER_CTX_new(); + /* set cipher type and mode */ + EVP_EncryptInit_ex(this->ctx, this->cipher, NULL, NULL, NULL); + /* set the IV length as 128-bits (or 16 bytes) */ + EVP_CIPHER_CTX_ctrl(this->ctx, EVP_CTRL_GCM_SET_IVLEN, AES_BLOCK_SIZE, + NULL); + /* initialize key and IV */ + OpenABERNG rng; + rng.getRandomBytes(&this->the_iv, AES_BLOCK_SIZE); + + EVP_EncryptInit_ex(this->ctx, NULL, NULL, this->key->getInternalPtr(), + this->the_iv.getInternalPtr()); + /* save the generated IV */ + iv->clear(); + *iv += this->the_iv; + /* initialize internal counters and state */ + this->total_ct_len = 0; + this->updateEncCount = 0; + this->init_enc_set = true; + } else { + throw OpenABE_ERROR_IN_USE_ALREADY; + } + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR OpenABESymKeyAuthEncStream::encryptUpdate(OpenABEByteString *plaintextBlock, + OpenABEByteString *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + if (this->init_enc_set) { + /* encrypt plaintext */ + uint8_t *pt_ptr = plaintextBlock->getInternalPtr(); + int pt_len = plaintextBlock->size(); + int ct_len = 0; + /* make sure that the plaintext is at least 1 byte (since AES-GCM works on + * non-aligned block sizes) */ + ASSERT(pt_len > 0, OpenABE_ERROR_INVALID_INPUT); + + /* perform encryption update on the given plaintext */ + uint8_t ct[pt_len + 1]; + memset(ct, 0, pt_len); + EVP_EncryptUpdate(this->ctx, ct, &ct_len, pt_ptr, pt_len); + /* make sure we are not writing more than we've allocated */ + ASSERT(pt_len == ct_len, OpenABE_ERROR_INVALID_INPUT); + /* keep track of the total ciphertext length so far*/ + this->total_ct_len += ct_len; + /* return back to user */ + ciphertext->appendArray(ct, ct_len); + /* increment number of encrypt updates the user has performed */ + this->updateEncCount++; + } + + return result; +} + +OpenABE_ERROR OpenABESymKeyAuthEncStream::encryptFinalize(OpenABEByteString *ciphertext, + OpenABEByteString *tag) { + OpenABE_ERROR result = OpenABE_NOERROR; + + if (this->init_enc_set && this->updateEncCount > 0) { + /* finalize: computes authentication tag*/ + uint8_t *ct_ptr = ciphertext->getInternalPtr(); + /* make sure 'ct' size is the same as our internal size counter */ + ASSERT(ciphertext->size() == this->total_ct_len, OpenABE_ERROR_INVALID_INPUT); + /* now we can finalize encryption */ + EVP_EncryptFinal_ex(this->ctx, ct_ptr, (int *)&this->total_ct_len); + // For AES-GCM, the 'len' should be '0' because there is no extra bytes used + // for padding. + ASSERT(this->total_ct_len == 0, OpenABE_ERROR_UNEXPECTED_EXTRA_BYTES); + + /* retrieve the tag */ + int tag_len = AES_BLOCK_SIZE; + uint8_t tag_ptr[tag_len + 1]; + memset(tag_ptr, 0, tag_len + 1); + EVP_CIPHER_CTX_ctrl(this->ctx, EVP_CTRL_GCM_GET_TAG, tag_len, tag_ptr); + // cout << "Tag:\n"; + // BIO_dump_fp(stdout, (const char *) tag, tag_len); + tag->appendArray(tag_ptr, tag_len); + + // house keeping + this->updateEncCount = 0; + EVP_CIPHER_CTX_free(this->ctx); + this->ctx = NULL; + // clear some buffers + this->the_iv.fillBuffer(0, this->the_iv.size()); + this->aad.fillBuffer(0, this->aad.size()); + this->aad_set = false; + // reset state + this->init_enc_set = false; + } + + return result; +} + +OpenABE_ERROR OpenABESymKeyAuthEncStream::decryptInit(OpenABEByteString *iv, + OpenABEByteString *tag) { + OpenABE_ERROR result = OpenABE_NOERROR; + try { + if (!this->init_dec_set) { + /* can't mix encryptInit AND decryptInit at the same time */ + ASSERT(!this->init_enc_set, OpenABE_ERROR_INVALID_INPUT); + + ASSERT_NOTNULL(iv); + ASSERT_NOTNULL(tag); + + /* allocate cipher context */ + this->ctx = EVP_CIPHER_CTX_new(); + + /* set cipher type and mode */ + EVP_DecryptInit_ex(this->ctx, this->cipher, NULL, NULL, NULL); + /* set the IV length as 128-bits (or 16 bytes) */ + EVP_CIPHER_CTX_ctrl(this->ctx, EVP_CTRL_GCM_SET_IVLEN, iv->size(), NULL); + /* specify key and iv */ + // cout << "Deckey:\n"; + // BIO_dump_fp(stdout, (const char *) this->key->getInternalPtr(), + // this->key->getLength()); + EVP_DecryptInit_ex(this->ctx, NULL, NULL, this->key->getInternalPtr(), + iv->getInternalPtr()); + + /* set the tag BEFORE any calls to decrypt update + NOTE: the tag isn't checked until decrypt finalize (i.e., once we've + obtained all the blocks) */ + EVP_CIPHER_CTX_ctrl(this->ctx, EVP_CTRL_GCM_SET_TAG, tag->size(), + tag->getInternalPtr()); + this->init_dec_set = true; + this->updateDecCount = 0; + } + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR OpenABESymKeyAuthEncStream::decryptUpdate(OpenABEByteString *ciphertextBlock, + OpenABEByteString *plaintext) { + OpenABE_ERROR result = OpenABE_NOERROR; + + try { + if (this->init_dec_set) { + ASSERT_NOTNULL(ciphertextBlock); + ASSERT(ciphertextBlock->size() > 0, OpenABE_ERROR_INVALID_INPUT); + /* perform decrypt update */ + int ct_len = ciphertextBlock->size(); + uint8_t *ct_ptr = ciphertextBlock->getInternalPtr(); + int pt_len = 0; + + uint8_t pt[ct_len + 1]; + memset(pt, 0, ct_len + 1); + /* decrypt and store plaintext in pt buffer */ + EVP_DecryptUpdate(this->ctx, pt, &pt_len, ct_ptr, ct_len); + ASSERT(pt_len == ct_len, OpenABE_ERROR_BUFFER_TOO_SMALL); + /* add pt block to the given plaintext buffer */ + plaintext->appendArray(pt, (uint32_t)pt_len); + this->updateDecCount++; + } + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR OpenABESymKeyAuthEncStream::decryptFinalize(OpenABEByteString *plaintext) { + OpenABE_ERROR result = OpenABE_NOERROR; + + try { + if (this->init_dec_set && this->updateDecCount > 0) { + /* finalize decryption */ + int pt_len = plaintext->size(); + int retValue = + EVP_DecryptFinal_ex(this->ctx, plaintext->getInternalPtr(), &pt_len); + /* clear memory before the check */ + EVP_CIPHER_CTX_free(this->ctx); + this->ctx = NULL; + this->updateDecCount = 0; + // clear some buffers + this->the_iv.fillBuffer(0, this->the_iv.size()); + this->aad.fillBuffer(0, this->aad.size()); + this->aad_set = false; + this->init_dec_set = false; + + if (retValue > 0) { + /* clear memory and return OpenABE_NOERROR */ + throw OpenABE_NOERROR; + } else { + /* tag verification failed. therefore, throw a decryption failed error + */ + throw OpenABE_ERROR_DECRYPTION_FAILED; + } + } else { + throw OpenABE_ERROR_INVALID_INPUT; + } + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +} diff --git a/src/openabe.cpp b/src/openabe.cpp new file mode 100644 index 00000000..9ff92a94 --- /dev/null +++ b/src/openabe.cpp @@ -0,0 +1,485 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file openabe.cpp +/// +/// \brief Main implementation for the Zeutro Toolkit (OpenABE). +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __OPENABE_CPP__ + +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Library global variables + ********************************************************************************/ + +// flag for the library initialization state +OpenABE_STATE gLibraryState = OpenABE_STATE_UNINITIALIZED; + +// flag for initializing openssl +bool initializedOpenssl = false; + +/******************************************************************************** + * Core API + ********************************************************************************/ +namespace oabe { + +/*! + * Global initialization for the toolkit. This routine must be called before + * any others. + * + * @return OpenABE_ERROR_NONE or an error code. + */ + +static OpenABE_ERROR +OpenABE_initialize(bool init_openssl) { + OpenABE_ERROR result = OpenABE_ERROR_LIBRARY_NOT_INITIALIZED; + + // If the library is in a pre-initialized state, we can initialize it and go. + // Otherwise return an error. + if (gLibraryState == OpenABE_STATE_UNINITIALIZED) { + + // Initialize the pairing library + result = zMathInitLibrary(); + + // Initialize OpenSSL + if (init_openssl) { + openSslInitialize(); + } + + // Set the error file to stderr. + // gErrorLog = new zErrorLog(); + + // Future library pre-processing, self-checks, etc. go here. + + // Set the library state to READY + initializedOpenssl = init_openssl; + gLibraryState = OpenABE_STATE_READY; + result = OpenABE_NOERROR; + } + + return result; +} + +/*! + * Internal routine for global shutdown for the library. + * + * @return OpenABE_ERROR_NONE or an error code. + */ + +static OpenABE_ERROR +OpenABE_shutdown() { + OpenABE_ERROR result = OpenABE_NOERROR; + + // Shut down the pairing library + result = zMathShutdownLibrary(); + + /* Future library shutdown, key destruction, etc. go here. */ + if (initializedOpenssl) { + openSslCleanup(); + } + + gLibraryState = OpenABE_STATE_UNINITIALIZED; + + return result; +} + +void AssertLibInit() { + if (gLibraryState == OpenABE_STATE_UNINITIALIZED) { + throw runtime_error(OpenABE_errorToString(OpenABE_ERROR_LIBRARY_NOT_INITIALIZED)); + } +} + +/*! + * Global initialization for the toolkit (for RELIC and OpenSSL library). + * This routin should be called prior to any other OpenABE API calls. + * + */ + +void InitializeOpenABE() { + // initialize RELIC and openssl + OpenABE_ERROR rc = OpenABE_initialize(true); + if (rc != OpenABE_NOERROR) { + throw runtime_error("InitializeOpenABE: Could not initialize the OpenABE"); + } + +} + +/*! + * Global shutdown for the library. This routine should be called prior to application + * exit. + */ + +void ShutdownOpenABE() { + OpenABE_ERROR rc = OpenABE_shutdown(); + if (rc != OpenABE_NOERROR) { + throw runtime_error("ShutdownOpenABE: Could not shutdown the OpenABE"); + } +} + +void InitializeOpenABEwithoutOpenSSL() { + // initialize just RELIC (caller responsible for initializing it though) + OpenABE_initialize(false); +} + +void OpenABEStateContext::initializeThread() { + if (!isInitialized_) { + // Initialize the pairing library + zMathInitLibrary(); + } +} + +void OpenABEStateContext::shutdownThread() { + if (isInitialized_) { + // check whether we have called init already + zMathInitLibrary(); + // reset the initialization state + isInitialized_ = false; + } +} + +/*! + * Create a new OpenABEContextABE for a specific scheme type. + * + * @param[in] a RNG object + * @param[in] the scheme type + * @return A pointer to the OpenABE context structure + */ + +OpenABEContextABE *OpenABE_createContextABE(unique_ptr *rng, + OpenABE_SCHEME scheme_type) { + OpenABEContextABE *newContext = NULL; + + /* Depending on the scheme, set up the context using the appropriate + * constructor. + * This will set appropriate function pointers within the context so the other + * calls won't require a switch statement. */ + switch (scheme_type) { + case OpenABE_SCHEME_CP_WATERS: + newContext = (OpenABEContextABE *)new OpenABEContextCPWaters(move(*rng)); + break; + case OpenABE_SCHEME_KP_GPSW: + newContext = (OpenABEContextABE *)new OpenABEContextKPGPSW(move(*rng)); + break; + default: + // gErrorLog.log("Could not instantiate unknown scheme type", __LINE__, + // __FILE__); + newContext = NULL; + } + + return newContext; +} + +/*! + * Create a new OpenABEContextScheme for a specific scheme type (for CPA security). + * + * @param[in] the scheme type + * @return A pointer to the OpenABE context structure + */ + +unique_ptr +OpenABE_createContextABESchemeCPA(OpenABE_SCHEME scheme_type) { + unique_ptr rng(new OpenABERNG); + unique_ptr kemContext(OpenABE_createContextABE(&rng, scheme_type)); + return unique_ptr(new OpenABEContextSchemeCPA(move(kemContext))); +} + +unique_ptr OpenABE_createABEContextForKEM(OpenABE_SCHEME scheme_type) { + unique_ptr kemContextCCA; + // create a scheme context for a given scheme type + unique_ptr schemeContext = + OpenABE_createContextABESchemeCPA(scheme_type); + if (!schemeContext) { + throw OpenABE_ERROR_INVALID_SCHEME_ID; + } + // create a CCA context (KEM version) based on the scheme context + kemContextCCA.reset(new OpenABEContextGenericCCA(std::move(schemeContext))); + + return kemContextCCA; +} + +/*! + * Create a new OpenABEContextSchemeCCA for a specific scheme type (for CCA security). + * + * @param[in] the scheme type + * @return A pointer to the OpenABE context structure + */ + +unique_ptr +OpenABE_createContextABESchemeCCA(OpenABE_SCHEME scheme_type) { + unique_ptr kemContextCCA = + OpenABE_createABEContextForKEM(scheme_type); + // wrap the CCA KEM context in a CCA scheme context for use by user + return unique_ptr( + new OpenABEContextSchemeCCA(std::move(kemContextCCA))); +} + +/*! + * Create a new OpenABEContextSchemeCCAWithATZN for a specific scheme type (for CCA security). + * + * @param[in] the scheme type + * @return A pointer to the OpenABE context structure + */ + +unique_ptr +OpenABE_createContextABESchemeCCAWithATZN(OpenABE_SCHEME scheme_type) { + unique_ptr kemContextCCA = + OpenABE_createABEContextForKEM(scheme_type); + // wrap the CCA KEM context in a CCA scheme context with amortization + return unique_ptr( + new OpenABEContextSchemeCCAWithATZN(std::move(kemContextCCA))); +} + + +/*! + * Create a new OpenABEContextPKE for a specific scheme type. + * + * @param[in] a RNG object + * @param[in] the scheme type + * @return A pointer to the OpenABE context structure + */ + +OpenABEContextPKE *OpenABE_createContextPKE(unique_ptr *rng, + OpenABE_SCHEME scheme_type) { + OpenABEContextPKE *newContext = NULL; + + /* Depending on the scheme, set up the context using the appropriate + * constructor. + * This will set appropriate function pointers within the context so the other + * calls won't require a switch statement. */ + switch(scheme_type) { + case OpenABE_SCHEME_PK_OPDH: + newContext = (OpenABEContextPKE *)new OpenABEContextOPDH(std::move(*rng)); + break; + default: + // gErrorLog.log("Could not instantiate unknown scheme type", __LINE__, + // __FILE__); + newContext = NULL; + } + + return newContext; +} + +/*! + * Create a new OpenABEContextSchemePKE for a specific scheme type (includes CCA security). + * + * @param[in] the scheme type + * @return A pointer to the OpenABE context structure + */ + +unique_ptr +OpenABE_createContextPKESchemeCCA(OpenABE_SCHEME scheme_type) { + // consruct an RNG object + unique_ptr rng(new OpenABERNG); + // create a KEM context for PKE given the RNG object + unique_ptr pkeKEMContext( + OpenABE_createContextPKE(&rng, scheme_type)); + if (!pkeKEMContext) { + throw OpenABE_ERROR_INVALID_SCHEME_ID; + } + // return a scheme context for PKE given the KEM context + return unique_ptr( + new OpenABEContextSchemePKE(move(pkeKEMContext))); +} + +unique_ptr OpenABE_createContextPKSIGScheme() { + // first create a PKSIG context (wrapper around OpenSSL) + unique_ptr pksig(new OpenABEContextPKSIG); + // return a unique ptr to a PKSIG scheme context (smoothen out API) + // with an underlying PKSIG context + return unique_ptr( + new OpenABEContextSchemePKSIG(move(pksig))); +} + +/*! + * Return the OpenABE version. + * + * @return The library version as a unsigned integer. + */ + +const uint32_t OpenABE_getLibraryVersion() { + return OpenABE_LIBRARY_VERSION; +} + +/* + * elliptic curve identifiers + */ +OpenABECurveID OpenABE_getCurveID(uint8_t id) { + OpenABECurveID curveID; + switch (id) { + case OpenABE_NONE_ID: + case OpenABE_NIST_P256_ID: + case OpenABE_NIST_P384_ID: + case OpenABE_NIST_P521_ID: + case OpenABE_BN_P158_ID: + case OpenABE_BN_P254_ID: + case OpenABE_BN_P256_ID: + curveID = (OpenABECurveID)id; + break; + default: + throw OpenABE_ERROR_INVALID_CURVE_ID; + } + return curveID; +} + +void OpenABE_setGroupObject(std::shared_ptr &group, uint8_t id) { + switch (id) { + case OpenABE_NONE_ID: + case OpenABE_NIST_P256_ID: + case OpenABE_NIST_P384_ID: + case OpenABE_NIST_P521_ID: + group.reset(new ECGroup((OpenABECurveID)id)); + break; + case OpenABE_BN_P254_ID: + case OpenABE_BN_P256_ID: + case OpenABE_BN_P382_ID: + group.reset(new BPGroup((OpenABECurveID)id)); + break; + default: + throw OpenABE_ERROR_INVALID_CURVE_ID; + } +} + +/* + */ +OpenABE_SCHEME OpenABE_getSchemeID(uint8_t id) { + OpenABE_SCHEME schemeID; + switch (id) { + case OpenABE_SCHEME_NONE: + case OpenABE_SCHEME_PKSIG_ECDSA: + case OpenABE_SCHEME_AES_GCM: + case OpenABE_SCHEME_PK_OPDH: + case OpenABE_SCHEME_CP_WATERS: + case OpenABE_SCHEME_KP_GPSW: + case OpenABE_SCHEME_CP_WATERS_CCA: + case OpenABE_SCHEME_KP_GPSW_CCA: + schemeID = (OpenABE_SCHEME)id; + break; + default: + throw OpenABE_ERROR_INVALID_SCHEME_ID; + } + return schemeID; +} + +const string OpenABE_convertSchemeIDToString(OpenABE_SCHEME id) { + string scheme = ""; + switch (id) { + case OpenABE_SCHEME_NONE: + scheme = "No Scheme"; + break; + case OpenABE_SCHEME_PKSIG_ECDSA: + scheme = OpenABE_EC_DSA; + break; + case OpenABE_SCHEME_PK_OPDH: + scheme = OpenABE_PK_ENC; + break; + case OpenABE_SCHEME_CP_WATERS_CCA: + case OpenABE_SCHEME_CP_WATERS: + scheme = OpenABE_CP_ABE; + break; + case OpenABE_SCHEME_KP_GPSW_CCA: + case OpenABE_SCHEME_KP_GPSW: + scheme = OpenABE_KP_ABE; + break; + default: + throw OpenABE_ERROR_INVALID_SCHEME_ID; + } + return scheme; +} + +OpenABE_SCHEME OpenABE_convertStringToSchemeID(const string id) { + if (id == OpenABE_EC_DSA) { + return OpenABE_SCHEME_PKSIG_ECDSA; + } else if (id == OpenABE_PK_ENC) { + return OpenABE_SCHEME_PK_OPDH; + } else if (id == OpenABE_CP_ABE) { + return OpenABE_SCHEME_CP_WATERS; + } else if (id == OpenABE_KP_ABE) { + return OpenABE_SCHEME_KP_GPSW; + } else { + return OpenABE_SCHEME_NONE; + } +} + +string OpenABE_convertCurveIDToString(OpenABECurveID id) { + switch (id) { + case OpenABE_NIST_P256_ID: + return "NIST_P256"; + break; + case OpenABE_NIST_P384_ID: + return "NIST_P384"; + break; + case OpenABE_NIST_P521_ID: + return "NIST_P521"; + break; + case OpenABE_BN_P254_ID: + return "BN_P254"; + break; + case OpenABE_BN_P256_ID: + return "BN_P256"; + break; + case OpenABE_BN_P382_ID: + return "BN_P382"; + break; + case OpenABE_BN_P638_ID: + return "BN_P638"; + break; + default: + throw OpenABE_ERROR_INVALID_PARAMS_ID; + } +} + +OpenABECurveID OpenABE_convertStringToCurveID(const string paramsID) { + OpenABECurveID curveID = OpenABE_NONE_ID; + if (paramsID == "NIST_P256") { + curveID = OpenABE_NIST_P256_ID; + } else if (paramsID == "NIST_P384") { + curveID = OpenABE_NIST_P384_ID; + } else if (paramsID == "NIST_P521") { + curveID = OpenABE_NIST_P521_ID; + } else if (paramsID == "BN_P256") { + curveID = OpenABE_BN_P256_ID; + } else if (paramsID == "BN_P382") { + curveID = OpenABE_BN_P382_ID; + } else { + // Unrecognized parameter type + throw OpenABE_ERROR_INVALID_PARAMS_ID; + } + + return curveID; +} + +} diff --git a/src/openssl_init.cpp b/src/openssl_init.cpp new file mode 100644 index 00000000..6c8dbaca --- /dev/null +++ b/src/openssl_init.cpp @@ -0,0 +1,126 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file openssl_init.cpp +/// +/// \brief Initialize and cleanup OpenSSL +/// +/// \author Alan Dunn +/// + +#define __OPENSSL_INIT_CPP__ + +#include +#include +#include +#include +#include +#include + +#if defined(SSL_LIB_INIT) + +#ifndef SSL_library_init + #define SSL_library_init() OPENSSL_init_ssl(0, NULL) +#endif + +#ifndef SSL_load_error_strings + #define SSL_load_error_strings() \ + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS \ + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL) +#endif + +#endif + +using namespace std; + +struct CRYPTO_dynlock_value { + mutex the_mutex; +}; + +static unique_ptr mutexes; + +static void lockingCallback(int mode, int n, const char*, int) { + if (mode & CRYPTO_LOCK) { + mutexes[n].lock(); + } else { + mutexes[n].unlock(); + } +} + +static CRYPTO_dynlock_value* dynlockCreate(const char*, int) { + return new CRYPTO_dynlock_value; +} + +static void dynlockLock(int mode, + struct CRYPTO_dynlock_value* lock, + const char*, int) { + if (lock != nullptr) { + if (mode & CRYPTO_LOCK) { + lock->the_mutex.lock(); + } else { + lock->the_mutex.unlock(); + } + } +} + +static void dynlockDestroy(struct CRYPTO_dynlock_value* lock, + const char*, int) { + delete lock; +} + +void openSslInitialize() { +#if defined(SSL_LIB_INIT) + SSL_library_init(); + SSL_load_error_strings(); +#endif + // static locking + mutexes.reset(new mutex[CRYPTO_num_locks()]); + if (mutexes == nullptr) { + throw runtime_error("openSslInitialize() failed, " + "out of memory while creating mutex array"); + } + CRYPTO_set_locking_callback(lockingCallback); + // dynamic locking + CRYPTO_set_dynlock_create_callback(dynlockCreate); + CRYPTO_set_dynlock_lock_callback(dynlockLock); + CRYPTO_set_dynlock_destroy_callback(dynlockDestroy); + + RAND_poll(); +} + +void openSslCleanup() { + // dynamic cleanup + CRYPTO_set_dynlock_create_callback(nullptr); + CRYPTO_set_dynlock_lock_callback(nullptr); + CRYPTO_set_dynlock_destroy_callback(nullptr); + // static cleanup + CRYPTO_set_locking_callback(nullptr); + // library cleanup + ERR_free_strings(); + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); + mutexes.reset(); +} diff --git a/src/pke/zcontextpke.cpp b/src/pke/zcontextpke.cpp new file mode 100644 index 00000000..e99fb36e --- /dev/null +++ b/src/pke/zcontextpke.cpp @@ -0,0 +1,725 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextpke.cpp +/// +/// \brief Implementation for OpenABE context PKE schemes. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEContextPKE class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEContextPKE base class. + * + */ +OpenABEContextPKE::OpenABEContextPKE() : OpenABEContext() {} + +/*! + * Destructor for the OpenABEContextPKE base class. + * + */ +OpenABEContextPKE::~OpenABEContextPKE() {} + +/*! + * Initialize the elliptic curve structure in underlying math library + * + * @param String for initializing the group parameters + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextPKE::initializeCurve(const string groupParams) { + OpenABE_ERROR result = OpenABE_NOERROR; + if (this->m_EllipticCurve_ != nullptr) { + return result; + } + + // Instantiate a OpenABE elliptic curve object with the given parameters + this->m_EllipticCurve_.reset(OpenABE_createNewEllipticCurve(groupParams)); + if (this->m_EllipticCurve_ == nullptr) { + throw OpenABE_ERROR_INVALID_GROUP_PARAMS; + } + + return result; +} + +/*! + * Select the elliptic curve based on the given security level. + * + * @param[in] Security level for the scheme. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextPKE::generateParams(OpenABESecurityLevel securityLevel) { + string ecParams = OpenABE_ECParamsForSecurityLevel(securityLevel); + + if (ecParams == "") { + return OpenABE_ERROR_INVALID_GROUP_PARAMS; + } + + return this->generateParams(ecParams); +} + + +/******************************************************************************** + * Implementation of the OpenABEContextOPDH class + ********************************************************************************/ + +/*! + * Constructor for the OpenABEContextOPDH base class. + * + */ +OpenABEContextOPDH::OpenABEContextOPDH(std::unique_ptr rng) : OpenABEContextPKE() { + // set the random number generator on initialization + this->m_RNG_ = std::move(rng); + this->algID = OpenABE_SCHEME_PK_OPDH; +} + +/*! + * Destructor for the OpenABEContextOPDH base class. + */ +OpenABEContextOPDH::~OpenABEContextOPDH() {} + +/*! + * Generate parameters of the elliptic curve based on a string identifier. + * + * @param[in] Specific elliptic curve to load for the scheme. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextOPDH::generateParams(const string groupParams) { + OpenABE_ERROR result = OpenABE_NOERROR; + + try { + // Instantiate a OpenABE elliptic curve object with the given parameters + this->initializeCurve(groupParams); + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +/*! + * Generate a public/private keypair for a given user. + * + * @param[in] identifier for the decryption key to be created. + * @param[in] parameter ID of the Public Key + * @param[in] parameter ID of the Secret Key + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextOPDH::generateDecryptionKey(const string &keyID, const string &pkID, + const string &skID) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr PK = nullptr, SK = nullptr; + OpenABEByteString uid; + OpenABERNG *myRNG = this->getRNG(); + + try { + // Assert that the RNG has been set + ASSERT_NOTNULL(myRNG); + // generate a random UID for PK/SK + myRNG->getRandomBytes(&uid, UID_LEN); + // select generator of the curve + G_t g = this->getECCurve()->getGenerator(); + // generate static public and private keys + ZP_t a = this->getECCurve()->randomZP(myRNG); + // A = g ^ a + G_t A = g.exp(a); + + // initialize containers for the keys + PK.reset(new OpenABEKey(this->getECCurve()->getCurveID(), OpenABE_SCHEME_PK_OPDH, + keyID, &uid)); + SK.reset(new OpenABEKey(this->getECCurve()->getCurveID(), OpenABE_SCHEME_PK_OPDH, + keyID, &uid)); + + PK->setComponent("A", &A); + SK->setComponent("a", &a); + + // Add (MPK, MSK) to the keystore + this->getKeystore()->addKey(pkID, PK, KEY_TYPE_PUBLIC); + this->getKeystore()->addKey(skID, SK, KEY_TYPE_SECRET); + + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +/*! + * Generate and encrypt a symmetric key using the key encapsulation mode + * of the scheme. Return the key and ciphertext. + * + * @param[in] random number generator to use during encryption (it is optional: could be set to NULL here). + * @param[in] public key identifier in keystore for the recipient (assumes it's already in keystore). + * @param[in] public key UID for sender. + * @param[in] length of the symmetric key. + * @param[out] symmetric key to be returned (must be allocated). + * @param[out] PKE ciphertext (must be allocated). + * @return An error code or OpenABE_NOERROR. + */ + +OpenABE_ERROR +OpenABEContextOPDH::encryptKEM(OpenABERNG *rng, const string &pkID, + OpenABEByteString *senderID, uint32_t keyBitLen, + const std::shared_ptr &key, + OpenABECiphertext *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABERNG *myRNG = this->getRNG(); + + try { + // check inputs + ASSERT_NOTNULL(senderID); + ASSERT_NOTNULL(ciphertext); + ASSERT_NOTNULL(key); + + // check if the RNG has been set or not + if (rng != nullptr) { + myRNG = rng; + } + ASSERT_NOTNULL(myRNG); + // load the recipient's public key + shared_ptr PK = this->getKeystore()->getPublicKey(pkID); + if (PK == nullptr) { + throw OpenABE_ERROR_MISSING_RECEIVER_PUBLIC_KEY; + } + // select generator of the curve + G_t g = this->getECCurve()->getGenerator(); + // select ephemeral private keyL e <-$- ZP + ZP_t e = this->getECCurve()->randomZP(myRNG); + // compute ephemeral public key: C = g^e + G_t C = g.exp(e); + // store C in ciphertext + ciphertext->setComponent("C", &C); + + // compute P = A ^ e => shared key: g^(a*e) + G_t *A = PK->getG_t("A"); + ASSERT_NOTNULL(A); + + G_t P = A->exp(e); + ZP_t x, y; + P.get(x, y); + OpenABEByteString Z = x.getByteString(); + + // compute the metadata + OpenABEByteString kdfMetadata; + // kdf_metadata required: AlgID || ID_Sender || ID_Recipient + kdfMetadata.insertFirstByte(OpenABE_SCHEME_PK_OPDH); + kdfMetadata = kdfMetadata + *senderID + PK->getUID(); + + unique_ptr kdf(new OpenABEKDF); + OpenABEByteString DerivedKeyMaterial = + kdf->DeriveKey(Z, keyBitLen, kdfMetadata); + // return the derived key material + key->setSymmetricKey(DerivedKeyMaterial); + // set the ciphertext header (curve ID, scheme ID, etc) + ciphertext->setHeader(this->getECCurve()->getCurveID(), OpenABE_SCHEME_PK_OPDH, + myRNG); + // clear memory + DerivedKeyMaterial.zeroize(); + kdfMetadata.clear(); + Z.clear(); + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +/*! + * Decrypt a symmetric key using the key encapsulation mode + * of the scheme. Return the key. + * + * @param[in] public key identifier of the sender (assumes it's already in keystore). + * @param[in] secret key identifier of recipient (assumes it's already in keystore). + * @param[in] PKE ciphertext. + * @param[out] symmetric key to be returned. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextOPDH::decryptKEM(const string &pkID, const string &skID, + OpenABECiphertext *ciphertext, uint32_t keyBitLen, + const std::shared_ptr &key) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr SK = nullptr, PK = nullptr; + OpenABEByteString senderID; + unique_ptr kdf = nullptr; + // compute the metadata + OpenABEByteString kdfMetadata; + try { + // check inputs + ASSERT_NOTNULL(ciphertext); + ASSERT_NOTNULL(key); + + // load the sender's public key + PK = this->getKeystore()->getPublicKey(pkID); + if (PK == nullptr) { + throw OpenABE_ERROR_MISSING_SENDER_PUBLIC_KEY; + } + senderID = PK->getUID(); + + // load the recipient's private key + SK = this->getKeystore()->getSecretKey(skID); + if (SK == nullptr) { + throw OpenABE_ERROR_MISSING_RECEIVER_PRIVATE_KEY; + } + + // compute C ^ (recipient's private key) + // to obtain the shared key + G_t *C = ciphertext->getG_t("C"); + ASSERT_NOTNULL(C); + ZP_t *a = SK->getZP_t("a"); + ASSERT_NOTNULL(a); + G_t P = C->exp(*a); + // extract x-coordinate from group element P + ZP_t x, y; + P.get(x, y); + OpenABEByteString Z = x.getByteString(); + + // kdf_metadata required: AlgID || ID_Sender || ID_Recipient + kdfMetadata.insertFirstByte(OpenABE_SCHEME_PK_OPDH); + kdfMetadata = kdfMetadata + senderID + SK->getUID(); + + kdf.reset(new OpenABEKDF); + OpenABEByteString DerivedKeyMaterial = + kdf->DeriveKey(Z, keyBitLen, kdfMetadata); + + // return the derived key material + key->setSymmetricKey(DerivedKeyMaterial); + + // clear memory + DerivedKeyMaterial.zeroize(); + kdfMetadata.zeroize(); + Z.zeroize(); + + } catch (OpenABE_ERROR &err) { + result = err; + } + + return result; +} + +/*! + * + * Section 5.6.2.5 ECC Full Public Key Validation Routine. + * + * @param[in] A OpenABEKey public key to be validated. + * @return true or false. + */ +bool OpenABEContextOPDH::validatePublicKey(const std::shared_ptr &key) { + ASSERT_NOTNULL(key); + G_t *A = key->getG_t("A"); + /* make sure element exists in OpenABEKey structure */ + ASSERT_NOTNULL(A); + + /* retrieve the order of the EC points */ + ZP_t p = this->getECCurve()->getGroupOrder(); + ZP_t pMin1 = p; + pMin1 -= 1; + + /* 1. verify that public key Q is not the point at infinity O + also, partial check of the public key for an invalid range in the EC group + */ + if (this->getECCurve()->isAtInfinity(*A)) { + return false; + } + + /* 2. verify that Q->x and Q->y are integers in the interval [0,p-1] in the + case + that q is an odd prime p */ + ZP_t x, y; + A->get(x, y); + if (x >= pMin1 || y >= pMin1) { + return false; + } + + /* 3. Ensures that the public key is on the correct elliptic curve. */ + if (!this->getECCurve()->isOnCurve(*A)) { + return false; + } + + /* 4. Ensures that the public key has the correct order. Verify that n*Q == + * infinity. */ + // Also, ensures that the public key is in the correct range in the + // correct EC subgroup, that is, it is in the + // correct EC subgroup and is not the identity element. + G_t R = A->exp(p); + if (!this->getECCurve()->isAtInfinity(R)) { + return false; + } + + return true; +} + +/*! + * + * Section 5.6.2.5 ECC Full Private Key Validation Routine. + * + * @param[in] A OpenABEKey private key to be validated. + * @return true or false. + */ +bool OpenABEContextOPDH::validatePrivateKey(const std::shared_ptr &key) { + ASSERT_NOTNULL(key); + ZP_t *a = key->getZP_t("a"); + ASSERT_NOTNULL(a); + /* retrieve the order of the EC points */ + ZP_t p = this->getECCurve()->getGroupOrder(); + ZP_t pMin1 = p; + pMin1 -= 1; + + if (*a >= pMin1) { + return false; + } + + return true; +} + +/******************************************************************************** + * Implementation of the OpenABEContextSchemePKE class + ********************************************************************************/ + +/*! + * Constructor for the OpenABEContextSchemePKE base class. + * + */ +OpenABEContextSchemePKE::OpenABEContextSchemePKE(std::unique_ptr kem) { + this->m_KEM_ = std::move(kem); +} + +/*! + * Destructor for the OpenABEContextSchemePKE base class. + * + */ +OpenABEContextSchemePKE::~OpenABEContextSchemePKE() {} + +/*! + * Generate parameters of the elliptic curve based on a string identifier. + * + * @param[in] Specific elliptic curve to load for the scheme. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemePKE::generateParams(const string groupParams) { + return this->m_KEM_->generateParams(groupParams); +} + +/*! + * Generate a public/private keypair for a given user. + * + * @param[in] identifier for the decryption key to be created. + * @param[in] parameter ID of the Public Key + * @param[in] parameter ID of the Secret Key + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemePKE::keygen(const string &keyID, const string &pkID, + const string &skID) { + return this->m_KEM_->generateDecryptionKey(keyID, pkID, skID); +} + +/*! + * Export a key from the keystore given the key identifier. + * + * @param[in] identifier for the key. + * @param[out] an allocated OpenABEByteString to store the exported key header/body. + * @param[in] a password to encrypt the exported key under (optional). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemePKE::exportKey(const string &keyID, OpenABEByteString &keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString tmpKeyBlob; + + try { + // Attempt to export the given keyID to a temp keyBlob output buffer + if (OpenABE_exportKey(this->m_KEM_->getKeystore(), keyID, &tmpKeyBlob) != + OpenABE_NOERROR) { + throw OpenABE_ERROR_INVALID_INPUT; + } + + // Just set the keyBlob + keyBlob.clear(); + keyBlob += tmpKeyBlob; + // Clear the temp buffer + tmpKeyBlob.zeroize(); + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +/*! + * Load a public key into the keystore given a key identifier and blob of bytes. + * + * @param[in] identifier for the key. + * @param[in] a OpenABEByteString to load the key header/body. + * @param[in] a password to decrypt the key blob under (optional). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemePKE::loadPublicKey(const string &keyID, OpenABEByteString &keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr PK = nullptr; + + try { + // Parse the result into a OpenABEKey structure + OpenABEByteString outputKeyBytes; + PK = this->m_KEM_->getKeystore()->constructKeyFromBytes(keyID, keyBlob, + outputKeyBytes); + if (PK == nullptr) { + throw OpenABE_ERROR_INVALID_INPUT; + } + + // Initialize the curve if ec parameters are not set + if (this->m_KEM_->getECCurve() == nullptr) { + // Set parameters based on the PK's curve ID + this->m_KEM_->initializeCurve( + OpenABE_convertECCurveIDToString(PK->getCurveID())); + } + + if (PK->getCurveID() != this->m_KEM_->getECCurve()->getCurveID() || + PK->getAlgorithmID() != this->m_KEM_->getAlgorithmID()) { + throw OpenABE_ERROR_INVALID_KEY_HEADER; + } + + // Now we can deserialize the body of the key + PK->setGroup(this->m_KEM_->getECCurve()->getGroup()); + PK->loadKeyFromBytes(outputKeyBytes); + + // Perform validation on the public OpenABEKey structure + if (this->m_KEM_->validatePublicKey(PK)) { + // If all goes well, then add the constructed key to the keystore + this->m_KEM_->getKeystore()->addKey(keyID, PK, KEY_TYPE_PUBLIC); + } else { + throw OpenABE_ERROR_INVALID_PARAMS; + } + + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +/*! + * Load a private key into the keystore given a key identifier and blob of bytes. + * + * @param[in] identifier for the key. + * @param[in] a OpenABEByteString to load the key header/body. + * @param[in] a password to decrypt the key blob under (optional). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemePKE::loadPrivateKey(const string &keyID, OpenABEByteString &keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr SK = nullptr; + + try { + // Parse the keyBlob into a OpenABEKey structure + OpenABEByteString outputKeyBytes; + SK = this->m_KEM_->getKeystore()->constructKeyFromBytes(keyID, keyBlob, + outputKeyBytes); + if (SK == nullptr) { + throw OpenABE_ERROR_INVALID_INPUT; + } + // Initialize the curve if ec parameters are not set + if (this->m_KEM_->getECCurve() == nullptr) { + // Set parameters based on the PK's curve ID + this->m_KEM_->initializeCurve( + OpenABE_convertECCurveIDToString(SK->getCurveID())); + } + + if (SK->getCurveID() != this->m_KEM_->getECCurve()->getCurveID() || + SK->getAlgorithmID() != this->m_KEM_->getAlgorithmID()) { + throw OpenABE_ERROR_INVALID_KEY_HEADER; + } + + // Now we can deserialize the body of the key + SK->setGroup(this->m_KEM_->getECCurve()->getGroup()); + SK->loadKeyFromBytes(outputKeyBytes); + // Perform validation on the private OpenABEKey + if (this->m_KEM_->validatePrivateKey(SK)) { + // If all goes well, then add the constructed key to the keystore + this->m_KEM_->getKeystore()->addKey(keyID, SK, KEY_TYPE_SECRET); + } else { + throw OpenABE_ERROR_INVALID_PARAMS; + } + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +/*! + * Delete a key from the in-memory keystore given a key identifier. + * + * @param[in] a string key identifier. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemePKE::deleteKey(const string &keyID) { + return this->m_KEM_->getKeystore()->deleteKey(keyID); +} + +/*! + * Generate and encrypt a symmetric key using the key encapsulation mode + * of the underlying scheme. Use the symmetric key with AES-GCM to encrypt + * the plaintext. Return the ciphertext. + * + * @param[in] random number generator to use during encryption (it is optional: could be set to NULL here). + * @param[in] public key identifier in keystore for the recipient (assumes it's already in keystore). + * @param[in] public key UID for sender. + * @param[in] the plaintext. + * @param[out] PKE ciphertext (must be allocated). + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemePKE::encrypt(OpenABERNG *rng, const string &pkID, + const string &senderpkID, const string &plaintext, + OpenABECiphertext *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr senderPK = nullptr; + OpenABEByteString senderID, keyBytes, ctHdr, iv, ct, tag; + shared_ptr key(new OpenABESymKey); + unique_ptr authEnc = nullptr; + + try { + ASSERT_NOTNULL(ciphertext); + // make sure plaintext size > 0 + ASSERT(plaintext.size() > 0, OpenABE_ERROR_NO_PLAINTEXT_SPECIFIED); + + // Get PK of sender (assumes it has already been loaded) + senderPK = this->m_KEM_->getKeystore()->getPublicKey(senderpkID); + if (senderPK == nullptr) { + throw OpenABE_ERROR_MISSING_SENDER_PUBLIC_KEY; + } + senderID = senderPK->getUID(); + // Returns a ciphertext and a symmetric key + result = this->m_KEM_->encryptKEM(rng, pkID, &senderID, + DEFAULT_SYM_KEY_BITS, key, ciphertext); + // Propagate errors from encryptKEM + ASSERT(result == OpenABE_NOERROR, result); + + // Instantiate an auth enc scheme with the symmetric key + keyBytes = key->getKeyBytes(); + authEnc.reset( + new oabe::crypto::OpenABESymKeyAuthEnc(DEFAULT_AES_SEC_LEVEL, keyBytes)); + // Obtain header from ciphertext + ciphertext->getHeader(ctHdr); + // Embed the header of the ciphertext as AAD + authEnc->setAddAuthData(ctHdr); + // Encrypt + authEnc->encrypt(plaintext, &iv, &ct, &tag); + // Store symmetric ciphertext + ciphertext->setComponent("IV", &iv); + ciphertext->setComponent("CT", &ct); + ciphertext->setComponent("Tag", &tag); + } catch (OpenABE_ERROR &error) { + result = error; + } + + key->zeroize(); + keyBytes.zeroize(); + return result; +} + +/*! + * Decrypt a symmetric key using the key encapsulation mode + * of the underlying scheme. Use the key with AES-GCM to decrypt + * the other half of the ciphertext payload. Return the plaintext. + * + * @param[in] public key identifier of the sender (assumes it's already in + * keystore). + * @param[in] secret key identifier of recipient (assumes it's already in + * keystore). + * @param[out] OpenABEByteString object to store resulting plaintext (assumes it's + * already allocated). + * @param[in] PKE ciphertext. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR +OpenABEContextSchemePKE::decrypt(const string &pkID, const string &skID, + string &plaintext, OpenABECiphertext *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr key(new OpenABESymKey); + unique_ptr authEnc = nullptr; + OpenABEByteString *iv = nullptr, *ct = nullptr, *tag = nullptr; + OpenABEByteString ctHdr, keyBytes; + + try { + result = this->m_KEM_->decryptKEM(pkID, skID, ciphertext, + DEFAULT_SYM_KEY_BITS, key); + // propagate errors from decryptKEM + ASSERT(result == OpenABE_NOERROR, result); + + // construct the 'ct' structure from ciphertext then decrypt + iv = ciphertext->getByteString("IV"); + ASSERT_NOTNULL(iv); + ct = ciphertext->getByteString("CT"); + ASSERT_NOTNULL(ct); + tag = ciphertext->getByteString("Tag"); + ASSERT_NOTNULL(tag); + + // Instantiate an auth enc scheme with the symmetric key + keyBytes = key->getKeyBytes(); + authEnc.reset( + new oabe::crypto::OpenABESymKeyAuthEnc(DEFAULT_AES_SEC_LEVEL, keyBytes)); + // embed the header of the ciphertext + ciphertext->getHeader(ctHdr); + // embed the header of the ciphertext as AAD + authEnc->setAddAuthData(ctHdr); + + if (!authEnc->decrypt(plaintext, iv, ct, tag)) { + throw OpenABE_ERROR_DECRYPTION_FAILED; + } + } catch (OpenABE_ERROR &error) { + result = error; + } + + key->zeroize(); + keyBytes.zeroize(); + return result; +} +} diff --git a/src/pksig/zcontextpksig.cpp b/src/pksig/zcontextpksig.cpp new file mode 100644 index 00000000..0f578441 --- /dev/null +++ b/src/pksig/zcontextpksig.cpp @@ -0,0 +1,451 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextpksig.cpp +/// +/// \brief Implementation for OpenABE context PKSIG schemes. +/// +/// \author J. Ayo Akinyele +/// +/// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEContextPKSIG class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEContextPKSIG base class. + * + */ +OpenABEContextPKSIG::OpenABEContextPKSIG(): OpenABEContext() { + this->group = nullptr; +} + +/*! + * Destructor for the OpenABEContextPKSIG base class. + * + */ +OpenABEContextPKSIG::~OpenABEContextPKSIG() { + if(this->group != nullptr) { + EC_GROUP_free(this->group); + } +} + +OpenABE_ERROR +OpenABEContextPKSIG::initializeCurve(const std::string groupParams) { + try { + if(this->group == nullptr) { + generateECCurveParameters(&this->group, groupParams); + ASSERT_NOTNULL(this->group); + } + } catch(OpenABE_ERROR& error) { + return error; + } + + return OpenABE_NOERROR; +} + +OpenABE_ERROR +OpenABEContextPKSIG::generateParams(const std::string groupParams) { + OpenABE_ERROR result = OpenABE_NOERROR; + + try { + // initialize the group (if not already) + this->initializeCurve(groupParams); + + // ***Important*** + // The ASN1 flag causes OpenSSL to maintain curve names in the + // keys it saves. This is necessary for TLS to work properly + // (without enabling generic EC group support in TLS options, + // which maybe you can do?) + EC_GROUP_set_asn1_flag(this->group, OPENSSL_EC_NAMED_CURVE); + + } catch(OpenABE_ERROR& error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextPKSIG::keygen(const std::string &pkID, const std::string &skID) { + OpenABE_ERROR result = OpenABE_NOERROR; + EC_KEY *ec_key = nullptr; + shared_ptr pubKey = nullptr, privKey = nullptr; + + try { + ASSERT_NOTNULL(this->group); + + ec_key = EC_KEY_new(); + ASSERT_NOTNULL(ec_key); + + if (EC_KEY_set_group(ec_key, this->group) == 0) { + throw OpenABE_ERROR_INVALID_GROUP_PARAMS; + } + + // generate ECDSA keys and store inside the ec_key object + if (!EC_KEY_generate_key(ec_key)) { + throw OpenABE_ERROR_KEYGEN_FAILED; + } + + // now split the EC_KEY into public and private key structures + // and instantiate the OpenABEPKey objects + pubKey.reset(new OpenABEPKey(ec_key, false, this->group)); + privKey.reset(new OpenABEPKey(ec_key, true)); + + // add the keys to the keystore + this->getKeystore()->addKey(pkID, pubKey, KEY_TYPE_PUBLIC); + this->getKeystore()->addKey(skID, privKey, KEY_TYPE_SECRET); + + } catch(OpenABE_ERROR& error) { + result = error; + } + + return result; +} + + +OpenABE_ERROR +OpenABEContextPKSIG::sign(OpenABEPKey *privKey, OpenABEByteString *message, OpenABEByteString *signature) { + OpenABE_ERROR result = OpenABE_NOERROR; + EVP_MD_CTX* md = nullptr; + string error_msg = ""; + size_t siglen = 0; + uint8_t *sig = nullptr; + + ASSERT_NOTNULL(privKey); + ASSERT_NOTNULL(message); + ASSERT_NOTNULL(signature); + + md = EVP_MD_CTX_create(); + if (!md) { + error_msg = "EVP_MD_CTX_create"; + goto out; + } + + if (EVP_DigestSignInit(md, NULL, EVP_sha256(), NULL, privKey->getPkey()) != 1) { + error_msg = "EVP_DigestSignInit"; + goto out; + } + + if (EVP_DigestSignUpdate(md, message->getInternalPtr(), message->size()) != 1) { + error_msg = "EVP_DigestSignUpdate"; + goto out; + } + + if (EVP_DigestSignFinal(md, NULL, &siglen) != 1) { + error_msg = "EVP_DigestSignFinal(determine siglen)"; + goto out; + } + + // using openssl malloc instead of OpenABEByteString->fillBuffer + // to avoid trailing zero bytes. Trailing zero bytes + // invalidates ECDSA_verify DER encoding/decoding test. + // NOTE: this was exposed by recent improvements + // in openssl-1.0.1l + sig = (uint8_t *)OPENSSL_malloc((unsigned int)siglen); + if (sig == nullptr) { + error_msg = "OPENSSL_malloc failed in OpenABEContextPKSIG::sign"; + goto out; + } + // Extract the signature + if (EVP_DigestSignFinal(md, sig, &siglen) != 1) { + error_msg = "EVP_DigestSignFinal(output sig)"; + goto out; + } + // return sig as a OpenABEByteString + signature->clear(); + signature->appendArray(sig, siglen); +out: + if (md) { + EVP_MD_CTX_destroy(md); + } + + if(error_msg != "") { + OpenABE_LOG(error_msg); + result = OpenABE_ERROR_SIGNATURE_FAILED; + } + + if (sig != NULL) { + OPENSSL_cleanse((char *)sig, siglen); + OPENSSL_free(sig); + } + return result; +} + +OpenABE_ERROR +OpenABEContextPKSIG::verify(OpenABEPKey *pubKey, OpenABEByteString *message, OpenABEByteString *signature) { + OpenABE_ERROR result = OpenABE_NOERROR; + EVP_MD_CTX* md = NULL; + string error_msg = ""; + bool answer; + ASSERT_NOTNULL(pubKey); + ASSERT_NOTNULL(message); + ASSERT_NOTNULL(signature); + + md = EVP_MD_CTX_create(); + if (!md) { + error_msg = "EVP_MD_CTX_create"; + goto out; + } + + if (EVP_DigestVerifyInit(md, NULL, EVP_sha256(), NULL, pubKey->getPkey()) != 1) { + error_msg = "EVP_DigestVerifyInit"; + goto out; + } + + if (EVP_DigestVerifyUpdate(md, message->getInternalPtr(), message->size()) != 1) { + error_msg = "EVP_DigestVerifyUpdate"; + goto out; + } + + answer = (EVP_DigestVerifyFinal(md, (unsigned char*)signature->getInternalPtr(), signature->size()) == 1); + if(!answer) { + error_msg = "EVP_DigestVerifyFinal failed"; + goto out; + } + +out: + if (md) { + EVP_MD_CTX_destroy(md); + } + + if(error_msg != "") { + OpenABE_LOG(error_msg); + result = OpenABE_ERROR_VERIFICATION_FAILED; + } + + return result; +} + +bool +OpenABEContextPKSIG::validatePkey(EVP_PKEY* pkey, bool expectPrivate) { + EC_KEY* eckey; + const EC_GROUP* group; + bool result = false; + bool hasPrivate; + + eckey = EVP_PKEY_get1_EC_KEY(pkey); + if (!eckey) { + // Wrong key type + goto out; + } + group = EC_KEY_get0_group(eckey); + if (!group) { + // Shouldn't happen + goto out; + } + // Check public versus private key + hasPrivate = (EC_KEY_get0_private_key(eckey) != NULL); + if (hasPrivate != expectPrivate) { + goto out; + } + + // Success + result = true; + + out: + if (eckey) { + EC_KEY_free(eckey); + } + + return result; +} + +bool +OpenABEContextPKSIG::validatePublicKey(const shared_ptr& key) { + ASSERT_NOTNULL(key); + return this->validatePkey(key->getPkey(), false); +} + + +bool +OpenABEContextPKSIG::validatePrivateKey(const std::shared_ptr& key) { + ASSERT_NOTNULL(key); +// return this->validatePkey(key->getPkey(), true); + return true; +} + + +/******************************************************************************** + * Implementation of the OpenABEContextSchemePKSIG class + ********************************************************************************/ + +OpenABEContextSchemePKSIG::OpenABEContextSchemePKSIG(unique_ptr pksig): ZObject() { + m_PKSIG = move(pksig); +} + +OpenABEContextSchemePKSIG::~OpenABEContextSchemePKSIG() { +} + +OpenABE_ERROR +OpenABEContextSchemePKSIG::exportKey(const string &keyID, OpenABEByteString &keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + + try { + // attempt to export the given keyID to a temp keyBlob output buffer (without a header) + shared_ptr key = this->m_PKSIG->getKeystore()->getKey(keyID); + if(key == nullptr) { + throw OpenABE_ERROR_INVALID_INPUT; + } + + // convert to pkey + shared_ptr pkey = static_pointer_cast(key); + ASSERT_NOTNULL(pkey); + // export key to bytes + pkey->exportKeyToBytes(keyBlob); + } catch(OpenABE_ERROR& error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextSchemePKSIG::loadPrivateKey(const std::string &keyID, OpenABEByteString &keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr SK = nullptr; + bool isPrivate = true; + + try { + // now we can deserialize the key directly + SK.reset(new OpenABEPKey(isPrivate)); + SK->loadKeyFromBytes(keyBlob); + + if(this->m_PKSIG->validatePrivateKey(SK)) { + // if validation successful, then add to the keystore + this->m_PKSIG->getKeystore()->addKey(keyID, SK, KEY_TYPE_SECRET); + } + else { + throw OpenABE_ERROR_INVALID_PARAMS; + } + + } catch(OpenABE_ERROR& error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextSchemePKSIG::loadPublicKey(const std::string &keyID, OpenABEByteString &keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr PK = nullptr; + bool isPrivate = false; + + try { + // now we can deserialize the key directly + PK.reset(new OpenABEPKey(isPrivate)); + PK->loadKeyFromBytes(keyBlob); + + if(this->m_PKSIG->validatePublicKey(PK)) { + // if validation successful, then add to the keystore + this->m_PKSIG->getKeystore()->addKey(keyID, PK, KEY_TYPE_PUBLIC); + } + else { + throw OpenABE_ERROR_INVALID_PARAMS; + } + + } catch(OpenABE_ERROR& error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextSchemePKSIG::deleteKey(const string &keyID) { + return this->m_PKSIG->getKeystore()->deleteKey(keyID); +} + +OpenABE_ERROR +OpenABEContextSchemePKSIG::generateParams(const std::string groupParams) { + return this->m_PKSIG->generateParams(groupParams); +} + +OpenABE_ERROR +OpenABEContextSchemePKSIG::keygen(const std::string &pkID, const std::string &skID) { + return this->m_PKSIG->keygen(pkID, skID); +} + +OpenABE_ERROR +OpenABEContextSchemePKSIG::sign(const std::string &skID, OpenABEByteString *message, OpenABEByteString *signature) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr SK = nullptr; + + try { + ASSERT_NOTNULL(message); + ASSERT_NOTNULL(signature); + + // load the secret key from the keystore + SK = static_pointer_cast(this->m_PKSIG->getKeystore()->getSecretKey(skID)); + ASSERT_NOTNULL(SK); + + // sign the message with the key that was just loaded + result = this->m_PKSIG->sign(SK.get(), message, signature); + ASSERT(result == OpenABE_NOERROR, result); + + } catch(OpenABE_ERROR& error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextSchemePKSIG::verify(const std::string &pkID, OpenABEByteString *message, OpenABEByteString *signature) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr PK = nullptr; + + try { + ASSERT_NOTNULL(message); + ASSERT_NOTNULL(signature); + + // load the public key from the keystore + PK = static_pointer_cast(this->m_PKSIG->getKeystore()->getPublicKey(pkID)); + ASSERT_NOTNULL(PK); + + // verify the message and signature against a verification key + result = this->m_PKSIG->verify(PK.get(), message, signature); + + } catch(OpenABE_ERROR& error) { + result = error; + } + + return result; +} + +} diff --git a/src/profile_libopenabe.cpp b/src/profile_libopenabe.cpp new file mode 100644 index 00000000..c078305a --- /dev/null +++ b/src/profile_libopenabe.cpp @@ -0,0 +1,338 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file profile_libopenabe.cpp +/// +/// \brief Tool to profile specific ABE schemes +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include + +#include + +#define CPABE "CP" +#define KPABE "KP" + +#define CPA "cpa" +#define CCA "cca" + +#define KEYGEN_OP "keygen" +#define ENCRYPT_OP "encrypt" + +#define EXIT(msg) cout << msg << endl; goto CLEANUP + +using namespace std; +using namespace oabe; + +string getSchemeString(OpenABE_SCHEME scheme_type) +{ + if(scheme_type == OpenABE_SCHEME_CP_WATERS) + return "CP-ABE"; + else if(scheme_type == OpenABE_SCHEME_KP_GPSW) + return "KP-ABE"; + else + throw runtime_error("Invalid scheme type"); +} + +int profileABE_CPA_KEM(OpenABE_SCHEME scheme_type, string operation, string input_str) { + cout << "Profiling... " << getSchemeString(scheme_type) << endl; + unique_ptr context = nullptr; + unique_ptr rng(new OpenABERNG); + string mpk, msk, auth1mpk, auth1msk, decKey = "decKey"; + shared_ptr symkey = nullptr; + std::unique_ptr keyFuncInput = nullptr, encFuncInput = nullptr; + unique_ptr ciphertext = nullptr; + int policy_components = 0; + + // Initialize a OpenABEContext structure + context.reset(OpenABE_createContextABE(&rng, scheme_type)); + if (context == nullptr) { + EXIT("Unable to create a new context"); + } + + // perform context + if(scheme_type == OpenABE_SCHEME_CP_WATERS || scheme_type == OpenABE_SCHEME_KP_GPSW) { + mpk = "MPK"; + msk = "MSK"; + // Generate a set of parameters for an ABE authority + if (context->generateParams(DEFAULT_BP_PARAM, mpk, msk) != OpenABE_NOERROR) { + EXIT("Unable to generate params"); + } + } else { + EXIT("ERROR: not one of the supported scheme types. See help menu for options."); + } + + // check the operation now + if (operation == KEYGEN_OP) { + // this means we're measuring the size of the keys (for storage) + if(scheme_type == OpenABE_SCHEME_CP_WATERS) { + keyFuncInput = std::unique_ptr(createAttributeList(input_str)); + if (!keyFuncInput) { + EXIT("ERROR: invalid key input string for CP - expecting attribute list"); + } + + const vector *raw_attrs = ((OpenABEAttributeList*) keyFuncInput.get())->getAttributeList(); + policy_components = raw_attrs->size(); + + + } else if(scheme_type == OpenABE_SCHEME_KP_GPSW) { + keyFuncInput = std::unique_ptr(createPolicyTree(input_str)); + if (!keyFuncInput) { + EXIT("ERROR: invalid key input string for KP - expecting policy"); + } + + set attr_set = ((OpenABEPolicy *) keyFuncInput.get())->getAttrCompleteSet(); + policy_components = attr_set.size(); + + } + + // let's generate the key then export + context->generateDecryptionKey((OpenABEFunctionInput *)keyFuncInput.get(), "deckey", mpk, msk); + + // export key bytes here + OpenABEByteString key_str; + cout << "<=== KEY INPUT ===>\n" << keyFuncInput->toCompactString() << "\n<=== KEY INPUT ===>\n"; + cout << "OpenABE key input attributes: " << policy_components << endl; + cout << "OpenABE key size: " << key_str.size() << endl; + + } else if(operation == ENCRYPT_OP) { + // this means we're measuring the size of the ciphertext (for storage) + if(scheme_type == OpenABE_SCHEME_CP_WATERS) { + encFuncInput = std::unique_ptr(createPolicyTree(input_str)); + if (!encFuncInput) { + EXIT("ERROR: invalid enc input string for CP - expecting policy"); + } + + set attr_set = ((OpenABEPolicy *) encFuncInput.get())->getAttrCompleteSet(); + policy_components = attr_set.size(); + } + else if(scheme_type == OpenABE_SCHEME_KP_GPSW) { + // attributes are embedded in the ciphertext + encFuncInput = std::unique_ptr(createAttributeList(input_str)); + if (!encFuncInput) { + EXIT("ERROR: invalid enc input string for KP - expecting attribute list"); + } + + const vector *raw_attrs = ((OpenABEAttributeList*) encFuncInput.get())->getAttributeList(); + policy_components = raw_attrs->size(); + } + + symkey.reset(new OpenABESymKey); + ciphertext.reset(new OpenABECiphertext); + context->encryptKEM(nullptr, mpk, encFuncInput.get(), DEFAULT_SYM_KEY_BYTES, symkey, ciphertext.get()); + + OpenABEByteString ct_str; + ciphertext->exportToBytes(ct_str); + + cout << "<=== ENC INPUT ===>\n" << encFuncInput->toCompactString() << "\n<=== ENC INPUT ===>\n"; + cout << "OpenABE enc input attributes: " << policy_components << endl; + cout << "OpenABE ciphertext size: " << ct_str.size() << endl; + } else { + EXIT("ERROR: you specified an invalid or unsupported operation. See help menu for options."); + } + +CLEANUP: + return 0; +} + +int profileABE_CCA_KEM(OpenABE_SCHEME scheme_type, string operation, string input_str) { + cout << "Profiling... " << getSchemeString(scheme_type) << endl; + string mpk, msk, auth1mpk, auth1msk, decKey = "decKey"; + std::unique_ptr keyFuncInput = nullptr, encFuncInput = nullptr; + shared_ptr symkey = nullptr; + unique_ptr ciphertext = nullptr; + unique_ptr ccaContext = nullptr; + unique_ptr schemeContext = nullptr; + unique_ptr rng(new OpenABERNG), rng2(new OpenABERNG); + int policy_components = 0; + + // initialize a scheme context with the KEM context + schemeContext = OpenABE_createContextABESchemeCPA(scheme_type); + if(!schemeContext) { + EXIT("Unable to create CPA scheme context"); + } + + // initialize a CCA scheme context + ccaContext.reset(new OpenABEContextGenericCCA(std::move(schemeContext))); + if(ccaContext == nullptr) { + EXIT("Unable to create a new CCA KEM context"); + } + + // generate the parameters for the given scheme_type + if(scheme_type == OpenABE_SCHEME_CP_WATERS || scheme_type == OpenABE_SCHEME_KP_GPSW) { + mpk = "MPK"; + msk = "MSK"; + // Generate a set of parameters for an ABE authority + if (ccaContext->generateParams(DEFAULT_BP_PARAM, mpk, msk) != OpenABE_NOERROR) { + EXIT("Unable to generate params"); + } + } else { + EXIT("ERROR: not one of the supported scheme types"); + } + + // check the operation now + if (operation == KEYGEN_OP) { + // this means we're measuring the size of the keys (for storage) + if(scheme_type == OpenABE_SCHEME_CP_WATERS) { + keyFuncInput = std::unique_ptr(createAttributeList(input_str)); + if (!keyFuncInput) { + EXIT("ERROR: invalid key input string for CP/MA - expecting attribute list"); + } + + const vector *raw_attrs = ((OpenABEAttributeList*) keyFuncInput.get())->getAttributeList(); + policy_components = raw_attrs->size(); + + + } else if(scheme_type == OpenABE_SCHEME_KP_GPSW) { + keyFuncInput = std::unique_ptr(createPolicyTree(input_str)); + if (!keyFuncInput) { + EXIT("ERROR: invalid key input string for KP - expecting policy"); + } + + set attr_set = ((OpenABEPolicy *) keyFuncInput.get())->getAttrCompleteSet(); + policy_components = attr_set.size(); + + } + + // let's generate the key then export + ccaContext->generateDecryptionKey((OpenABEFunctionInput *)keyFuncInput.get(), "deckey", mpk, msk); + + // export key bytes here + OpenABEByteString key_str; + ccaContext->exportKey("deckey", key_str); + + cout << "<=== KEY INPUT ===>\n" << keyFuncInput->toCompactString() << "\n<=== KEY INPUT ===>\n"; + cout << "OpenABE key input attributes: " << policy_components << endl; + cout << "OpenABE key size: " << key_str.size() << endl; + + } else if(operation == ENCRYPT_OP) { + // this means we're measuring the size of the ciphertext (for storage) + if(scheme_type == OpenABE_SCHEME_CP_WATERS) { + encFuncInput = std::unique_ptr(createPolicyTree(input_str)); + if (!encFuncInput) { + EXIT("ERROR: invalid enc input string for CP/MA - expecting policy"); + } + + set attr_set = ((OpenABEPolicy *) encFuncInput.get())->getAttrCompleteSet(); + policy_components = attr_set.size(); + } + else if(scheme_type == OpenABE_SCHEME_KP_GPSW) { + // attributes are embedded in the ciphertext + encFuncInput = std::unique_ptr(createAttributeList(input_str)); + if (!encFuncInput) { + EXIT("ERROR: invalid enc input string for KP - expecting attribute list"); + } + const vector *raw_attrs = ((OpenABEAttributeList*) encFuncInput.get())->getAttributeList(); + policy_components = raw_attrs->size(); + } + + symkey.reset(new OpenABESymKey); + ciphertext.reset(new OpenABECiphertext); + ccaContext->encryptKEM(rng2.get(), mpk, encFuncInput.get(), DEFAULT_SYM_KEY_BYTES, symkey, ciphertext.get()); + + OpenABEByteString ct_str; + ciphertext->exportToBytes(ct_str); + + cout << "<=== ENC INPUT ===>\n" << encFuncInput->toCompactString() << "\n<=== ENC INPUT ===>\n"; + cout << "OpenABE enc input attributes: " << policy_components << endl; + cout << "OpenABE ciphertext size: " << ct_str.size() << endl; + } else { + EXIT("ERROR: you specified an invalid or unsupported operation. See help menu for options."); + } + +CLEANUP: + return 0; +} + + +int main(int argc, const char *argv[]) +{ + cout << "Math Library: " << DEFAULT_MATH_LIB << endl; + if(argc < 5) { + cout << "OpenABE profiler utility, v" << (OpenABE_LIBRARY_VERSION / 100.) << endl; + cout << "Usage " << argv[0] << ": [ scheme => 'CP' or 'KP'] [ operation ] [ input ] [ 'cpa' or 'cca']" << endl; + cout << "\tscheme: the type of ABE scheme to benchmark" << endl; + cout << "\toperation: 'keygen' or 'encrypt'" << endl; + cout << "\tinput: an attribute list or policy tree string depending on scheme type" << endl; + cout << "\tcpa or cca: chosen-plaintext secure vs chosen-ciphertext secure versions" << endl; + cout << "Profiler:" << endl; + return -1; + } + + string schemeType = argv[1]; + string operation = string( argv[2] ); + string input = string( argv[3] ); + string secType = string( argv[4] ); + + InitializeOpenABE(); + + // get the scheme type + OpenABE_SCHEME scheme_type; + if(schemeType == CPABE) { + /* benchmark with CP-ABE func */ + scheme_type = OpenABE_SCHEME_CP_WATERS; + } + else if(schemeType == KPABE) { + /* benchmark with KP-ABE func */ + scheme_type = OpenABE_SCHEME_KP_GPSW; + } + else { + /* other scheme types */ + cout << "Invalid scheme type!" << endl; + return -1; + } + + try { + // check the security type + if(secType == CPA) { + // run all the CPA tests + cout << "Running with CPA context" << endl; + profileABE_CPA_KEM(scheme_type, operation, input); + } + else if(secType == CCA) { + // run all the CCA tests + cout << "Running with CCA context" << endl; + profileABE_CCA_KEM(scheme_type, operation, input); + } + else { + cout << "Invalid security type! Expected Argument: '" << CPA << "' or '" << CCA << "'" << endl; + return -1; + } + } catch(OpenABE_ERROR& error) { + cout << "Caught error: " << ::OpenABE_errorToString(error) << endl; + } + + ShutdownOpenABE(); + + return 0; +} diff --git a/src/ske/zcontextske.cpp b/src/ske/zcontextske.cpp new file mode 100644 index 00000000..ec32c364 --- /dev/null +++ b/src/ske/zcontextske.cpp @@ -0,0 +1,452 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontextske.cpp +/// +/// \brief Implementation for OpenABE context SKE and streaming SKE schemes. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Utility functions for managing symmetric keys in a keystore + ********************************************************************************/ +namespace oabe { + +/*! + * Stores a symmetric key in a given Keystore. + * + * @param[in] A Keystore reference. + * @param[in] A symmetric key identifier. + * @param[in] A reference to a OpenABESymKey object. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR OpenABE_storeSymmetricKey(OpenABEKeystore *gKeystore, const std::string keyID, + const shared_ptr &skey) { + OpenABE_ERROR result = OpenABE_NOERROR; + try { + // check input is valid + ASSERT_NOTNULL(gKeystore); + ASSERT_NOTNULL(skey); + // add key into the keystore + gKeystore->addKey(keyID, skey, KEY_TYPE_SECRET); + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +/*! + * Load a symmetric key blob into a given Keystore. + * + * @param[in] A Keystore reference. + * @param[in] A symmetric key identifier to store the key as. + * @param[in] A reference to a OpenABEByteString key blob. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR OpenABE_loadSymmetricKey(OpenABEKeystore *gKeystore, const std::string keyID, + OpenABEByteString *skeyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString keyBytes; + shared_ptr symKey = nullptr; + + try { + // check that input is valid + ASSERT_NOTNULL(gKeystore); + ASSERT_NOTNULL(skeyBlob); + // construct symmetric key + symKey.reset(new OpenABESymKey); + symKey->loadKeyFromBytes(*skeyBlob); + // add symmetric key into the keystore + gKeystore->addKey(keyID, symKey, KEY_TYPE_SECRET); + symKey.reset(); + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +/*! + * Retrieve a symmetric key from a given Keystore. + * + * @param[in] A Keystore reference. + * @param[in] A symmetric key identifier. + * @return A reference to the requested OpenABESymKey or NULL if not found in the Keystore. + */ +shared_ptr OpenABE_getSymmetricKey(OpenABEKeystore *gKeystore, + const std::string keyID) { + shared_ptr skey = nullptr; + + // get the OpenABEKey stored inside the keystore + shared_ptr key = gKeystore->getSecretKey(keyID); + if (key == nullptr) { + return nullptr; + } + + // convert the key into a OpenABESymKey structure + skey = static_pointer_cast(key); + if (skey == nullptr) { + return nullptr; + } + + return skey; +} + +/*! + * Delete a symmetric key from a given Keystore. + * + * @param[in] A Keystore reference. + * @param[in] A symmetric key identifier. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR OpenABE_deleteSymmetricKey(OpenABEKeystore *gKeystore, + const std::string keyID) { + OpenABE_ERROR result = OpenABE_NOERROR; + try { + // delete the key within the keystore + if (gKeystore->deleteKey(keyID) != OpenABE_NOERROR) { + throw OpenABE_ERROR_INVALID_INPUT; + } + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +/*! + * Export a OpenABEKey key in a given Keystore to a buffer. + * + * @param[in] A Keystore reference. + * @param[in] A key identifier. + * @param[out] A reference to a OpenABEByteString output buffer. + * @return An error code or OpenABE_NOERROR. + */ +OpenABE_ERROR OpenABE_exportKey(OpenABEKeystore *gKeystore, const std::string keyID, + OpenABEByteString *outputKeyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + try { + // check that input is valid + ASSERT_NOTNULL(gKeystore); + ASSERT_NOTNULL(outputKeyBlob); + // retrieve the key from keystore using keyID + if (gKeystore->exportKeyToBytes(keyID, *outputKeyBlob) != OpenABE_NOERROR) { + throw OpenABE_ERROR_INVALID_KEY; + } + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +/******************************************************************************** + * Implementation of the OpenABEContextSchemeStreamSKE class + ********************************************************************************/ + +/*! + * Constructor for the OpenABEContextSchemeStreamSKE base class. + * + */ +OpenABEContextSchemeStreamSKE::OpenABEContextSchemeStreamSKE() : ZObject() { + this->m_AuthEncStream = nullptr; + this->m_AuthDecStream = nullptr; +} + +/*! + * Destructor for the OpenABEContextSchemeSKE base class. + * + */ +OpenABEContextSchemeStreamSKE::~OpenABEContextSchemeStreamSKE() { + SAFE_DELETE(this->m_AuthEncStream); + SAFE_DELETE(this->m_AuthDecStream); +} + +OpenABE_ERROR OpenABEContextSchemeStreamSKE::keygen(const string &keyID) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr skey = nullptr; + + try { + // make sure secret key ID hasn't been used before + bool does_exist = this->m_Keystore_.checkSecretKey(keyID); + if (does_exist) { + throw OpenABE_ERROR_IN_USE_ALREADY; + } + // select a new symmetric key for keyID + skey.reset(new OpenABESymKey); + skey->generateSymmetricKey(DEFAULT_SYM_KEY_BYTES); + // now we can add it to the keystore + this->m_Keystore_.addKey(keyID, skey, KEY_TYPE_SECRET); + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR OpenABEContextSchemeStreamSKE::exportKey(const string &keyID, + OpenABEByteString &keyBlob, + const string password) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString tmpKeyBlob; + + try { + // attempt to export the given keyID to the keyBlob output buffer + if (OpenABE_exportKey(&this->m_Keystore_, keyID, &tmpKeyBlob) != OpenABE_NOERROR) { + throw OpenABE_ERROR_INVALID_INPUT; + } + + // check if user specified a password + if (password != "") { + // encrypt the exported key using the specified password + if ((result = encryptUnderPassword(password, tmpKeyBlob, keyBlob)) != + OpenABE_NOERROR) { + return result; + } + } else { + // set the keyBlob + keyBlob.clear(); + keyBlob += tmpKeyBlob; + } + // clear the temp buffer + tmpKeyBlob.clear(); + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextSchemeStreamSKE::loadPrivateKey(const string &keyID, + OpenABEByteString &inputKeyBlob, + const string password) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString keyBlob; + + try { + // check if user specified a password + if (password != "") { + // decrypt inputKeyBlob into keyBlob using 'password' + if ((result = decryptUnderPassword(password, inputKeyBlob, keyBlob)) != + OpenABE_NOERROR) { + return result; + } + } else { + keyBlob += inputKeyBlob; + } + + // load the symmetric key without attempting to decrypt the blob first + if ((result = OpenABE_loadSymmetricKey(&this->m_Keystore_, keyID, &keyBlob)) != + OpenABE_NOERROR) { + return result; + } + + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR OpenABEContextSchemeStreamSKE::deleteKey(const string &keyID) { + return OpenABE_deleteSymmetricKey(&this->m_Keystore_, keyID); +} + +OpenABE_ERROR OpenABEContextSchemeStreamSKE::encryptInit(const string &skID, + OpenABEByteString *iv) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr symKey = nullptr; + + try { + /* check if AuthEncStream has been allocated */ + if (this->m_AuthEncStream != nullptr) { + SAFE_DELETE(this->m_AuthEncStream); + } + + /* load OpenABESymKey using skID */ + symKey = OpenABE_getSymmetricKey(&this->m_Keystore_, skID); + if (symKey == nullptr) { + throw OpenABE_ERROR_INVALID_KEY; + } + /* now we can allocate the AuthEncStream class and set the symmetric key */ + this->m_AuthEncStream = + new OpenABESymKeyAuthEncStream(DEFAULT_AES_SEC_LEVEL, symKey); + /* perform encryptInit and verify there were no errors */ + result = this->m_AuthEncStream->encryptInit(iv); + if (result != OpenABE_NOERROR) { + throw result; + } + // check for the AAD + if (this->aad.size() > 0) { + /* set AAD accordingly */ + this->m_AuthEncStream->initAddAuthData(this->aad.getInternalPtr(), + this->aad.size()); + } else { + /* do the default here */ + this->m_AuthEncStream->initAddAuthData(NULL, 0); + } + result = this->m_AuthEncStream->setAddAuthData(); + ASSERT(result == OpenABE_NOERROR, result); + + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextSchemeStreamSKE::encryptUpdate(OpenABEByteString *plaintextBlock, + OpenABEByteString *ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + + try { + /* make sure we've called encryptInit already */ + ASSERT_NOTNULL(this->m_AuthEncStream); + /* perform encryption update */ + this->m_AuthEncStream->encryptUpdate(plaintextBlock, ciphertext); + + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextSchemeStreamSKE::encryptFinalize(OpenABEByteString *ciphertext, + OpenABEByteString *tag) { + OpenABE_ERROR result = OpenABE_NOERROR; + + try { + /* make sure we've called encryptInit already */ + ASSERT_NOTNULL(this->m_AuthEncStream); + /* finalize encryption */ + this->m_AuthEncStream->encryptFinalize(ciphertext, tag); + /* delete AuthEncStream object */ + SAFE_DELETE(this->m_AuthEncStream); + this->m_AuthEncStream = nullptr; + + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextSchemeStreamSKE::decryptInit(const string &skID, OpenABEByteString *iv, + OpenABEByteString *tag) { + OpenABE_ERROR result = OpenABE_NOERROR; + shared_ptr symKey = nullptr; + + try { + /* check if AuthEncStream has been allocated */ + if (this->m_AuthDecStream != nullptr) { + SAFE_DELETE(this->m_AuthDecStream); + } + + /* load OpenABESymKey using skID */ + symKey = OpenABE_getSymmetricKey(&this->m_Keystore_, skID); + if (symKey == nullptr) { + throw OpenABE_ERROR_INVALID_KEY; + } + + /* now we can allocate the AuthEncStream class and set the symmetric key */ + this->m_AuthDecStream = + new OpenABESymKeyAuthEncStream(DEFAULT_AES_SEC_LEVEL, symKey); + /* perform decrypt init */ + this->m_AuthDecStream->decryptInit(iv, tag); + // check for the AAD + if (this->aad.size() > 0) { + /* set AAD accordingly */ + this->m_AuthDecStream->initAddAuthData(this->aad.getInternalPtr(), + this->aad.size()); + } else { + /* do the default here */ + this->m_AuthDecStream->initAddAuthData(NULL, 0); + } + result = this->m_AuthDecStream->setAddAuthData(); + ASSERT(result == OpenABE_NOERROR, result); + + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextSchemeStreamSKE::decryptUpdate(OpenABEByteString *ciphertextBlock, + OpenABEByteString *plaintext) { + OpenABE_ERROR result = OpenABE_NOERROR; + + try { + /* make sure we've called encryptInit already */ + ASSERT_NOTNULL(this->m_AuthDecStream); + /* perform encryption update */ + this->m_AuthDecStream->decryptUpdate(ciphertextBlock, plaintext); + + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +OpenABE_ERROR +OpenABEContextSchemeStreamSKE::decryptFinalize(OpenABEByteString *plaintext) { + OpenABE_ERROR result = OpenABE_NOERROR; + + try { + /* make sure we've called encryptInit already */ + ASSERT_NOTNULL(this->m_AuthDecStream); + /* perform encryption update */ + this->m_AuthDecStream->decryptFinalize(plaintext); + + SAFE_DELETE(this->m_AuthDecStream); + this->m_AuthDecStream = nullptr; + } catch (OpenABE_ERROR &error) { + result = error; + } + + return result; +} + +} diff --git a/src/test_abe.cpp b/src/test_abe.cpp new file mode 100644 index 00000000..cae38ae2 --- /dev/null +++ b/src/test_abe.cpp @@ -0,0 +1,890 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file test_abe.cpp +/// +/// \brief Unit testing utility for OpenABE schemes. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace oabe; + +#define TEST_MSG_LEN 32 + +#define COMMA ',' +#define TEST_DESCRIPTION(desc) RecordProperty("description", desc) +#define TESTSUITE_DESCRIPTION(desc) ::testing::Test::RecordProperty("description", desc) + +string createAttribute(int i) +{ + stringstream ss; + ss << "Attr" << i; + return ss.str(); +} + +bool getOpenABEAttributeList(int max, vector & attrList) +{ + if(max <= 0) { return false; } + int start = 0; + // reset + attrList.clear(); + for(int i = start; i <= max; i++) { + attrList.push_back(createAttribute(i)); + } + return true; +} + +// returns an evenly distributed / balanced policy tree +string getBalancedOpenABETree(int start, int end) { + if(start == end) { return createAttribute(start); } + int mid = ceil((start + (end - start) / 2.0)); + if(mid == 0) { + return "(" + createAttribute(start) + " and " + createAttribute(end) + ")"; + } + else { + return "(" + getBalancedOpenABETree(start, mid-1) + " and " + getBalancedOpenABETree(mid, end) + ")"; + } +} + +// returns a right-sided skewed policy tree +string getOpenABEPolicyString(int max) +{ + string policystr; + if(max >= 2) { + policystr = "(" + createAttribute(0) + " and " + createAttribute(1) + ")"; + } + else if(max == 1) { + policystr = createAttribute(0); + } + + for(int i = 2; i <= max; i++) + { + policystr = "(" + policystr + " and " + createAttribute(i) + ")"; + } + + return policystr; +} + +bool runLSSSTest(string policy_str, string attr_list_str, bool verbose = false) +{ + // Create a pairing object + OpenABEPairing pairing(DEFAULT_BP_PARAM); + // instantiate RNG + OpenABERNG rng; + + unique_ptr policy = createPolicyTree(policy_str); + if(verbose) { + cout << "Policy: " << policy->toString() << endl; + } + ZP secret = pairing.randomZP(&rng); + // Compute the secret shares + OpenABELSSS lsss(&pairing, &rng); + lsss.shareSecret(policy.get(), secret); + // Get the resulting shares + OpenABELSSSRowMap shares = lsss.getRows(); + cout << "Obtained " << shares.size() << " secret shares" << endl; + + OpenABELSSS recoveryLsss(&pairing, &rng); + + // OpenABEAttributeList *attrList = new OpenABEAttributeList(S.size(), S); + unique_ptr attrList = createAttributeList(attr_list_str); + if(verbose) { + cout << "AttrList: " << attrList->toString() << endl; + } + if(recoveryLsss.recoverCoefficients(policy.get(), attrList.get()) == false) + return false; + OpenABELSSSRowMap coefficients = recoveryLsss.getRows(); + cout << "Recovered " << coefficients.size() << " coefficients." << endl; + + ZP recSecret = recoveryLsss.LSSStestSecretRecovery(coefficients, shares); + return secret == recSecret; +} + +TEST(Attribute, SerializeAndDeserialize) { + TEST_DESCRIPTION("Testing serialize and deserialize for attribute lists"); + OpenABEAttributeList attr_list; + attr_list.addAttribute("Alice"); + attr_list.addAttribute("Bob"); + + OpenABEByteString bytes; + attr_list.serialize(bytes); + OpenABEAttributeList attr_list2; + attr_list2.deserialize(bytes); + + ASSERT_TRUE(attr_list.isEqual(&attr_list2)); +} + +class PolicyParser : public ::testing::Test { + protected: + virtual void SetUp() { } + +}; + +TEST_F(PolicyParser, OrderOfParanthesis) { + TEST_DESCRIPTION("Testing that basic ordering of parenthesis does not matter"); + unique_ptr s1 = createPolicyTree("(one or two) and three"); + unique_ptr s2 = createPolicyTree("three and (one or two)"); + ASSERT_TRUE(s1 != nullptr); + ASSERT_TRUE(s2 != nullptr); + set attr_set1 = s1->getAttrCompleteSet(); + set attr_set2 = s2->getAttrCompleteSet(); + ASSERT_EQ(attr_set1, attr_set2); +} + +TEST_F(PolicyParser, DateRangePolicy) { + TEST_DESCRIPTION("Testing that we can handle range of dates policies"); + ASSERT_TRUE(createPolicyTree("Date = January 1-31, 2016") != nullptr); + ASSERT_TRUE(createPolicyTree("Date = February 1-15, 2016") != nullptr); + ASSERT_TRUE(createPolicyTree("Date = March 21-28, 2016") != nullptr); +} + +TEST_F(PolicyParser, ValidDatePolicy) { + TEST_DESCRIPTION("Testing that we can handle date type policies"); + ASSERT_TRUE(createPolicyTree("Date = January 5, 2016") != nullptr); + ASSERT_TRUE(createPolicyTree("Date > January 5, 2016") != nullptr); + ASSERT_TRUE(createPolicyTree("Date < January 5, 2016") != nullptr); + ASSERT_TRUE(createPolicyTree("Date <= January 5, 2016") != nullptr); + ASSERT_TRUE(createPolicyTree("Date >= January 5, 2016") != nullptr); +} + +TEST_F(PolicyParser, InvalidDate) { + TEST_DESCRIPTION("Testing that an exception is thrown for invalid dates before unix epoch"); + ASSERT_TRUE(createPolicyTree("Date = January 1, 1968") == nullptr); +} + +TEST_F(PolicyParser, InvalidStartDateRange) { + TEST_DESCRIPTION("Testing that an exception is thrown for an invalid date range"); + ASSERT_TRUE(createPolicyTree("Date = January 0-10, 1970") == nullptr); +} + + +TEST_F(PolicyParser, InvalidEndDateRange) { + TEST_DESCRIPTION("Testing that an exception is thrown for an invalid date range"); + ASSERT_TRUE(createPolicyTree("Date = January 1-40, 1970") == nullptr); +} + +TEST_F(PolicyParser, InvalidDateFormat) { + TEST_DESCRIPTION("Testing that dates are specified correctly"); + ASSERT_TRUE(createPolicyTree("(One or Two) and (Date : January 1, 1970)") == nullptr); +} + +TEST_F(PolicyParser, IntegerRangePolicy) { + TEST_DESCRIPTION("Testing that range of integers supported in the policy"); + ASSERT_TRUE(createPolicyTree("Level in (2-35)") != nullptr); + unique_ptr s1 = createPolicyTree("Level > 2 and Level < 35"); + ASSERT_TRUE(s1 != nullptr); +} + +TEST_F(PolicyParser, InvalidExpInts) { + // verifying invalid policies are caught appropriately + TEST_DESCRIPTION("Testing that integers in expint can be represented by number of bits specified"); + // make sure integers in expint can be represented by number of bits specified + ASSERT_TRUE(createPolicyTree("Month < 16#4") == nullptr); +} + +TEST_F(PolicyParser, InvalidExpIntsWithZero) { + TEST_DESCRIPTION("Testing that integers in expint can be represented by number of bits specified"); + // make sure integers in expint can be represented by number of bits specified + ASSERT_TRUE(createPolicyTree("Month < 4#0") == nullptr); +} + +TEST_F(PolicyParser, NegativeIntegerInPolicies) { + TEST_DESCRIPTION("Testing that negative integers are not allowed"); + // make sure negative integers are not allowed + ASSERT_TRUE(createPolicyTree("Month > -1#4") == nullptr); + ASSERT_TRUE(createPolicyTree("Month < -3#4") == nullptr); +} + +TEST_F(PolicyParser, LessThanGreaterThanNotInAttributeList) { + TEST_DESCRIPTION("Testing that >,<=,etc cannot be added in attribute lists"); + // make sure we can't add >,<=,etc in attribute lists + ASSERT_TRUE(createAttributeList("Alice|Day >= 100|Bob") == nullptr); +} + +TEST_F(PolicyParser, ExpIntForAttributeList) { + TEST_DESCRIPTION("Testing that expint logic applies to attribute lists"); + // make sure expint logic applies to attribute lists as well. striving for uniformity + ASSERT_TRUE(createAttributeList("Alice|Day = 1000#8|Bob") == nullptr); +} + +TEST_F(PolicyParser, DuplicateDatesInAttributeListAreIgnored) { + TEST_DESCRIPTION("Testing that duplicate dates in attribute lists are ignored"); + string a = "|Date = May 10, 2017|Alice"; + unique_ptr attr_list1 = createAttributeList(a + "|Date = July 1, 2015"); + unique_ptr attr_list2 = createAttributeList(a); + string a1 = attr_list1->toString(); + string a2 = attr_list2->toString(); + ASSERT_TRUE(a1.compare(a2) == 0); +} + +TEST_F(PolicyParser, ExpIntNotAllowedInInputAttribute) { + TEST_DESCRIPTION("Testing that user cannot specify expint as part of an attribute list"); + // make sure user cannot specify expint as part of an attribute + ASSERT_TRUE(createAttributeList("foo_expint04_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx0xx|bar") == nullptr); +} + +TEST_F(PolicyParser, ExpIntNotAllowedInInputPolicy) { + TEST_DESCRIPTION("Testing that user cannot specify expint as part of a policy"); + ASSERT_TRUE(createPolicyTree("Alice or foo_expint04_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx0xx") == nullptr); +} + +class LinearSecretSharing : public ::testing::Test { + protected: + virtual void SetUp() { + verbose = false; + } + bool verbose; +}; + +TEST_F(LinearSecretSharing, TestWithGreaterThan) { + TEST_DESCRIPTION("Testing LSSS with greater than type policy"); + ASSERT_TRUE(runLSSSTest("Day > 5 and Charlie", "Charlie|Day=7", verbose)); +} + +TEST_F(LinearSecretSharing, TestWithGreaterThanOrEqual) { + TEST_DESCRIPTION("Testing LSSS with greater than or equal type policy"); + string attrList = "Day = 7"; + ASSERT_TRUE(runLSSSTest("(Day >= 5)", attrList, verbose)); + ASSERT_FALSE(runLSSSTest("(Day >= 12)", attrList, verbose)); +} + +TEST_F(LinearSecretSharing, TestWithLessThan) { + TEST_DESCRIPTION("Testing LSSS with less than operation"); + string attrList = "Day = 17"; + ASSERT_TRUE(runLSSSTest("(Day < 25)", attrList, verbose)); + ASSERT_FALSE(runLSSSTest("(Day < 5)", attrList, verbose)); +} + +TEST_F(LinearSecretSharing, TestWithLessThanOrEqual) { + TEST_DESCRIPTION("Testing LSSS with less than or equal type policy"); + string attrList = "Day = 7000"; + ASSERT_TRUE(runLSSSTest("(Day <= 7000)", attrList, verbose)); + ASSERT_FALSE(runLSSSTest("(Day <= 5)", attrList, verbose)); +} + +TEST_F(LinearSecretSharing, TestWithEquality) { + TEST_DESCRIPTION("Testing LSSS with just equality type policy"); + string attrList = "Month = 7#4"; + ASSERT_TRUE(runLSSSTest("(Month == 7#4)", attrList, verbose)); + ASSERT_FALSE(runLSSSTest("(Month == 6#4)", attrList, verbose)); +} + +TEST_F(LinearSecretSharing, TestOtherComparisonOps) { + TEST_DESCRIPTION("Testing LSSS with multiple comparison ops in addition to other attributes in the policy"); + string attrList = "Month = 7#4|Bob|Charlie"; + ASSERT_TRUE(runLSSSTest("(Month<12#4 and Bob)", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("(Month> 2#4 and Charlie)", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("(Month <10#4 and Charlie)", attrList, verbose)); + // make sure this throws an exception. '==' required for equality testing + ASSERT_ANY_THROW(runLSSSTest("(Month= 2#4 and Charlie)", attrList, verbose)); +} + +TEST_F(LinearSecretSharing, TestWithSimpleDatePolicies) { + TEST_DESCRIPTION("Testing LSSS with simple date type policies"); + string attrList = "|Date = December 15, 2015|Bob|Charlie"; + ASSERT_TRUE(runLSSSTest("(Date < January 1, 2017 and Bob)", attrList, verbose)); + ASSERT_FALSE(runLSSSTest("(Date > March 10, 2016 and Charlie)", attrList, verbose)); +} + +TEST_F(LinearSecretSharing, TestWithIntegerRangeTypePolicies) { + TEST_DESCRIPTION("Testing LSSS with integer range type policies"); + string attrList = "|Bob|Month = 7#4"; + ASSERT_TRUE(runLSSSTest("(Month in (3#4-15#4) and Bob)", attrList, verbose)); + ASSERT_FALSE(runLSSSTest("(Month in (3#4-5#4) and Bob)", attrList, verbose)); +} + +TEST_F(LinearSecretSharing, TestWithDateRangeTypePolicies) { + TEST_DESCRIPTION("Testing LSSS with date range type policies"); + string attrList = "|Date = December 15, 2016|Charlie"; + ASSERT_TRUE(runLSSSTest("((Date = December 10-16, 2016) and Charlie)", attrList, verbose)); + ASSERT_FALSE(runLSSSTest("((Date = December 1-14, 2016) and Charlie)", attrList, verbose)); +} + +TEST(LSSS, TestCorrectnessOfOrPolicyTree) { + TEST_DESCRIPTION("Testing correctness of different policy trees"); + // Create attribute list + string attrList = "|Alice|Bob|Charlie|David"; + bool verbose = true; + ASSERT_TRUE(runLSSSTest("(Alice or Bob)", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("(Alice and Bob)", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("(Eve or Alice)", attrList, verbose)); + ASSERT_FALSE(runLSSSTest("(Eve or Frank) and Alice", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("((Alice or Bob) and Charlie)", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("((Alice or Bob) and (Charlie or David))", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("((Alice and Bob) or (Charlie and David))", attrList, verbose)); + ASSERT_FALSE(runLSSSTest("(Alice and (Eve or Frank))", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("(Alice or (Eve and Frank))", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("((Eve and Frank) or Alice)", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("(Alice or (Eve or Frank))", attrList, verbose)); + // here we are selecting the shortest path to satisfy the tree (exercising sort logic) + ASSERT_TRUE(runLSSSTest("((Bob and Charlie) or Alice)", attrList, verbose)); + ASSERT_FALSE(runLSSSTest("(Alice and Eve)", attrList, verbose)); + // test ability to sort + cout << "* Test ability to sort..." << endl; + ASSERT_TRUE(runLSSSTest("(Alice or (Bob and Charlie))", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("((Bob and Charlie) or Alice)", attrList, verbose)); +} + +TEST(LSSS, TestCorrectnessWithDupAttributes) { + TEST_DESCRIPTION("Testing correctness when duplicate attributes are present"); + string attrList = "|Alice|Bob|Charlie|David"; + bool verbose = true; + ASSERT_TRUE(runLSSSTest("(Alice or Alice)", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("(Alice and Alice)", attrList, verbose)); + ASSERT_TRUE(runLSSSTest("((Alice and Alice) and Bob)", attrList, verbose)); +} + +string convertToAttributeListString(vector& attr_list) { + string a_str = "|"; + for (auto a : attr_list) { + a_str += a + "|"; + } + return a_str; +} + +TEST(LSSS, TestCorrectnessOfBalancedAndPolicyTree) { + TEST_DESCRIPTION("Testing correctness of balanced policy trees"); + // get a comprehensive list of attributes + string attr_list_good, attr_list_bad; + vector attrListGood, attrListBad; + getOpenABEAttributeList(32768, attrListGood); + attrListBad = attrListGood; + attrListBad.erase(attrListBad.begin()); + + int attrCount = 4; + string balanced_policy_str = getBalancedOpenABETree(0, attrCount); + // call function to convert attrListGood to a string sep by '|' + attr_list_good = convertToAttributeListString(attrListGood); + ASSERT_TRUE(runLSSSTest(balanced_policy_str, attr_list_good)); + +#if 0 + attrCount = 8192; + balanced_policy_str = getBalancedOpenABETree(0, attrCount); + attr_list_bad = convertToAttributeListString(attrListBad); + ASSERT_FALSE(runLSSSTest(balanced_policy_str, attr_list_bad)); + +#ifndef USING_EMSCRIPTEN + attrCount = 16384; + balanced_policy_str = getBalancedOpenABETree(0, attrCount); + ASSERT_TRUE(runLSSSTest(balanced_policy_str, attr_list_good)); + + attrCount = 32768; + balanced_policy_str = getBalancedOpenABETree(0, attrCount); + ASSERT_TRUE(runLSSSTest(balanced_policy_str, attr_list_good)); +#endif +// takes a few minutes to test +// attrCount = 65536; +// balanced_policy_str = getBalancedOpenABETree(0, attrCount); +// getOpenABEAttributeList(attrCount, attrListGood); +// ASSERT_TRUE(runLSSSTest(balanced_policy_str, attrListGood)); + +#endif +} + +TEST(LSSS, TestCorrectnessOfSkewedAndPolicyTree) { + TEST_DESCRIPTION("Testing correctness of LSSS on a skewed policy tree"); + + string attr_list_good, attr_list_bad; + // get a comprehensive list of attributes + vector attrListGood, attrListBad; + getOpenABEAttributeList(8192, attrListGood); + attrListBad = attrListGood; + attrListBad.erase(attrListBad.begin()); + + int attrCount = 4; + string skewed_policy_str = getOpenABEPolicyString(attrCount-1); + attr_list_good = convertToAttributeListString(attrListGood); + ASSERT_TRUE(runLSSSTest(skewed_policy_str, attr_list_good)); + +#if 0 +#ifndef USING_EMSCRIPTEN + attrCount = 8192; + skewed_policy_str = getOpenABEPolicyString(attrCount-1); + attr_list_bad = convertToAttributeListString(attrListBad); + ASSERT_TRUE(runLSSSTest(skewed_policy_str, attr_list_good)); + ASSERT_FALSE(runLSSSTest(skewed_policy_str, attr_list_bad)); + + attrCount = 16384; + getOpenABEAttributeList(attrCount, attrListGood); + skewed_policy_str = getOpenABEPolicyString(attrCount-1); + attr_list_good = convertToAttributeListString(attrListGood); + ASSERT_TRUE(runLSSSTest(skewed_policy_str, attr_list_good)); +#endif + +#endif +// might take a few minutes to test +// attrCount = 32768; +// getOpenABEAttributeList(attrCount, attrListGood); +// skewed_policy_str = getOpenABEPolicyString(attrCount-1); +// ASSERT_TRUE(runLSSSTest(skewed_policy_str, attrListGood)); + +// takes a few minutes to test +// attrCount = 65536; +// getOpenABEAttributeList(attrListGood, false); +// balanced_policy_str = getBalancedOpenABETree(0, attrCount); +// ASSERT_TRUE(runLSSSTest(attrCount, balanced_policy_str, attrListGood1)); +} + +/* Note on CPA security tests: + * Decryption returns OpenABE_NOERROR in either a successful or failed decryption attempt except + * if an exception is triggered due to invalid inputs. This is by design. + */ + +namespace { + +class Input { +public: + Input(OpenABE_SCHEME scheme, const string enc_input, + const string key, bool expect_pass, + bool verbose = false) { + scheme_type = scheme; + func_input = enc_input; + key_input = key; + expect_pass_ = expect_pass; + verbose_ = verbose; + } + ~Input() {}; + OpenABE_SCHEME scheme_type; + string func_input, policy_str, key_input; + vector attr_list; + bool verbose_, expect_pass_; +}; + +class CPASecurityForSchemeTest : public ::testing::TestWithParam { +protected: + virtual void SetUp() { + rng_.reset(new OpenABERNG); + rng_->getRandomBytes(&plaintext, TEST_MSG_LEN); + MPK = "testMPK"; + MSK = "testMSK"; + AUTH1MPK = "auth1", AUTH1MSK = "auth1MSK"; + AUTH2MPK = "auth2", AUTH2MSK = "auth2MSK"; + } + + unique_ptr getEncInput(OpenABE_SCHEME type, const string func_input) { + if(type == OpenABE_SCHEME_CP_WATERS) + return createPolicyTree(func_input); + else if(type == OpenABE_SCHEME_KP_GPSW) + return createAttributeList(func_input); + return nullptr; + } + + unique_ptr getKeyInput(OpenABE_SCHEME type, string key_input) { + if(type == OpenABE_SCHEME_CP_WATERS) + return createAttributeList(key_input); + else if(type == OpenABE_SCHEME_KP_GPSW) + return createPolicyTree(key_input); + return nullptr; + } + + const string printScheme(OpenABE_SCHEME type) { + switch(type) { + case OpenABE_SCHEME_CP_WATERS: + return "CP-ABE"; break; + case OpenABE_SCHEME_KP_GPSW: + return "KP-ABE"; break; + default: + break; + } + return "None"; + } + + OpenABEByteString mpkBlob, mskBlob, skBlob, ctBlob; + OpenABEByteString plaintext, plaintext1; + unique_ptr rng_; + string MPK, MSK, AUTH1MPK, AUTH1MSK, AUTH2MPK, AUTH2MSK; +}; + +class CCASecurityForKEMTest : public CPASecurityForSchemeTest {}; +class CCASecurityForSchemeTest : public CPASecurityForSchemeTest {}; + +/* Unit tests for CPA scheme contexts */ +TEST_P(CPASecurityForSchemeTest, testWorkingExamples) { + Input input = GetParam(); + TEST_DESCRIPTION("Testing CPA-secure " + printScheme(input.scheme_type) + " scheme with Key: '" + \ + input.key_input + "' and Enc: '" + input.func_input + "'"); + OpenABECiphertext ciphertext, ciphertext2; + cout << "* Testing CPA security for " << printScheme(input.scheme_type) << " schemes..." << endl; + unique_ptr schemeContext = OpenABE_createContextABESchemeCPA(input.scheme_type); // OpenABE_SCHEME_CP_WATERS + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(schemeContext->generateParams(DEFAULT_BP_PARAM, MPK, MSK) == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->exportKey(MPK, mpkBlob) == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->exportKey(MSK, mskBlob) == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->deleteKey(MPK) == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->deleteKey(MSK) == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->loadMasterPublicParams(MPK, mpkBlob) == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->loadMasterSecretParams(MSK, mskBlob) == OpenABE_NOERROR); + + // encrypt under the specified functional input + unique_ptr encInput = getEncInput(input.scheme_type, input.func_input); + ASSERT_TRUE(schemeContext->encrypt(NULL, MPK, encInput.get(), &plaintext, &ciphertext) == OpenABE_NOERROR); + + ciphertext.exportToBytes(ctBlob); + ciphertext2.loadFromBytes(ctBlob); + ASSERT_TRUE(ciphertext == ciphertext2); + // verify header is thesame + OpenABEByteString hdr1, hdr2; + ciphertext.getHeader(hdr1); + ciphertext2.getHeader(hdr2); + ASSERT_TRUE(hdr1 == hdr2); + + // for both auth1 and auth2 + unique_ptr keyInput = getKeyInput(input.scheme_type, input.key_input); + + ASSERT_TRUE(schemeContext->keygen((OpenABEFunctionInput *)keyInput.get(), "DecKey", MPK, MSK) == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->exportKey("DecKey", skBlob) == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->deleteKey("DecKey") == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->loadUserSecretParams("DecKey", skBlob) == OpenABE_NOERROR); + + // Decrypt the ciphertext with multiple keys + ASSERT_TRUE(schemeContext->decrypt(MPK, "DecKey", &plaintext1, &ciphertext2) == OpenABE_NOERROR); + + if (input.verbose_) { + cout << "Input Plaintext: " << plaintext.toHex() << endl; + cout << "Enc Input used: " << input.func_input << endl; + cout << "Key Input used: " << input.key_input << endl; + cout << "Rec Plaintext: " << plaintext1.toHex() << endl; + cout << "Test expected to pass: " << (input.expect_pass_ ? "true" : "false") << endl; + } + if(input.expect_pass_) { + ASSERT_TRUE(plaintext == plaintext1); + } else { + ASSERT_FALSE(plaintext == plaintext1); + } +} + +/* Unit test fixture for CCA KEM contexts */ +TEST_P(CCASecurityForKEMTest, testWorkingExamples) { + Input input = GetParam(); + TEST_DESCRIPTION("Testing CCA-secure KEM " + printScheme(input.scheme_type) + " scheme with Key: '" + \ + input.key_input + "' and Enc: '" + input.func_input + "'"); + + OpenABECiphertext ciphertext1, ciphertext2; + shared_ptr sym_key(new OpenABESymKey), sym_key1(new OpenABESymKey); + // , sym_key2(new OpenABESymKey), sym_key3(new OpenABESymKey); + + cout << "* Testing CCA KEM security for " << printScheme(input.scheme_type) << " schemes..." << endl; + unique_ptr ccaKEMContext = OpenABE_createABEContextForKEM(input.scheme_type); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(ccaKEMContext->generateParams(DEFAULT_BP_PARAM, MPK, MSK) == OpenABE_NOERROR); + ASSERT_TRUE(ccaKEMContext->exportKey(MPK, mpkBlob) == OpenABE_NOERROR); + ASSERT_TRUE(ccaKEMContext->exportKey(MSK, mskBlob) == OpenABE_NOERROR); + + ASSERT_TRUE(ccaKEMContext->deleteKey(MPK) == OpenABE_NOERROR); + ASSERT_TRUE(ccaKEMContext->deleteKey(MSK) == OpenABE_NOERROR); + + ASSERT_TRUE(ccaKEMContext->loadMasterPublicParams(MPK, mpkBlob) == OpenABE_NOERROR); + ASSERT_TRUE(ccaKEMContext->loadMasterSecretParams(MSK, mskBlob) == OpenABE_NOERROR); + + // encrypt under the specified functional input + unique_ptr encInput = getEncInput(input.scheme_type, input.func_input); + // Encrypt a test key using the KEM mode + ASSERT_TRUE(ccaKEMContext->encryptKEM(rng_.get(), MPK, encInput.get(), DEFAULT_SYM_KEY_BYTES, sym_key, &ciphertext1) == OpenABE_NOERROR); + + // make sure ABE ciphertext and header serialization works correctly + ciphertext1.exportToBytes(ctBlob); + ciphertext2.loadFromBytes(ctBlob); + ASSERT_TRUE(ciphertext1 == ciphertext2); + // verify header is thesame + OpenABEByteString hdr1, hdr2; + ciphertext1.getHeader(hdr1); + ciphertext2.getHeader(hdr2); + ASSERT_TRUE(hdr1 == hdr2); + + // for auth1 and auth2 + unique_ptr keyInput = getKeyInput(input.scheme_type, input.key_input); + + ASSERT_TRUE(ccaKEMContext->generateDecryptionKey((OpenABEFunctionInput *)keyInput.get(), "GoodDecKey1", MPK, MSK) == OpenABE_NOERROR); + + ASSERT_TRUE(ccaKEMContext->exportKey("GoodDecKey1", skBlob) == OpenABE_NOERROR); + ASSERT_TRUE(ccaKEMContext->deleteKey("GoodDecKey1") == OpenABE_NOERROR); + ASSERT_TRUE(ccaKEMContext->loadUserSecretParams("GoodDecKey1", skBlob) == OpenABE_NOERROR); + + if (input.verbose_) { + cout << "Enc Input used: " << input.func_input << endl; + cout << "Key Input used: " << input.key_input << endl; + cout << "Test expected to pass: " << (input.expect_pass_ ? "true" : "false") << endl; + } + + if (input.expect_pass_) { + ASSERT_TRUE(ccaKEMContext->decryptKEM(MPK, "GoodDecKey1", &ciphertext1, DEFAULT_SYM_KEY_BYTES, sym_key1) == OpenABE_NOERROR); + ASSERT_TRUE(*sym_key == *sym_key1); + } else { + ASSERT_FALSE(ccaKEMContext->decryptKEM(MPK, "GoodDecKey1", &ciphertext1, DEFAULT_SYM_KEY_BYTES, sym_key1) == OpenABE_NOERROR); + ASSERT_FALSE(*sym_key == *sym_key1); + } +} + + +/* Unit test fixture for CCA scheme contexts */ +TEST_P(CCASecurityForSchemeTest, testWorkingExamples) { + Input input = GetParam(); + TEST_DESCRIPTION("Testing CCA-secure scheme " + printScheme(input.scheme_type) + " scheme with Key: '" + \ + input.key_input + "' and Enc: '" + input.func_input + "'"); + OpenABECiphertext ciphertext1, ciphertext_1, ciphertext2, ciphertext_2; + + cout << "* Testing CCA security for " << printScheme(input.scheme_type) << " schemes..." << endl; + unique_ptr ccaSchemeContext = OpenABE_createContextABESchemeCCA(input.scheme_type); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(ccaSchemeContext->generateParams(DEFAULT_BP_PARAM, MPK, MSK) == OpenABE_NOERROR); + ASSERT_TRUE(ccaSchemeContext->exportKey(MPK, mpkBlob) == OpenABE_NOERROR); + ASSERT_TRUE(ccaSchemeContext->exportKey(MSK, mskBlob) == OpenABE_NOERROR); + + ASSERT_TRUE(ccaSchemeContext->deleteKey(MPK) == OpenABE_NOERROR); + ASSERT_TRUE(ccaSchemeContext->deleteKey(MSK) == OpenABE_NOERROR); + + ASSERT_TRUE(ccaSchemeContext->loadMasterPublicParams(MPK, mpkBlob) == OpenABE_NOERROR); + ASSERT_TRUE(ccaSchemeContext->loadMasterSecretParams(MSK, mskBlob) == OpenABE_NOERROR); + + // encrypt under the specified functional input + unique_ptr encInput = getEncInput(input.scheme_type, input.func_input); + string pt = plaintext.toString(); + ASSERT_TRUE(ccaSchemeContext->encrypt(MPK, encInput.get(), pt, &ciphertext_1, &ciphertext_2) == OpenABE_NOERROR); + + // make sure ABE ciphertext and header serialization works correctly + ciphertext_1.exportToBytes(ctBlob); + ciphertext1.loadFromBytes(ctBlob); + ASSERT_TRUE(ciphertext1 == ciphertext_1); + // verify header is thesame + OpenABEByteString hdr1, hdr2; + ciphertext_1.getHeader(hdr1); + ciphertext1.getHeader(hdr2); + ASSERT_TRUE(hdr1 == hdr2); + + // make sure symmetric ciphertext serialization works correctly + OpenABEByteString ctBlob1, ctBlob2; + ciphertext_2.exportToBytesWithoutHeader(ctBlob1); + ciphertext2.loadFromBytesWithoutHeader(ctBlob1); + ciphertext2.exportToBytesWithoutHeader(ctBlob2); + ASSERT_TRUE(ctBlob1 == ctBlob2); + + // for auth1 and auth2 + unique_ptr keyInput = getKeyInput(input.scheme_type, input.key_input); + + ASSERT_TRUE(ccaSchemeContext->keygen((OpenABEFunctionInput *)keyInput.get(), "GoodDecKey1", MPK, MSK) == OpenABE_NOERROR); + + ASSERT_TRUE(ccaSchemeContext->exportKey("GoodDecKey1", skBlob) == OpenABE_NOERROR); + ASSERT_TRUE(ccaSchemeContext->deleteKey("GoodDecKey1") == OpenABE_NOERROR); + ASSERT_TRUE(ccaSchemeContext->loadUserSecretParams("GoodDecKey1", skBlob) == OpenABE_NOERROR); + + string pt1; + if (input.expect_pass_) { + ASSERT_TRUE(ccaSchemeContext->decrypt(MPK, "GoodDecKey1", pt1, &ciphertext_1, &ciphertext_2) == OpenABE_NOERROR); + plaintext1 += pt1; + ASSERT_TRUE(plaintext == plaintext1); + } else { + ASSERT_FALSE(ccaSchemeContext->decrypt(MPK, "GoodDecKey1", pt1, &ciphertext_1, &ciphertext_2) == OpenABE_NOERROR); + } +} + +} + +INSTANTIATE_TEST_CASE_P(ABETest1, CPASecurityForSchemeTest, + ::testing::Values( + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and (Charlie or David))", "Alice|Charlie", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and (Charlie or David))", "Bob|David", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and (Charlie or David))", "Bob|Eve", false), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie", "((Alice or Bob) and (Charlie or David)) and Alice", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie", "((Alice or Bob) and Alice)", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie", "((Alice and Bob) and Charlie)", false) +)); + +INSTANTIATE_TEST_CASE_P(ABETest2, CPASecurityForSchemeTest, + ::testing::Values( + Input(OpenABE_SCHEME_CP_WATERS, "((Alice and Bob) or uid:567abc)", "uid:567abc", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice and Bob) or uid:567abc)", "Alice|Bob", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice and Bob) or uid:567abc)", "Bob|Eve", false), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|uid:567abcdef", "((Alice or Bob) and (Charlie or David)) and Alice", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|uid:567abcdef", "((Alice or Bob) and Alice)", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|uid:567abcdef", "((Alice and Bob) and Charlie)", false) +)); + +INSTANTIATE_TEST_CASE_P(ABETest3, CPASecurityForSchemeTest, + ::testing::Values( + Input(OpenABE_SCHEME_CP_WATERS, "Alice and Date = May 1-10, 2016", "Alice|Date=May 5, 2016", true), + Input(OpenABE_SCHEME_CP_WATERS, "Date = May 1-10, 2016 and (Alice or Bob)", "Bob|Date=May 8, 2016", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and Date = May 1-10, 2016)", "Bob|Eve|Date=May 12, 2016", false), + Input(OpenABE_SCHEME_KP_GPSW, "Charlie|Date = June 12, 2014", "(Date = June 10-20, 2014 and (Charlie or David))", true), + Input(OpenABE_SCHEME_KP_GPSW, "David|Date = June 25, 2014", "((David or Bob) and Date = June 21-28, 2014)", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|Date = June 30, 2014", "((Alice and Date = June 21-28, 2014) and Charlie)", false) +)); + +INSTANTIATE_TEST_CASE_P(ABETest4, CCASecurityForKEMTest, + ::testing::Values( + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and (Charlie or David))", "Alice|Charlie", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and (Charlie or David))", "Bob|David", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and (Charlie or David))", "Bob|Eve", false), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie", "((Alice or Bob) and (Charlie or David)) and Alice", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie", "((Alice or Bob) and Alice)", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie", "((Alice and Bob) and Charlie)", false) +)); + +INSTANTIATE_TEST_CASE_P(ABETest5, CCASecurityForKEMTest, + ::testing::Values( + Input(OpenABE_SCHEME_CP_WATERS, "((Alice and Bob) or uid:567abc)", "uid:567abc", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice and Bob) or uid:567abc)", "Alice|Bob", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice and Bob) or uid:567abc)", "Bob|Eve", false), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|uid:567abcdef", "((Alice or Bob) and (Charlie or David)) and Alice", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|uid:567abcdef", "((Alice or Bob) and Alice)", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|uid:567abcdef", "((Alice and Bob) and Charlie)", false) +)); + +INSTANTIATE_TEST_CASE_P(ABETest6, CCASecurityForKEMTest, + ::testing::Values( + Input(OpenABE_SCHEME_CP_WATERS, "Alice and Date = May 1-10, 2016", "Alice|Date=May 5, 2016", true), + Input(OpenABE_SCHEME_CP_WATERS, "Date = May 1-10, 2016 and (Alice or Bob)", "Bob|Date=May 8, 2016", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and Date = May 1-10, 2016)", "Bob|Eve|Date=May 12, 2016", false), + Input(OpenABE_SCHEME_KP_GPSW, "Charlie|Date = June 12, 2014", "(Date = June 10-20, 2014 and (Charlie or David))", true), + Input(OpenABE_SCHEME_KP_GPSW, "David|Date = June 25, 2014", "((David or Bob) and Date = June 21-28, 2014)", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|Date = June 30, 2014", "((Alice and Date = June 21-28, 2014) and Charlie)", false) +)); + + +INSTANTIATE_TEST_CASE_P(ABETest7, CCASecurityForSchemeTest, + ::testing::Values( + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and (Charlie or David))", "Alice|Charlie", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and (Charlie or David))", "Bob|David", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and (Charlie or David))", "Bob|Eve", false), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie", "((Alice or Bob) and (Charlie or David)) and Alice", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie", "((Alice or Bob) and Alice)", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie", "((Alice and Bob) and Charlie)", false) +)); + +INSTANTIATE_TEST_CASE_P(ABETest8, CCASecurityForSchemeTest, + ::testing::Values( + Input(OpenABE_SCHEME_CP_WATERS, "((Alice and Bob) or uid:567abc)", "uid:567abc", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice and Bob) or uid:567abc)", "Alice|Bob", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice and Bob) or uid:567abc)", "Bob|Eve", false), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|uid:567abcdef", "((Alice or Bob) and (Charlie or David)) and Alice", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|uid:567abcdef", "((Alice or Bob) and Alice)", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|uid:567abcdef", "((Alice and Bob) and Charlie)", false) +)); + +INSTANTIATE_TEST_CASE_P(ABETest9, CCASecurityForSchemeTest, + ::testing::Values( + Input(OpenABE_SCHEME_CP_WATERS, "Alice and Date = May 1-10, 2016", "Alice|Date=May 5, 2016", true), + Input(OpenABE_SCHEME_CP_WATERS, "Date = May 1-10, 2016 and (Alice or Bob)", "Bob|Date=May 8, 2016", true), + Input(OpenABE_SCHEME_CP_WATERS, "((Alice or Bob) and Date = May 1-10, 2016)", "Bob|Eve|Date=May 12, 2016", false), + Input(OpenABE_SCHEME_KP_GPSW, "Charlie|Date = June 12, 2014", "(Date = June 10-20, 2014 and (Charlie or David))", true), + Input(OpenABE_SCHEME_KP_GPSW, "David|Date = June 25, 2014", "((David or Bob) and Date = June 21-28, 2014)", true), + Input(OpenABE_SCHEME_KP_GPSW, "Alice|Charlie|Date = June 30, 2014", "((Alice and Date = June 21-28, 2014) and Charlie)", false) +)); + +class SatInput { +public: + SatInput(const string policy_str, const string attr_list, bool expect_pass) { + policy_str_ = policy_str; + attr_list_ = attr_list; + expect_pass_ = expect_pass; + verbose_ = false; + } + ~SatInput() {}; + string policy_str_, attr_list_; + bool verbose_, expect_pass_; +}; + +class CheckIfSatisfiedTests : public ::testing::TestWithParam { +protected: + virtual void SetUp() {} +}; + +TEST_P(CheckIfSatisfiedTests, testWorkingExamples) { + SatInput input = GetParam(); + TEST_DESCRIPTION("Checking sat for: '" + input.policy_str_ + "' sat by '" + input.attr_list_ + "'"); + + unique_ptr policy = createPolicyTree(input.policy_str_); + ASSERT_TRUE(policy != nullptr); + unique_ptr attr_list = createAttributeList(input.attr_list_); + ASSERT_TRUE(attr_list != nullptr); + pair res = checkIfSatisfied(policy.get(), attr_list.get()); + if (input.expect_pass_) { + ASSERT_TRUE(res.first); + } else { + ASSERT_FALSE(res.first); + } +} + +INSTANTIATE_TEST_CASE_P(CheckSat1, CheckIfSatisfiedTests, + ::testing::Values( + // test standard or/and type policy combos + SatInput("((Alice or Bob) or David)", "Bob", true), + SatInput("((Alice and Bob) or David)", "Bob|David", true), + SatInput("(Alice and (Bob or David))", "Bob|David", false), + SatInput("(Alice and (Bob and David))", "Alice|Bob|David", true), + SatInput("((Alice or Bob) and David)", "Bob|David", true), + SatInput("((Alice or Bob) and David)", "Alice|Charlie", false), + SatInput("((Alice or Bob) and David)", "Alice|David", true), + SatInput("(David or Charlie)", "Alice|Bob", false), + SatInput("Bar", "Alice|Bob", false), + SatInput("Alice", "Alice|Bob", true), + SatInput("Foor", "Bar", false), + // test uids + SatInput("((Alice and Bob) or uid:567abcdef)", "uid:567abcdef|Bob", true), + SatInput("((Alice or Bob) and uid:567abcdef)", "uid:567abcdef|Bob", true), + // test integer range + SatInput("(Floor in (2-5) and Alice)", "Alice|Floor=3", true), + SatInput("(Floor in (2-5) and Alice)", "Alice|Floor=7", false), + // test dates and date ranges + SatInput("(David or Date = January 1-31, 2015)", "David|Bob", true), + SatInput("(David or Date = January 1-31, 2015)", "Date=January 27, 2015|Bob", true), + SatInput("(David or Date = January 1-31, 2015)", "Date=March 17, 2015|Bob", false), + SatInput("Date > January 1, 1971", "Date = January 1, 2010", true), + SatInput("Date >= January 1, 1971", "Date = January 1, 1971", true), + SatInput("Date <= January 1, 1971", "Date = January 1, 1975", false), + SatInput("Date < January 1, 1971", "Date = December 1, 2000", false) +)); + +int main(int argc, char **argv) { + int rc; + + InitializeOpenABE(); + + ::testing::InitGoogleTest(&argc, argv); + rc = RUN_ALL_TESTS(); + + ShutdownOpenABE(); + + return rc; +} diff --git a/src/test_keystore.cpp b/src/test_keystore.cpp new file mode 100644 index 00000000..53ee9720 --- /dev/null +++ b/src/test_keystore.cpp @@ -0,0 +1,191 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file src/utils/test_keystore.cpp +/// +/// \brief Testing Keystore manager functionality +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace oabe; + +#define TEST_MSG_LEN 32 +#define TEST_DESCRIPTION(desc) RecordProperty("description", desc) + +namespace { + +class Config { +public: + Config(OpenABE_SCHEME scheme, const string keyList, const string theFuncInput) { + scheme_type = scheme; + // format: 'Alice,Bob:Charlie,David:Eve,Frank' etc + keyInputs = oabe::split(keyList, ':'); + funcInput = theFuncInput; + } + ~Config() {}; + + OpenABE_SCHEME scheme_type; + vector keyInputs; + string funcInput; +}; + +class KeystoreManagerTest : public ::testing::TestWithParam { +protected: + virtual void SetUp() { + rng_.reset(new OpenABERNG); + rng_->getRandomBytes(&plaintext, TEST_MSG_LEN); + MPK = "testMPK"; + MSK = "testMSK"; + } + + unique_ptr getEncInput(OpenABE_SCHEME type, const string func_input) { + if(type == OpenABE_SCHEME_CP_WATERS) + return createPolicyTree(func_input); + else if(type == OpenABE_SCHEME_KP_GPSW) + return createAttributeList(func_input); + return nullptr; + } + + unique_ptr getKeyInput(OpenABE_SCHEME type, string key_input) { + if(type == OpenABE_SCHEME_CP_WATERS) + return createAttributeList(key_input); + else if(type == OpenABE_SCHEME_KP_GPSW) + return createPolicyTree(key_input); + return nullptr; + } + + const string printScheme(OpenABE_SCHEME type) { + switch(type) { + case OpenABE_SCHEME_CP_WATERS: + return "CP-ABE"; break; + case OpenABE_SCHEME_KP_GPSW: + return "KP-ABE"; break; + default: + break; + } + return "None"; + } + + OpenABEByteString mpkBlob, mskBlob, skBlob, ctBlob; + OpenABEByteString plaintext, plaintext1, plaintext2, plaintext3; + unique_ptr rng_; + string MPK, MSK, AUTH1MPK, AUTH1MSK, AUTH2MPK, AUTH2MSK; +}; + + +TEST_P(KeystoreManagerTest, testBaseCases) { + Config input = GetParam(); + TEST_DESCRIPTION("Testing keystore manager works with basic test cases for " + printScheme(input.scheme_type)); + OpenABECiphertext ciphertext; + OpenABE_SCHEME scheme_type = input.scheme_type; + const string userId = "user"; + + cout << "* Testing keystore management for " << printScheme(scheme_type) << " schemes..." << endl; + unique_ptr schemeContext = OpenABE_createContextABESchemeCPA(scheme_type); + // where each string represents a list of attributes or a policy string + vector keyInput = input.keyInputs; + + map keyBlobs; + OpenABEByteString tmp; + unique_ptr keyInput1 = nullptr; + + // generate scheme parameters and keys + schemeContext->generateParams(DEFAULT_BP_PARAM, MPK, MSK); + for(size_t i = 0; i < keyInput.size(); i++) { + const string keyID = "key"+to_string(i+1); + keyInput1 = getKeyInput(scheme_type, keyInput[i]); + cout << "Generate " << keyID << ": " << keyInput1->toString() << endl; + schemeContext->keygen((OpenABEFunctionInput *)keyInput1.get(), keyID, MPK, MSK); + schemeContext->exportKey(keyID, tmp); + keyBlobs[ keyID ] = tmp; + schemeContext->deleteKey(keyID); + } + + cout << "* Load the generated keys..." << endl; + // load the keystore with the generated keys + unique_ptr km(new OpenABEKeystoreManager); + map::iterator it; + uint64_t expireDate = (uint64_t)time(NULL); + for(it = keyBlobs.begin(); it != keyBlobs.end(); it++) { + ASSERT_TRUE(km->storeWithKeyIDCommand(userId, it->first, it->second, expireDate)); + } + + cout << "* Create ciphertext..." << endl; + // create ciphertext and attempt to find key that decrypts it + unique_ptr encInput = getEncInput(input.scheme_type, input.funcInput); + cout << "Functional Input: " << encInput->toString() << endl; + schemeContext->encrypt(NULL, MPK, encInput.get(), &plaintext, &ciphertext); + + cout << "* Search for a key..." << endl; + // attempt decryption + OpenABEKeyQuery query; + query.userId = userId; + query.isEfficient = true; + unique_ptr funcInput = getFunctionInput(&ciphertext); + const string decKey = km->searchKeyCommand(&query, funcInput.get()); + cout << "The decryption key: " << decKey << endl; + ASSERT_TRUE(decKey != ""); + + cout << "* Decrypt with the key: "; + pair sk = km->getKeyCommand(userId, decKey); + skBlob = sk.second; + ASSERT_TRUE(schemeContext->loadUserSecretParams(decKey, skBlob) == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->decrypt(MPK, decKey, &plaintext1, &ciphertext) == OpenABE_NOERROR); + cout << "success!" << endl; +} + +} + +INSTANTIATE_TEST_CASE_P(ABETest5, KeystoreManagerTest, + // arg 1 = scheme type, arg 2 = key input list, arg 3 = enc input string + ::testing::Values(Config(OpenABE_SCHEME_CP_WATERS, "Alice|Bob:Bob|David:Frank|Eve|Alice|Charlie", "((Alice or Bob) and (Charlie or David))"), + Config(OpenABE_SCHEME_KP_GPSW, "((Alice or Charlie) and Eve):(David or Charlie):(Alice and Bob)", "Alice|Bob|Charlie|David") +)); + +int main(int argc, char **argv) { + int rc; + + InitializeOpenABE(); + + ::testing::InitGoogleTest(&argc, argv); + rc = RUN_ALL_TESTS(); + ShutdownOpenABE(); + + return rc; +} diff --git a/src/test_libopenabe.cpp b/src/test_libopenabe.cpp new file mode 100644 index 00000000..072b22bf --- /dev/null +++ b/src/test_libopenabe.cpp @@ -0,0 +1,2404 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file test_libopenabe.cpp +/// +/// \brief Functional testing utility for OpenABE. This executable is capable +/// of running all functional tests, depending on user settings. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace oabe; +using namespace oabe::crypto; + +#define COLOR_STR_GREEN "\033[32m" +#define COLOR_STR_NORMAL "\033[0m" +#define COLOR_STR_RED "\033[31m" + +#define EXIT(msg) cout << msg << endl; goto CLEANUP +#define NUM_PAIRING_TESTS 10 +#define ASSERT_RESULT(condition, msg) if(condition) { \ + cout << "FAIL: " << msg << endl; \ + return false; } + +#define TEST_DESCRIPTION(desc) RecordProperty("description", desc) +#define TESTSUITE_DESCRIPTION(desc) ::testing::Test::RecordProperty("description", desc) + +// Global test counters +uint32_t gNumTests = 0; +uint32_t gSuccessfulTests = 0; + +////////// +// Utility routines +////////// +namespace { + +TEST(libopenabe, PolicyTreeAndAttributeListParser) { + TEST_DESCRIPTION("policy parser works correctly for supported inputs (and rejects invalid inputs)"); + + ASSERT_TRUE(OpenABE_getLibraryVersion() >= 100); + + std::unique_ptr policy1 = createPolicyTree("((one or two) and three)"); + ASSERT_TRUE(policy1 != nullptr); + + std::unique_ptr policy2 = createPolicyTree("((one > 5 or two) and (three == 15))"); + ASSERT_TRUE(policy2 != nullptr); + + std::unique_ptr policy3 = createPolicyTree("((one or two) and (Date > January 1, 2015))"); + ASSERT_TRUE(policy3 != nullptr); + + // test edge cases for attribute lists + vector attr_list; + attr_list.push_back("alice"); + attr_list.push_back("bob"); + attr_list.push_back("charlie"); + std::unique_ptr aList; + ASSERT_ANY_THROW(aList.reset(new OpenABEAttributeList(2, attr_list))); + + std::unique_ptr aList2(new OpenABEAttributeList); + + string test_str1 = "foo:alice", test_str2 = "bar:Date = Jan 1, 2017"; + string compactStr = test_str1 + "|" + test_str2 + "|"; + ASSERT_TRUE(aList2->addAttribute(test_str1)); + ASSERT_TRUE(aList2->addAttribute(test_str2)); + + set m_prefix2 = aList2->getPrefixSet(); +// for (auto& d : m_prefix2) { +// cout << "PREFIX for aList2: " << d << endl; +// } + + OpenABEByteString result; + unique_ptr aList3 = createAttributeList(compactStr); + aList3->serialize(result); + + set m_prefix3 = aList3->getPrefixSet(); +// for (auto& c : m_prefix3) { +// cout << "PREFIX for aList3: " << c << endl; +// } + + ASSERT_EQ(aList2->toCompactString(), result.toString()); + + ASSERT_TRUE(createAttributeList("") == nullptr); + + ASSERT_TRUE(createAttributeList("|this or that|Value = 30#4") == nullptr); + + cout << "Check if isEqual throws an error correctly" << endl; + ASSERT_ANY_THROW(aList2->isEqual(nullptr)); +} + +TEST(libopenabe, BasicPairingTests) { + TEST_DESCRIPTION("Testing that pairing arithmetic is correct"); + + OpenABERNG rng; + // Create a pairing object + OpenABEPairing pairing(DEFAULT_BP_PARAM); + + // Generate a random element of G1, G2 and ZP + G1 eltG1 = pairing.randomG1(&rng); + G1 anotherEltG1 = pairing.randomG1(&rng); + + //pairing.randomElement(GROUP_G1); + G2 eltG2 = pairing.randomG2(&rng); + ZP eltZP = pairing.randomZP(&rng); + + G1 inverseEltG1 = -eltG1; +// OpenABEElement inverseEltG1 = eltG1; +// inverseEltG1.multInverse(); + + // This makes sure that simple arithmetic on + // points in G1 works. + // eltG1 * anotherEltG1 * inv(eltG1) = anotherEltG1 + G1 product = (eltG1 * anotherEltG1); + G1 undo = (product * inverseEltG1); + + ASSERT_TRUE(undo == anotherEltG1); +} + +TEST(libopenabe, PairingArithmeticTests) { + TEST_DESCRIPTION("Testing that pairing arithmetic is correct"); + + OpenABERNG rng; + // Create a pairing object + OpenABEPairing pairing(DEFAULT_BP_PARAM); + G1 eltG1 = pairing.randomG1(&rng); + G2 eltG2 = pairing.randomG2(&rng); + + // Pairing bilinearity test = NUM_PAIRING_TESTS + for (int i = 0; i < NUM_PAIRING_TESTS; i++) { + ZP a = pairing.randomZP(&rng); + ZP b = pairing.randomZP(&rng); + ZP c = pairing.randomZP(&rng); + G1 g1A = eltG1.exp(a); + G1 g1B = eltG1.exp(b); + G2 g2A = eltG2.exp(a); + G2 g2B = eltG2.exp(b); + GT pairingResult = pairing.pairing(g1A, g2B); + //cout << "e(eltG1^a, eltG2^b) = " << pairingResult << endl; + + GT pairingResult2 = pairing.pairing(g1B, g2A); + //cout << "e(eltG1^b, eltG2^a) = " << pairingResult2 << endl; + + ASSERT_TRUE(pairingResult == pairingResult2); + + GT pairingResult3 = pairing.pairing(eltG1, eltG2).exp(a * b); + ASSERT_TRUE(pairingResult == pairingResult3); + + // working for G1 + G1 g1AB = g1A * g1B; + G2 g2C = eltG2.exp(c); + GT pairingResult4 = pairing.pairing(g1AB, g2C); + GT pairingResult5 = pairing.pairing(g1A, g2C) * pairing.pairing(g1B, g2C); + ASSERT_TRUE(pairingResult4 == pairingResult5); + + G2 g2BC = eltG2.exp(b) * eltG2.exp(c); + pairingResult4 = pairing.pairing(g1A, g2BC); + pairingResult5 = pairing.pairing(g1A, g2B) * pairing.pairing(g1A, g2C); + ASSERT_TRUE(pairingResult4 == pairingResult5); + + // verify that e(g1^a, g2^b * g2^c) / e(g1^a, g2^c) == e(g1^a, g2^b) + GT pairingResult6 = pairing.pairing(g1A, g2BC) / pairing.pairing(g1A, g2C); + ASSERT_TRUE(pairingResult == pairingResult6); + } +} + +TEST(libopenabe, MultiPairings) { + TEST_DESCRIPTION("Testing that multi-pairing arithmetic is correct"); + + OpenABERNG rng; + // Create a pairing object + OpenABEPairing pairing(DEFAULT_BP_PARAM); + + vector g1; + vector g2; + // Generate a random element of G1, G2 and ZP + G1 p0 = pairing.randomG1(&rng); + G1 p1 = pairing.randomG1(&rng); + G2 q0 = pairing.randomG2(&rng); + G2 q1 = pairing.randomG2(&rng); + + GT gt1 = pairing.pairing(p0, q0) * pairing.pairing(p1, q1); + // cout << "pairing => " << gt1 << endl; + + g1.push_back(p0); + g1.push_back(p1); + g2.push_back(q0); + g2.push_back(q1); + + GT gt2 = pairing.initGT(); + pairing.multi_pairing(gt2, g1, g2); + // cout << "pairing prod => " << gt2 << endl; + + ASSERT_TRUE(gt1 == gt2); +} + + +TEST(libopenabe, MultiPairingsWithMultipleElements) { + TEST_DESCRIPTION("Testing that multi-pairing arithmetic is correct"); + OpenABERNG rng; + // Create a pairing object + OpenABEPairing pairing(DEFAULT_BP_PARAM); + + vector g1; + vector g2; + G1 p0 = pairing.randomG1(&rng); + G2 q0 = pairing.randomG2(&rng); + + ZP a = pairing.randomZP(&rng); + ZP b = pairing.randomZP(&rng); + ZP c = pairing.randomZP(&rng); + ZP d = pairing.randomZP(&rng); + + g1.push_back(p0.exp(a)); + g1.push_back(p0.exp(b)); + + g2.push_back(q0.exp(c)); + g2.push_back(q0.exp(d)); + + // e(g1^a, g2^c) * e(g1^b, g2^d) + GT gt3 = pairing.pairing(g1.at(0), g2.at(0)) * pairing.pairing(g1.at(1), g2.at(1)); + + GT gt4 = pairing.initGT(); + pairing.multi_pairing(gt4, g1, g2); + + ASSERT_TRUE(gt3 == gt4); +} + +TEST(libopenabe, LinearSecretSharing) { + TEST_DESCRIPTION("Test that secret sharing and recovery are consistent"); + + // Create a pairing object + OpenABEPairing pairing(DEFAULT_BP_PARAM); + // instantiate RNG + OpenABERNG rng; + + // Create a policy + // string str = "(Alice and Bob)"; + //string str = "(Alice or Bob)"; + // string str = "((Alice or Bob) and Charlie)"; + //string str = "((Alice or Bob) and (Charlie or David))"; + //string str = "((Alice or Bob) and (Charlie and David))"; + //string str = "((Alice and Bob) and (Charlie or David))"; + //string str = "((Alice and Bob) or (Charlie and David))"; + string str = "((Alice and Bob) and (Charlie and David))"; // fail + //string str = "(Alice or (Eve and Frank))"; + //string str = "((Eve and Frank) or Alice)"; + //string str = "((Alice and Bob) or Charlie)"; // sort test + std::unique_ptr policy = createPolicyTree(str); + ASSERT_TRUE(policy != nullptr); + cout << "Target Policy: " << policy->toString() << endl; + + // Generate a random secret (element of ZP) + ZP s = pairing.randomZP(&rng); + cout << "Sharing secret s = " << s << endl; + + // Compute the secret shares + OpenABELSSS lsss(&pairing, &rng); + lsss.shareSecret(policy.get(), s); + + // Get the resulting shares + OpenABELSSSRowMap shares = lsss.getRows(); + + cout << "Obtained " << shares.size() << " secret shares" << endl; + // for(OpenABELSSSRowMap::const_iterator testIt = shares.begin(); testIt != shares.end(); ++testIt) { + // cout << "key: " << testIt->first << ", value: " << testIt->second.element() << endl; + // } + + // Next initialize a new LSSS structure and see if we can recover + // from some basic attribute list + OpenABELSSS recoveryLsss(&pairing, &rng); + OpenABEAttributeList attList; + attList.addAttribute(string("Alice")); + attList.addAttribute(string("Bob")); + attList.addAttribute(string("Charlie")); + attList.addAttribute(string("David")); + + // Failed to recover coefficient! Secret sharing not working. + ASSERT_TRUE(recoveryLsss.recoverCoefficients(policy.get(), &attList)); + + OpenABELSSSRowMap coefficients = recoveryLsss.getRows(); + cout << "Required " << coefficients.size() << " coefficients." << endl; + // Now use the coefficients to actually recover the secret from + // shares + ZP recoveredShare = recoveryLsss.LSSStestSecretRecovery(coefficients, shares); + cout << "Recovered secret = " << recoveredShare << endl; + ASSERT_TRUE(recoveredShare == s); + + // Finally, run a test with an invalid attribute list and + // make sure secret recovery fails. This **should** throw an + // exception. + OpenABELSSS recoveryLsss2(&pairing, &rng); + OpenABEAttributeList attList2; + attList2.addAttribute(string("Alice")); + + std::unique_ptr policy2 = createPolicyTree(str); + ASSERT_TRUE(policy2 != nullptr); + ASSERT_FALSE(recoveryLsss2.recoverCoefficients(policy2.get(), &attList2)); + + OpenABELSSSRowMap coefficients2 = recoveryLsss2.getRows(); + cout << "Required " << coefficients2.size() << " coefficients." << endl; + + + OpenABEPolicy *policy3 = new OpenABEPolicy; + OpenABETreeNode *left = new OpenABETreeNode("Alice"); + OpenABETreeNode *right = new OpenABETreeNode("Bob"); + OpenABETreeNode *right2 = new OpenABETreeNode("Charlie"); + + OpenABETreeNode *m_rootNode = new OpenABETreeNode; + m_rootNode->setNodeType(GATE_TYPE_THRESHOLD); + m_rootNode->addSubnode(left); + m_rootNode->addSubnode(right); + m_rootNode->addSubnode(right2); + + policy3->setRootNode(m_rootNode); + + // testing more edge cases + ASSERT_ANY_THROW(recoveryLsss2.recoverCoefficients(policy3, &attList2)); + SAFE_DELETE(policy3); + + OpenABELSSS new_lsss(&pairing, &rng); + ASSERT_ANY_THROW(new_lsss.shareSecret(nullptr, s)); + +// ZP recoveredShare2 = recoveryLsss2.LSSStestSecretRecovery(coefficients2, shares); +// cout << "Recovered secret = " << recoveredShare2 << endl; +// ASSERT_TRUE(recoveredShare == s); + + +// { +// // We succeeded in recovering, which means there was a problem with +// // this test! +// cout << "Error: recovered coefficients for invalid function input" << endl; +// return false; +// } +// +// +// { +// cout << "Recovered secret does not match!" << endl; +// return false; +// } +} + +TEST(libopenabe, Base64Tests) { + TEST_DESCRIPTION("Testing that Base64 encode/decode works correctly"); + const string to_encode("Hello, world!"); + const string encoded_result("SGVsbG8sIHdvcmxkIQ=="); + const string result = Base64Encode((const unsigned char*)to_encode.data(), + to_encode.size()); + if (encoded_result != result) { + cout << "Didn't base64 encode to known result! " + << "(expected: " << encoded_result << " got: " << result << ")" + << endl; + } + ASSERT_TRUE(encoded_result == result); + + if (to_encode != Base64Decode(encoded_result)) { + cout << "Encode followed by decode of '" << to_encode + << "' didn't work!" << endl; + } + ASSERT_TRUE(to_encode == Base64Decode(encoded_result)); + + const string invalid_b64("~"); + EXPECT_THROW(Base64Decode(invalid_b64), OpenABE_ERROR); // OpenABE_ERROR_INVALID_INPUT +} + +TEST(libopenabe, SerializationTests) { + TEST_DESCRIPTION("Testing that pairing group elements serialization works correctly"); + // Create a pairing object + OpenABEPairing pairing(DEFAULT_BP_PARAM); + OpenABERNG rng; + ZP x1, x2; + pairing.initZP(x2, 0); + G1 g01 = pairing.initG1(), g10 = pairing.initG1(); + G2 g20 = pairing.initG2(), g21 = pairing.initG2(); + GT gt20 = pairing.initGT(), gt21 = pairing.initGT(); + int trials = 5; + + for(int i = 0; i < trials; i++) { + cout << "iteration " << i; + OpenABEByteString byteBlob; + x1 = pairing.randomZP(&rng); + x1.serialize(byteBlob); + //cout << "x1 bytes : " << byteBlob.toHex() << endl; + //cout << "x1 : " << x1 << endl; + + // deserialize now + x2.deserialize(byteBlob); + //cout << "x2 : " << x2 << endl; + ASSERT_TRUE(x1 == x2); + + // cout << endl << endl; + g01 = pairing.randomG1(&rng); + g01.serialize(byteBlob); + //cout << "G1 : " << byteBlob.toHex() << endl; + + g10.deserialize(byteBlob); + // cout << "g01: " << g01 << endl; + // cout << "g10: " << g10 << endl; + ASSERT_TRUE(g01 == g10); + + OpenABEByteString byteBlob1; + cout << endl << endl; + g20 = pairing.randomG2(&rng); + g20.serialize(byteBlob1); + // cout << "G2 : " << byteBlob1.toHex() << endl; + + g21.deserialize(byteBlob1); + //cout << "g20 : " << g20 << endl; + //cout << "g21 : " << g21 << endl; + ASSERT_TRUE(g20 == g21); + + OpenABEByteString byteBlob2; + // cout << endl << endl; + gt20 = pairing.pairing(g01, g20); + gt20.serialize(byteBlob2); + // cout << "GT : " << byteBlob2.toHex() << endl; + + gt21.deserialize(byteBlob2); + //cout << "gt20 : " << gt20 << endl; + //cout << "gt21 : " << gt21 << endl; + ASSERT_TRUE(gt20 == gt21); + } +} + +TEST(libopenabe, SerializationIntTests) { + TEST_DESCRIPTION("Testing that integer elements serialization works correctly"); + + OpenABEByteString byteBlob3; + OpenABEUInteger ui1(3735928559, 32), ui2(0, 32); + ui1.serialize(byteBlob3); + // cout << "ui1 => " << ui1 << endl; + cout << "32-bit INT: " << byteBlob3.toHex() << endl; + ui2.deserialize(byteBlob3); + // cout << "ui2 => " << ui2 << endl; + ASSERT_TRUE(ui1 == ui2); + + uint64_t val = 144674407370955150; + OpenABEUInteger ui3(val, 64), ui4(0, 64); + ui3.serialize(byteBlob3); + cout << "64-bit INT: " << byteBlob3.toHex() << endl; + ui4.deserialize(byteBlob3); + ASSERT_TRUE(ui3 == ui4); +} + +TEST(libopenabe, OpenABEByteStringZeroize) { + TEST_DESCRIPTION("Testing that zeroization for OpenABEByteString works correctly"); + OpenABERNG rng; + OpenABEByteString buf, empty; + + rng.getRandomBytes(&buf, 100); + cout << "Rand Bytes: " << buf.toHex() << endl; + buf.zeroize(); + + ASSERT_TRUE(buf.toHex() == empty.toHex()); + ASSERT_TRUE(buf.size() == empty.size()); +} + +TEST(libopenabe, OpenABECiphertextTests) { + TEST_DESCRIPTION("Test that ciphertext can support all container object types"); + + // Create a pairing object + OpenABEPairing pairing(DEFAULT_BP_PARAM); + OpenABERNG rng; + OpenABECiphertext *ciphertext = new OpenABECiphertext(pairing.getGroup()); + ciphertext->setHeader(OpenABE_NONE_ID, OpenABE_SCHEME_NONE, &rng); + + // create an element of ZP and store/get from ciphertext + ZP c0 = pairing.randomZP(&rng); + ciphertext->setComponent("C0", &c0); + ZP *c1 = ciphertext->getZP("C0"); + ASSERT_TRUE(c0 == *c1); + + G1 g0 = pairing.randomG1(&rng); + ciphertext->setComponent("G1", &g0); + G1 *g1 = ciphertext->getG1("G1"); + ASSERT_TRUE(g0 == *g1); + + G2 g2 = pairing.randomG2(&rng); + ciphertext->setComponent("G2", &g2); + G2 *g3 = ciphertext->getG2("G2"); + ASSERT_TRUE(g2 == *g3); + + GT gt = pairing.pairing(g0, g2); + //cout << "gt : " << gt << endl; + ciphertext->setComponent("GT", >); + GT *gt0 = ciphertext->getGT("GT"); + ASSERT_TRUE(gt == *gt0); + + string s = "storing this as a test byte string."; + OpenABEByteString someText; + someText = s; + // cout << "Storing ByteString: '" << someText << "'\n"; + ciphertext->setComponent("str", &someText); + // OpenABEByteString *someText2 = ciphertext->getByteString("str"); + // cout << "Recovered ByteString: '" << *someText2 << "'\n"; + + uint32_t integer = 128; + OpenABEUInteger i(integer); + // cout << "Storing integer: " << i << endl; + ciphertext->setComponent("int", &i); + OpenABEUInteger *i2 = ciphertext->getInteger("int"); + ASSERT_TRUE(i2->getVal() == i.getVal()); + // cout << "Recovered integer: " << i2->getVal() << endl; + + vector attributes(3); + attributes[0] = "Alice"; + attributes[1] = "Bob"; + attributes[2] = "Charlie"; + OpenABEAttributeList *attrlist = new OpenABEAttributeList(3, attributes); + cout << "<== ATTRIBUTES ==>\n" << *attrlist << "<== ATTRIBUTES ==>\n"; + ciphertext->setComponent("stuff", attrlist); + + OpenABECiphertext *ciphertext2 = new OpenABECiphertext(pairing.getGroup()); + // test serializing the entire ciphertext into a blob (or OpenABEByteString?) + OpenABEByteString ctBlob; + ciphertext->exportToBytes(ctBlob); + // cout << "<======== CIPHERTEXT ========>\n"; + // cout << ctBlob << endl; + // cout << "<======== CIPHERTEXT ========>\n"; + + ciphertext2->loadFromBytes(ctBlob); + + ZP *c11 = ciphertext->getZP("C0"); + ASSERT_TRUE(c0 == *c11); + + G1 *g11 = ciphertext2->getG1("G1"); + ASSERT_TRUE(g0 == *g11); + + G2 *g33 = ciphertext2->getG2("G2"); + ASSERT_TRUE(g2 == *g33); + + GT *gt00 = ciphertext2->getGT("GT"); + // cout << "gt 2: " << gt << endl; + // cout << "gt00: " << *gt00 << endl; + ASSERT_TRUE(gt == *gt00); + + OpenABEByteString *someText22 = ciphertext2->getByteString("str"); + cout << "Recovered ByteString: '" << *someText22 << "'\n"; + + OpenABEUInteger *i22 = ciphertext2->getInteger("int"); + cout << "Recovered integer: " << i22->getVal() << endl; + + OpenABEAttributeList *attrlist2 = (OpenABEAttributeList*) ciphertext->getComponent("stuff"); + cout << "attrlist2 :\n<== ATTRIBUTES ==>\n" << *attrlist2 << "<== ATTRIBUTES ==>\n"; + + ASSERT_TRUE(*ciphertext == *ciphertext2); + + OpenABEByteString uid, emptyUid; + rng.getRandomBytes(&uid, UID_LEN); + + OpenABECiphertext ct(uid); // random + OpenABECiphertext ct2(emptyUid); // emtpy (means will be generated internally) + ASSERT_TRUE(ct.getUID() != ct2.getUID()); + + OpenABECiphertext ct3; + // should be an invalid input (due to less bytes than header size) + ASSERT_ANY_THROW(ct3.loadFromBytes(uid)); + + OpenABEByteString ctBuf; + ciphertext->getHeader(ctBuf); + + cout << "ctBuf.hex() => " << ctBuf.toHex() << endl; + ctBuf.insertFirstByte(0x11); // add 1 to header len (16 bytes) + ctBuf.insertFirstByte(PACK_8); + + ASSERT_ANY_THROW(ct3.loadFromBytes(ctBuf)); + + // cleanup + SAFE_DELETE(ciphertext); + SAFE_DELETE(ciphertext2); + SAFE_DELETE(attrlist); +} + +TEST(libopenabe, CPATestsForCpAbeKEMContext) { + TEST_DESCRIPTION("Testing that CPA secure CP-ABE KEM encryption and decryption context is correct"); + OpenABEContextABE *context = NULL; + OpenABEAttributeList *attrlist = NULL; + OpenABECiphertext *ciphertext = NULL; + OpenABESymKeyEnc *aes = NULL, *aes2 = NULL; + shared_ptr symkey(new OpenABESymKey), newkey(new OpenABESymKey); + unique_ptr rng(new OpenABERNG); + + // Initialize an RNG + // Initialize a OpenABEContext structure + context = OpenABE_createContextABE(&rng, OpenABE_SCHEME_CP_WATERS); + ASSERT_FALSE(context == NULL); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(context->generateParams(DEFAULT_BP_PARAM, "testMPK", "testMSK") == OpenABE_NOERROR); + + + // Encrypt a test key using the KEM mode + string s = "((Alice or Bob) and (Charlie or David))"; + std::unique_ptr policy = createPolicyTree(s); + ciphertext = new OpenABECiphertext; + ASSERT_FALSE(context->encryptKEM(NULL, "testMPK", nullptr, DEFAULT_SYM_KEY_BYTES, symkey, ciphertext) == OpenABE_NOERROR); + + ASSERT_FALSE(context->encryptKEM(NULL, "noSuchMPK", policy.get(), DEFAULT_SYM_KEY_BYTES, symkey, ciphertext) == OpenABE_NOERROR); + + ASSERT_TRUE(context->encryptKEM(NULL, "testMPK", policy.get(), DEFAULT_SYM_KEY_BYTES, symkey, ciphertext) == OpenABE_NOERROR); + + string symKeyStr = symkey->toString(); + cout << "Original symmetric key: " << symKeyStr << endl; + aes = new OpenABESymKeyEnc(symKeyStr); + string data = "0123456789098765 and hello world!"; + string ciphertext2 = aes->encrypt((uint8_t*) data.c_str(), (uint32_t) data.size()); + cout << "successfully encrypted: " << ciphertext2 << endl; + + vector attributes(2); + attributes[0] = "Alice"; + attributes[1] = "Charlie"; + attrlist = new OpenABEAttributeList(2, attributes); + cout << "<== ATTRIBUTES ==>\n" << *attrlist << "<== ATTRIBUTES ==>\n"; + ASSERT_TRUE(context->generateDecryptionKey(attrlist, "decKey", "testMPK", "testMSK") == OpenABE_NOERROR); + + ASSERT_FALSE(context->generateDecryptionKey(nullptr, "decKeyBad", "testMPK", "testMSK") == OpenABE_NOERROR); + + ASSERT_FALSE(context->generateDecryptionKey(attrlist, "decKeyBad", "badMPKId", "testMSK") == OpenABE_NOERROR); + + // Decrypt with a bad key + ASSERT_FALSE(context->decryptKEM("testMPK", "noSuchDecKey", ciphertext, DEFAULT_SYM_KEY_BYTES, newkey) == OpenABE_NOERROR); + + // Decrypt the ciphertext + ASSERT_TRUE(context->decryptKEM("testMPK", "decKey", ciphertext, DEFAULT_SYM_KEY_BYTES, newkey) == OpenABE_NOERROR); + + string newKeyStr = newkey->toString(); + cout << "Decrypted symmetric key: " << newKeyStr << endl << endl; + aes2 = new OpenABESymKeyEnc(newKeyStr); + string plaintext = aes2->decrypt(ciphertext2); + cout << "Plaintext: " << plaintext << endl; + + ASSERT_TRUE(symKeyStr.compare(newKeyStr.c_str()) == 0); + ASSERT_TRUE(data.compare(plaintext) == 0); + + SAFE_DELETE(attrlist); + SAFE_DELETE(ciphertext); + SAFE_DELETE(aes); + SAFE_DELETE(aes2); + SAFE_DELETE(context); +} + + +TEST(libopenabe, CPATestsForCpAbeSchemeContext) { + TEST_DESCRIPTION("Testing that CPA secure CP-ABE scheme context is correct"); + unique_ptr schemeContext = nullptr; + OpenABEAttributeList *attrlist = NULL; + OpenABECiphertext *ciphertext = NULL; + OpenABEByteString mpkBlob, mskBlob; + + // initialize a scheme context with the KEM context + schemeContext = OpenABE_createContextABESchemeCPA(OpenABE_SCHEME_CP_WATERS); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(schemeContext->generateParams(DEFAULT_BP_PARAM, "testMPK", "testMSK") == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->exportKey("testMPK", mpkBlob) == OpenABE_NOERROR); + + // cout << "MPK: " << mpkBlob.toHex() << "\nlen: " << mpkBlob.size() << endl; + + ASSERT_TRUE(schemeContext->exportKey("testMSK", mskBlob) == OpenABE_NOERROR); + + // cout << "MSK: " << mskBlob.toHex() << "\nlen: " << mskBlob.size() << endl; + + ASSERT_TRUE(schemeContext->deleteKey("testMPK") == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->deleteKey("testMSK") == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->loadMasterPublicParams("testMPK", mpkBlob) == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->loadMasterSecretParams("testMSK", mskBlob) == OpenABE_NOERROR); + + OpenABEByteString plaintext; + plaintext = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x40\x41\x42\x43\x44\x45\x46"; + string s = "((Alice or Bob) and (Charlie or David))"; + std::unique_ptr policy = createPolicyTree(s); + ciphertext = new OpenABECiphertext; + ASSERT_TRUE (schemeContext->encrypt(NULL, "testMPK", policy.get(), &plaintext, ciphertext) == OpenABE_NOERROR); + + vector attributes(3); + attributes[0] = "Alice"; + attributes[1] = "Bob"; + attributes[2] = "Charlie"; + attrlist = new OpenABEAttributeList(3, attributes); + cout << "<== ATTRIBUTES ==>\n" << *attrlist << "<== ATTRIBUTES ==>\n"; + ASSERT_TRUE(schemeContext->keygen(attrlist, "decKey", "testMPK", "testMSK") == OpenABE_NOERROR); + + // Decrypt the ciphertext + OpenABEByteString plaintext2; + ASSERT_TRUE(schemeContext->decrypt("testMPK", "decKey", &plaintext2, ciphertext) == OpenABE_NOERROR); + + cout << "Orig M: " << plaintext.toHex() << endl; + cout << "Recv M: " << plaintext2.toHex() << endl; + ASSERT_TRUE(plaintext.toHex() == plaintext2.toHex()); + + SAFE_DELETE(ciphertext); + SAFE_DELETE(attrlist); +} + +TEST(libopenabe, CPATestsForKpAbeSchemeContext) { + TEST_DESCRIPTION("Testing that CPA secure KP-ABE scheme context is correct"); + unique_ptr schemeContext = nullptr; + OpenABEAttributeList *attrlist = NULL; + OpenABECiphertext *ciphertext = NULL; + OpenABEByteString mpkBlob, mskBlob; + + // initialize a scheme context with the KEM context + schemeContext = OpenABE_createContextABESchemeCPA(OpenABE_SCHEME_KP_GPSW); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(schemeContext->generateParams(DEFAULT_BP_PARAM, "testMPK", "testMSK") == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->exportKey("testMPK", mpkBlob) == OpenABE_NOERROR); + + // cout << "MPK: " << mpkBlob.toHex() << "\nlen: " << mpkBlob.size() << endl; + + ASSERT_TRUE(schemeContext->exportKey("testMSK", mskBlob) == OpenABE_NOERROR); + + // cout << "MSK: " << mskBlob.toHex() << "\nlen: " << mskBlob.size() << endl; + + ASSERT_TRUE(schemeContext->deleteKey("testMPK") == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->deleteKey("testMSK") == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->loadMasterPublicParams("testMPK", mpkBlob) == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->loadMasterSecretParams("testMSK", mskBlob) == OpenABE_NOERROR); + + OpenABEByteString plaintext; + plaintext = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x40\x41\x42\x43\x44\x45\x46"; + vector attributes(3); + attributes[0] = "Alice"; + attributes[1] = "Bob"; + attributes[2] = "Charlie"; + attrlist = new OpenABEAttributeList(3, attributes); + cout << "<== ATTRIBUTES ==>\n" << *attrlist << "<== ATTRIBUTES ==>\n"; + ciphertext = new OpenABECiphertext; + + ASSERT_TRUE(schemeContext->encrypt(NULL, "testMPK", attrlist, &plaintext, ciphertext) == OpenABE_NOERROR); + + string s = "((Alice or Bob) and (Charlie or David))"; + std::unique_ptr policy = createPolicyTree(s); + ASSERT_TRUE(schemeContext->keygen(policy.get(), "decKey", "testMPK", "testMSK") == OpenABE_NOERROR); + + // Decrypt the ciphertext + OpenABEByteString plaintext2; + ASSERT_TRUE(schemeContext->decrypt("testMPK", "decKey", &plaintext2, ciphertext) == OpenABE_NOERROR); + + cout << "Orig M: " << plaintext.toHex() << endl; + cout << "Recv M: " << plaintext2.toHex() << endl; + ASSERT_TRUE(plaintext.toHex() == plaintext2.toHex()); + + SAFE_DELETE(ciphertext); + SAFE_DELETE(attrlist); +} + +TEST(libopenabe, CCATestsForCpAbeKEMContext) { + TEST_DESCRIPTION("Testing that CCA secure CP-ABE KEM context (wrapper around CPA KEM) is correct"); + + unique_ptr schemeContext = nullptr; + OpenABEContextCCA *contextCCAKEM = NULL; + OpenABECiphertext *ciphertext = NULL; + OpenABEAttributeList *attrlist = NULL; + shared_ptr symkey(new OpenABESymKey), newkey(new OpenABESymKey); + // Initialize an RNG + unique_ptr rng(new OpenABERNG); + + // initialize a scheme context with the KEM context + schemeContext = OpenABE_createContextABESchemeCPA(OpenABE_SCHEME_CP_WATERS); + + // initialize a CCA scheme context + contextCCAKEM = (OpenABEContextCCA*) new OpenABEContextGenericCCA(std::move(schemeContext)); + ASSERT_FALSE(contextCCAKEM == NULL); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(contextCCAKEM->generateParams(DEFAULT_BP_PARAM, "testMPK", "testMSK") == OpenABE_NOERROR); + + // should return false + ASSERT_FALSE(contextCCAKEM->generateParams(DEFAULT_BP_PARAM, "testMPK", "testMSK") == OpenABE_NOERROR); + + // Encrypt a test key using the KEM mode + string s = "((Alice or Bob) and (Charlie or David))"; + std::unique_ptr policy = createPolicyTree(s); + ciphertext = new OpenABECiphertext; + ASSERT_FALSE(contextCCAKEM->encryptKEM(rng.get(), "testMPK", nullptr, DEFAULT_SYM_KEY_BYTES, symkey, ciphertext) == OpenABE_NOERROR); + ASSERT_FALSE(contextCCAKEM->encryptKEM(rng.get(), "noSuchMPK", policy.get(), DEFAULT_SYM_KEY_BYTES, symkey, ciphertext) == OpenABE_NOERROR); + + ASSERT_TRUE(contextCCAKEM->encryptKEM(rng.get(), "testMPK", policy.get(), DEFAULT_SYM_KEY_BYTES, symkey, ciphertext) == OpenABE_NOERROR); + + const string symkeyStr = symkey->toString(); + cout << "Orig symmetric key: " << symkeyStr << endl; + + // generate a decryption key + vector attributes(3); + attributes[0] = "Alice"; + attributes[1] = "Bob"; + attributes[2] = "Charlie"; + attrlist = new OpenABEAttributeList(attributes.size(), attributes); + cout << "<== ATTRIBUTES ==>\n" << *attrlist << "<== ATTRIBUTES ==>\n"; + ASSERT_TRUE(contextCCAKEM->generateDecryptionKey(attrlist, "decKey", "testMPK", "testMSK") == OpenABE_NOERROR); + + // Decrypt the ciphertext + ASSERT_TRUE(contextCCAKEM->decryptKEM("testMPK", "decKey", ciphertext, DEFAULT_SYM_KEY_BYTES, newkey) == OpenABE_NOERROR); + + const string newkeyStr = newkey->toString(); + cout << "Recv symmetric key: " << newkeyStr << endl; + ASSERT_TRUE(symkeyStr.compare(newkeyStr) == 0); + + SAFE_DELETE(attrlist); + SAFE_DELETE(ciphertext); + SAFE_DELETE(contextCCAKEM); +} + +TEST(libopenabe, CCATestsForCpAbeSchemeContext) { + TEST_DESCRIPTION("Testing that CCA secure CP-ABE Scheme context (wrapper around CCA KEM) is correct"); + OpenABECiphertext *ciphertext1 = nullptr, *ciphertext2 = nullptr; + OpenABEAttributeList *attrlist = nullptr; + string plaintext1, plaintext2; + // Initialize an RNG + + // initialize a scheme context with the KEM context + unique_ptr ccaSchemeContext = OpenABE_createContextABESchemeCCA(OpenABE_SCHEME_CP_WATERS); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(ccaSchemeContext->generateParams(DEFAULT_BP_PARAM, "testMPK", "testMSK") == OpenABE_NOERROR); + + // Encrypt a test key using the KEM mode + std::unique_ptr policy = createPolicyTree("((Alice or Bob) and (Charlie or David))"); + plaintext1 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + ciphertext1 = new OpenABECiphertext; + ciphertext2 = new OpenABECiphertext; + ASSERT_TRUE(ccaSchemeContext->encrypt("testMPK", policy.get(), plaintext1, ciphertext1, ciphertext2) == OpenABE_NOERROR); + + vector attributes; + attributes.push_back("Alice"); + attributes.push_back("Bob"); + attributes.push_back("Charlie"); + attrlist = new OpenABEAttributeList(attributes.size(), attributes); + cout << "<== ATTRIBUTES ==>\n" << *attrlist << "<== ATTRIBUTES ==>\n"; + ASSERT_TRUE(ccaSchemeContext->keygen(attrlist, "decKey", "testMPK", "testMSK") == OpenABE_NOERROR); + + // Decrypt the ciphertext + ASSERT_TRUE(ccaSchemeContext->decrypt("testMPK", "decKey", plaintext2, ciphertext1, ciphertext2) == OpenABE_NOERROR); + + cout << "Orig M: " << plaintext1 << endl; + cout << "Recv M: " << plaintext2 << endl; + ASSERT_TRUE(plaintext1.compare(plaintext2) == 0); + + SAFE_DELETE(ciphertext1); + SAFE_DELETE(ciphertext2); + SAFE_DELETE(attrlist); +} + +TEST(libopenabe, CCATestsForKpAbeSchemeContextWithATZN) { + TEST_DESCRIPTION("Testing that CCA secure KP-ABE Scheme context with amortization (wrapper around CCA KEM) is correct"); + OpenABECiphertext *ciphertext = nullptr; + string key1, key2; + string plaintext1, plaintext2, ciphertext1, ciphertext2; + OpenABEByteString out1, out2; + + // initialize a scheme context with the KEM context + unique_ptr ccaKpabe = OpenABE_createContextABESchemeCCAWithATZN(OpenABE_SCHEME_KP_GPSW); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(ccaKpabe->generateParams(DEFAULT_BP_PARAM, "testMPK", "testMSK") == OpenABE_NOERROR); + + // Encrypt a test key using the KEM mode + std::unique_ptr attrlist = createAttributeList("Alice|Bob|Charlie"); + ciphertext = new OpenABECiphertext; + unique_ptr keyHandle1 = ccaKpabe->encrypt("testMPK", attrlist.get(), ciphertext); + + // encrypt plaintext files using handle + plaintext1 = "hello world this is message 1 under same enc input."; + keyHandle1->encrypt(ciphertext1, plaintext1); + out1 = ciphertext1; + cout << "Ciphertext 1: " << out1.toHex() << " => " << ciphertext1.size() << " bytes" << endl; + + plaintext2 = "hello world this is message 2 under same enc input."; + keyHandle1->encrypt(ciphertext2, plaintext2); + out2 = ciphertext2; + cout << "Ciphertext 2: " << out2.toHex() << " => " << ciphertext2.size() << " bytes" << endl; + ASSERT_TRUE(out1 != out2); + + // Generate the decryption key + std::unique_ptr policy = createPolicyTree("((Alice or Bob) and (Charlie or David))"); + cout << "<== POLICY ==>\n" << *policy << "\n<== POLICY ==>\n"; + ASSERT_TRUE(ccaKpabe->keygen(policy.get(), "decKey", "testMPK", "testMSK") == OpenABE_NOERROR); + + // Decrypt the ciphertext + unique_ptr keyHandle2 = ccaKpabe->decrypt("testMPK", "decKey", ciphertext); + ASSERT_TRUE(keyHandle2 != nullptr); + + keyHandle1->exportKey(key1); + keyHandle2->exportKey(key2); + + out1 = key1; + out2 = key2; + + cout << "Orig K: " << out1.toHex() << endl; + cout << "Recv K: " << out2.toHex() << endl; + ASSERT_TRUE(key1.compare(key2) == 0); + + string pt1, pt2; + keyHandle2->decrypt(pt2, ciphertext2); + keyHandle2->decrypt(pt1, ciphertext1); + ASSERT_TRUE(plaintext1.compare(pt1) == 0); + ASSERT_TRUE(plaintext2.compare(pt2) == 0); + cout << "Rec M1: " << pt1 << endl; + cout << "Rec M2: " << pt2 << endl; + + SAFE_DELETE(ciphertext); +} + + +TEST(libopenabe, CPATestsForKpAbeKEMContext) { + TEST_DESCRIPTION("Testing that CPA secure KP-ABE KEM encryption and decryption context is correct"); + + OpenABEContextABE *context = NULL; + OpenABEAttributeList *attrlist = NULL; + OpenABECiphertext *ciphertext = NULL; + shared_ptr symkey(new OpenABESymKey), newkey(new OpenABESymKey); + // Initialize an RNG + unique_ptr rng(new OpenABERNG); + + // Initialize a OpenABEContext structure + context = OpenABE_createContextABE(&rng, OpenABE_SCHEME_KP_GPSW); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(context->generateParams(DEFAULT_BP_PARAM, "testMPK", "testMSK") == OpenABE_NOERROR); + + // can't generate params for an existing ID + ASSERT_TRUE(context->generateParams(DEFAULT_BP_PARAM, "testMPK", "testMSK") == OpenABE_ERROR_INVALID_PARAMS_ID); + + vector attributes(3); + attributes[0] = "Alice"; + attributes[1] = "Bob"; + attributes[2] = "Charlie"; + attrlist = new OpenABEAttributeList(attributes.size(), attributes); + cout << "<== ATTRIBUTES ==>\n" << *attrlist << "<== ATTRIBUTES ==>\n"; + + ciphertext = new OpenABECiphertext; + ASSERT_TRUE(context->encryptKEM(NULL, "testMPK", nullptr, DEFAULT_SYM_KEY_BYTES, symkey, ciphertext) == OpenABE_ERROR_INVALID_INPUT); + ASSERT_TRUE(context->encryptKEM(NULL, "noSuchMPK", attrlist, DEFAULT_SYM_KEY_BYTES, symkey, ciphertext) == OpenABE_ERROR_INVALID_PARAMS); + + ASSERT_TRUE(context->encryptKEM(NULL, "testMPK", attrlist, DEFAULT_SYM_KEY_BYTES, symkey, ciphertext) == OpenABE_NOERROR); + + string symKeyStr = symkey->toString(); + cout << "Original symmetric key: " << symKeyStr << endl; + + string s = "((Alice or Bob) and (Charlie or David))"; + cout << "Decryption key policy: " << s << endl; + std::unique_ptr policy = createPolicyTree(s); + // fail + ASSERT_TRUE(context->generateDecryptionKey(nullptr, "decKey", "testMPK", "testMSK") == OpenABE_ERROR_INVALID_INPUT); + // fail + ASSERT_TRUE(context->generateDecryptionKey(policy.get(), "decKey", "noSuchMPK", "testMSK") == OpenABE_ERROR_INVALID_PARAMS); + + ASSERT_TRUE(context->generateDecryptionKey(policy.get(), "decKey", "testMPK", "testMSK") == OpenABE_NOERROR); + + // Decrypt the ciphertext + ASSERT_TRUE(context->decryptKEM("testMPK", "decKey", ciphertext, DEFAULT_SYM_KEY_BYTES, newkey) == OpenABE_NOERROR); + + string newKeyStr = newkey->toString(); + cout << "Decrypted symmetric key: " << newKeyStr << endl << endl; + + SAFE_DELETE(attrlist); + SAFE_DELETE(ciphertext); + SAFE_DELETE(context); +} + +TEST(libopenabe, CCATestsForKpAbeKEMContext) { + TEST_DESCRIPTION("Testing that CCA secure KP-ABE KEM context (wrapper around CPA KEM) is correct"); + unique_ptr schemeContext = nullptr; + OpenABEContextCCA *contextCCAKEM = NULL; + OpenABEAttributeList *attrlist = NULL; + OpenABECiphertext *ciphertext = NULL; + shared_ptr symkey(new OpenABESymKey), newkey(new OpenABESymKey); + // Initialize an RNG + unique_ptr rng(new OpenABERNG); + unique_ptr rng2(new OpenABERNG); + + // initialize a scheme context with the KEM context + schemeContext = OpenABE_createContextABESchemeCPA(OpenABE_SCHEME_KP_GPSW); + + // initialize a CCA scheme context + contextCCAKEM = (OpenABEContextCCA*) new OpenABEContextGenericCCA(std::move(schemeContext)); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(contextCCAKEM->generateParams(DEFAULT_BP_PARAM, "testMPK", "testMSK") == OpenABE_NOERROR); + + // Encrypt a test key using the KEM mode + vector attributes(3); + attributes[0] = "Alice"; + attributes[1] = "Bob"; + attributes[2] = "Charlie"; + attrlist = new OpenABEAttributeList(attributes.size(), attributes); + cout << "<== ATTRIBUTES ==>\n" << *attrlist << "<== ATTRIBUTES ==>\n"; + ciphertext = new OpenABECiphertext; + ASSERT_TRUE(contextCCAKEM->encryptKEM(rng2.get(), "testMPK", attrlist, DEFAULT_SYM_KEY_BYTES, symkey, ciphertext) == OpenABE_NOERROR); + const string symkeyStr = symkey->toString(); + cout << "Orig symmetric key: " << symkeyStr << endl; + + // generate a decryption key + string s = "((Alice or Bob) and (Charlie or David))"; + std::unique_ptr policy = createPolicyTree(s); + ASSERT_TRUE(contextCCAKEM->generateDecryptionKey(policy.get(), "decKey", "testMPK", "testMSK") == OpenABE_NOERROR); + + // Decrypt the ciphertext + ASSERT_TRUE(contextCCAKEM->decryptKEM("testMPK", "decKey", ciphertext, DEFAULT_SYM_KEY_BYTES, newkey) == OpenABE_NOERROR); + + const string newkeyStr = newkey->toString(); + cout << "Recv symmetric key: " << newkeyStr << endl; + ASSERT_TRUE(newkeyStr.compare(symkeyStr) == 0); + + SAFE_DELETE(attrlist); + SAFE_DELETE(ciphertext); + SAFE_DELETE(contextCCAKEM); +} + + +TEST(libopenabe, CSPRNG) { + TEST_DESCRIPTION("CSPRNG using AES-CTR-128 encryption"); + OpenABERNG *rng = NULL, *csprng1 = NULL, *csprng2 = NULL; + uint8_t buf[SHA256_LEN+1]; + + rng = new OpenABERNG; + + rng->getRandomBytes(buf, SHA256_LEN); + cout << "OpenSSL RNG test:\n"; + BIO_dump_fp(stdout, (const char *) buf, SHA256_LEN); + cout << endl; + rng->getRandomBytes(buf, SHA256_LEN); + BIO_dump_fp(stdout, (const char *) buf, SHA256_LEN); + cout << endl; + + + cout << "OpenSSL PRNG test:\n"; + OpenABEPairing pairing(DEFAULT_BP_PARAM); + + uint32_t length = 64; + ZP x = pairing.randomZP(rng); + size_t byte_len = SHA256_LEN; + + cout << "x : " << x << endl; + OpenABEByteString xBin = x.getByteString(); + cout << "xBin : " << xBin.toHex() << endl; + cout << "xBin size : " << xBin.size() << endl; + if (xBin.size() < byte_len) { + size_t x_size = xBin.size(); + for(size_t i = 0; i < (byte_len - x_size); i++) + xBin.insertFirstByte(0x00); + } + ASSERT_TRUE(xBin.size() == byte_len); + + OpenABEByteString seed = pairing.hashFromBytes(xBin, length, 0x00); + cout << "seed : " << seed.toHex() << endl; + + SAFE_DELETE(rng); + + csprng1 = (OpenABERNG*)new OpenABECTR_DRBG(xBin); + csprng1->setSeed(seed); + + OpenABEByteString x1; + csprng1->getRandomBytes(&x1, length); + cout << "x1: " << x1.toHex() << endl; + cout << "x1 size: " << x1.size() << endl; + + csprng2 = (OpenABERNG*)new OpenABECTR_DRBG(xBin); + csprng2->setSeed(seed); + + OpenABEByteString x2; + csprng2->getRandomBytes(&x2, length); + cout << "x2: " << x2.toHex() << endl; + cout << "x2 size: " << x2.size() << endl; + ASSERT_TRUE(x1.size() == x2.size()); + + // XOR tests + OpenABEByteString lhs; + csprng1->getRandomBytes(&lhs, length); + + OpenABEByteString rhs; + csprng1->getRandomBytes(&rhs, length); + + ASSERT_TRUE(lhs.size() == rhs.size()); + + cout << "\nTesting XOR with random OpenABEByteString objects...\n"; + cout << "lhs: 0x" << lhs.toHex() << endl; + + cout << "rhs: 0x" << rhs.toHex() << endl; + + lhs ^= rhs; + + cout << "\nresult: 0x" << lhs.toHex() << endl; + + SAFE_DELETE(csprng1); + SAFE_DELETE(csprng2); + + // test KDF + OpenABEKDF *kdf = new OpenABEKDF; + OpenABEByteString key = kdf->DeriveKey(lhs, 256, rhs); + cout << "Derived Key: " << key.toHex() << endl; + SAFE_DELETE(kdf); + ASSERT_TRUE(key.size() == SHA256_LEN); + +} + +static size_t offset; +static int self_test_entropy_callback(void *data, uint8_t *buf, size_t len) { + const uint8_t *p = (uint8_t *)data; + memcpy(buf, p + offset, len); + offset += len; + return 0; +} + +bool CTR_DRBG_NIST_Test(int count, const uint8_t *entropy_source_nopr, + const uint8_t *nonce_pers_nopr, const uint8_t *result_nopr) { + OpenABECtrDrbgContext drbg(entropy_source_nopr, 64); + uint8_t buf[16]; + memset(buf, 0, 16); + + offset = 0; + drbg.initSeed(self_test_entropy_callback, nonce_pers_nopr, 16); + drbg.getRandomBytes(buf, 16); + drbg.reSeed(NULL, 0); + drbg.getRandomBytes(buf, 16); + + cout << "Test Vector " << to_string(count) << ": "; + if (memcmp(buf, result_nopr, 16) == 0) { + cout << "PASSED" << endl; + return true; + } else { + cerr << "FAILED: did not get expected drbg output!" << endl; + return false; + } +} + +TEST(libopenabe, CTR_DRBG) { + TEST_DESCRIPTION("Testing that CTR_DRBG is implemented correctly (via test vectors)"); +// uint8_t pt[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00, +// 0x00,0x00,0x00,0x00,0x00,0x00, +// 0x00,0x00,0x00}; +// size_t len = 16; +// uint8_t ct0[len]; + +// // test 1 +// memset(ct0, 0, len); +// uint8_t key1[] = {0xc4,0x7b,0x02,0x94,0xdb,0xbb,0xee, +// 0x0f,0xec,0x47,0x57,0xf2,0x2f, +// 0xfe,0xee,0x35,0x87,0xca,0x47, +// 0x30,0xc3,0xd3,0x3b,0x69,0x1d, +// 0xf3,0x8b,0xab,0x07,0x6b,0xc5,0x58}; +// uint8_t ct1[] = {0x46,0xf2,0xfb,0x34,0x2d,0x6f,0x0a, +// 0xb4,0x77,0x47,0x6f,0xc5,0x01, +// 0x24,0x2c,0x5f}; +// +// // by default AES-256 ECB +// AES_ECB(key1, pt, ct0, len); +// cout << "ECB Test 0: "; +// if (memcmp(ct0, ct1, len) == 0) { +// cout << "PASSED" << endl; +// } else { +// cerr << "FAILED: Ciphertexts do not match test vector!" << endl; +// } +// +// // test 2 +// memset(ct0, 0, len); +// uint8_t key2[] = {0x28,0xd4,0x6c,0xff,0xa1,0x58,0x53, +// 0x31,0x94,0x21,0x4a,0x91,0xe7, +// 0x12,0xfc,0x2b,0x45,0xb5,0x18, +// 0x07,0x66,0x75,0xaf,0xfd,0x91, +// 0x0e,0xde,0xca,0x5f,0x41,0xac,0x64}; +// uint8_t ct2[] = {0x4b,0xf3,0xb0,0xa6,0x9a,0xeb,0x66, +// 0x57,0x79,0x4f,0x29,0x01,0xb1, +// 0x44,0x0a,0xd4}; +// +// // by default AES-256 ECB +// AES_ECB(key2, pt, ct0, len); +// cout << "ECB Test 1: "; +// if (memcmp(ct0, ct2, len) == 0) { +// cout << "PASSED" << endl; +// } else { +// cerr << "FAILED: Ciphertexts do not match test vector!" << endl; +// } + + // AES-256 use df (from CTR_DRBG_nopr_false) + // Count 0 + const uint8_t entropy0_source_nopr[64] = + { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, + 0x14, 0x54, 0xde, 0xf6, 0x75, 0xfb, + 0x79, 0x58, 0xfe, 0xc7, 0xdb, 0x87, + 0x3e, 0x56, 0x89, 0xfc, 0x9d, 0x03, + 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, + 0x20, 0xf9, 0xe6, 0x5e, 0x04, 0xd8, + 0x56, 0xf3, 0xa9, 0xc4, 0x4a, 0x4c, + 0xbd, 0xc1, 0xd0, 0x08, 0x46, 0xf5, + 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, + 0x7e, 0x4e, 0x0f, 0x9d, 0x8e, 0xf4, + 0x09, 0xf9, 0x2e }; + + const uint8_t nonce0_pers_nopr[16] = + { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, + 0xf5, 0x21, 0xf1, 0x5c, 0x1c, 0x0b, + 0x66, 0x5f, 0x3f }; + + const uint8_t result0_nopr[16] = + { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, + 0x88, 0x9d, 0x90, 0x3e, 0x07, 0x7c, + 0x6f, 0x21, 0x8f }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(0, entropy0_source_nopr, nonce0_pers_nopr, result0_nopr)); + + // Count 1 + const uint8_t entropy1_source_nopr[64] = + { 0x93, 0xb7, 0x05, 0x5d, 0x78, 0x88, 0xae, + 0x23, 0x4b, 0xfb, 0x43, 0x1e, 0x37, + 0x90, 0x69, 0xd0, 0x0a, 0xe8, 0x10, + 0xfb, 0xd4, 0x8f, 0x2e, 0x06, 0xc2, + 0x04, 0xbe, 0xae, 0x3b, 0x0b, 0xfa, + 0xf0, 0x91, 0xd1, 0xd0, 0xe8, 0x53, + 0x52, 0x5e, 0xad, 0x0e, 0x7f, 0x79, + 0xab, 0xb0, 0xf0, 0xbf, 0x68, 0x06, + 0x45, 0x76, 0x33, 0x9c, 0x35, 0x85, + 0xcf, 0xd6, 0xd9, 0xb5, 0x5d, 0x4f, + 0x39, 0x27, 0x8d }; + + const uint8_t nonce1_pers_nopr[16] = + { 0x90, 0xbc, 0x3b, 0x55, 0x5b, 0x9d, 0x6b, + 0x6a, 0xeb, 0x17, 0x74, 0xa5, 0x83, + 0xf9, 0x8c, 0xad }; + + const uint8_t result1_nopr[16] = + { 0xaa, 0xf2, 0x7f, 0xc2, 0xbf, 0x64, 0xb0, + 0x32, 0x0d, 0xd3, 0x56, 0x4b, 0xb9, + 0xb0, 0x33, 0x77 }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(1, entropy1_source_nopr, nonce1_pers_nopr, result1_nopr)); + + // Count 2 + const uint8_t entropy2_source_nopr[64] = + { 0x58, 0x36, 0x4c, 0xee, 0xfa, 0xd3, 0x75, + 0x81, 0xc5, 0x18, 0xb7, 0xd4, 0x2a, + 0xc4, 0xf9, 0xaa, 0xe2, 0x2b, 0xef, + 0xd8, 0x4c, 0xbc, 0x98, 0x6c, 0x08, + 0xd1, 0xfb, 0x20, 0xd3, 0xbd, 0x24, + 0x00, 0xa8, 0x99, 0xba, 0xfd, 0x47, + 0x02, 0x78, 0xfa, 0xd8, 0xf0, 0xa5, + 0x0f, 0x84, 0x90, 0xaf, 0x29, 0xf9, + 0x38, 0x47, 0x1b, 0x40, 0x75, 0x65, + 0x4f, 0xda, 0x57, 0x7d, 0xad, 0x20, + 0xfa, 0x01, 0xca }; + + const uint8_t nonce2_pers_nopr[16] = + { 0x4a, 0x2a, 0x7d, 0xcb, 0xde, 0x58, 0xb8, + 0xb3, 0xc3, 0xf4, 0x69, 0x7b, 0xeb, + 0x67, 0xbb, 0xa2 }; + + const uint8_t result2_nopr[16] = + { 0x20, 0xc5, 0x11, 0x7a, 0x8a, 0xca, 0x72, + 0xee, 0x5a, 0xb9, 0x14, 0x68, 0xda, + 0xf4, 0x4f, 0x29 }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(2, entropy2_source_nopr, nonce2_pers_nopr, result2_nopr)); + + // Count 3 + const uint8_t entropy3_source_nopr[64] = + { 0x2f, 0x04, 0x4b, 0x86, 0x51, 0xe1, 0xc9, + 0xd9, 0x93, 0x17, 0x08, 0x4c, 0xc6, + 0xc4, 0xfa, 0x1f, 0x50, 0x2d, 0xd6, + 0x24, 0x66, 0xa5, 0x7d, 0x4b, 0x88, + 0xbc, 0x0d, 0x70, 0x3c, 0xab, 0xc5, + 0x62, 0x70, 0x82, 0x01, 0xac, 0x19, + 0xcd, 0xb5, 0xcf, 0x91, 0x8f, 0xae, + 0x29, 0xc0, 0x09, 0xfb, 0x1a, 0x2c, + 0xf4, 0x2f, 0xd7, 0x14, 0xcc, 0x9a, + 0x53, 0xca, 0x5a, 0xcb, 0x71, 0x54, + 0x82, 0x45, 0x6a }; + + const uint8_t nonce3_pers_nopr[16] = + { 0x91, 0x1f, 0xaa, 0xb1, 0x34, 0x7a, 0xe2, + 0xb3, 0x09, 0x3a, 0x60, 0x7c, 0x8b, + 0xc7, 0x7b, 0xfe }; + + const uint8_t result3_nopr[16] = + { 0xaa, 0xe0, 0xc0, 0xac, 0x97, 0xf5, 0x3d, + 0x22, 0x2b, 0x83, 0x57, 0x8a, 0x2b, + 0x3d, 0xd0, 0x5d }; + + CTR_DRBG_NIST_Test(3, entropy3_source_nopr, nonce3_pers_nopr, result3_nopr); + + // Count 4 + const uint8_t entropy4_source_nopr[64] = + { 0x77, 0xd0, 0xf0, 0xef, 0xbc, 0x7c, 0xa7, + 0x94, 0xa5, 0x1d, 0xff, 0x96, 0xe8, + 0x5b, 0x8e, 0x7d, 0xfd, 0x48, 0x75, + 0xfb, 0xfb, 0x6e, 0x55, 0x93, 0xae, + 0x17, 0x90, 0x8b, 0xfb, 0xdd, 0xc3, + 0x13, 0xe0, 0x51, 0xcb, 0x7d, 0x65, + 0x9c, 0x83, 0x81, 0x80, 0xd8, 0x34, + 0xfd, 0xd9, 0x87, 0xae, 0x3c, 0x7f, + 0x60, 0x5a, 0xaa, 0x1b, 0x3a, 0x93, + 0x65, 0x75, 0x38, 0x4b, 0x00, 0x2a, + 0x35, 0xdd, 0x98 }; + + const uint8_t nonce4_pers_nopr[16] = + { 0xf9, 0x59, 0xf1, 0xbc, 0x10, 0x0a, 0xe3, + 0x00, 0x88, 0x01, 0x7f, 0xae, 0x51, + 0x28, 0x9d, 0x8e }; + + const uint8_t result4_nopr[16] = + { 0x5d, 0x80, 0xbc, 0x3f, 0xff, 0xa4, 0x2b, + 0x89, 0xcc, 0xb3, 0x90, 0xe8, 0x44, + 0x7e, 0x33, 0xe5 }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(4, entropy4_source_nopr, nonce4_pers_nopr, result4_nopr)); + + // Count 5 + const uint8_t entropy5_source_nopr[64] = + { 0x6b, 0xb1, 0x4d, 0xc3, 0x4f, 0x66, 0x97, + 0x59, 0xf8, 0xfa, 0x54, 0x53, 0xc4, + 0x89, 0x9e, 0xb5, 0xac, 0x4e, 0x33, + 0xa6, 0x9e, 0x35, 0xe8, 0x9b, 0x19, + 0xa4, 0x6d, 0xbd, 0x08, 0x88, 0x42, + 0x9d, 0x13, 0x67, 0xf7, 0xf3, 0x19, + 0x1e, 0x91, 0x1b, 0x3b, 0x35, 0x5b, + 0x6e, 0x3b, 0x24, 0x26, 0xe2, 0x42, + 0xef, 0x41, 0x40, 0xdd, 0xcc, 0x96, + 0x76, 0x37, 0x11, 0x01, 0x20, 0x96, + 0x62, 0xf2, 0x53 }; + + const uint8_t nonce5_pers_nopr[16] = + { 0x45, 0xa8, 0xbb, 0x33, 0x06, 0x27, 0x83, + 0xee, 0xde, 0x09, 0xb0, 0x5a, 0x35, + 0xbd, 0x44, 0xdd }; + + const uint8_t result5_nopr[16] = + { 0x0d, 0xfa, 0x99, 0x55, 0xa1, 0x3a, 0x9c, + 0x57, 0xa3, 0x54, 0x6a, 0x04, 0x10, + 0x8b, 0x8e, 0x9e }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(5, entropy5_source_nopr, nonce5_pers_nopr, result5_nopr)); + + // Count 6 + const uint8_t entropy6_source_nopr[64] = + { 0xb3, 0xd0, 0x1b, 0xcb, 0x1e, 0xc7, 0x47, + 0xfd, 0xb7, 0xfe, 0xb5, 0xa7, 0xde, + 0x92, 0x80, 0x7a, 0xfa, 0x43, 0x38, + 0xab, 0xa1, 0xc8, 0x1c, 0xe1, 0xeb, + 0x50, 0x95, 0x5e, 0x12, 0x5a, 0xf4, + 0x6b, 0x19, 0xae, 0xd8, 0x91, 0x36, + 0x6e, 0xc0, 0xf7, 0x0b, 0x07, 0x90, + 0x37, 0xa5, 0xae, 0xb3, 0x3f, 0x07, + 0xf4, 0xc8, 0x94, 0xfd, 0xcd, 0xa3, + 0xff, 0x41, 0xe2, 0x86, 0x7a, 0xce, + 0x1a, 0xa0, 0x5c }; + + const uint8_t nonce6_pers_nopr[16] = + { 0x0a, 0xda, 0x12, 0x9f, 0x99, 0x48, 0x07, + 0x3d, 0x62, 0x8c, 0x11, 0x27, 0x4c, + 0xec, 0x3f, 0x69 }; + + const uint8_t result6_nopr[16] = + { 0xf3, 0x47, 0x10, 0xc9, 0xeb, 0xf9, 0xd5, + 0xaa, 0xa5, 0xf7, 0x97, 0xfd, 0x85, + 0xa1, 0xc4, 0x13 }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(6, entropy6_source_nopr, nonce6_pers_nopr, result6_nopr)); + + // Count 7 + const uint8_t entropy7_source_nopr[64] = + { 0x98, 0x48, 0x2e, 0x58, 0xe4, 0x4b, 0x8e, + 0x4a, 0x6b, 0x09, 0xfa, 0x02, 0xc0, + 0x5f, 0xcc, 0x49, 0x1d, 0xa0, 0x3a, + 0x47, 0x9a, 0x7f, 0xad, 0x13, 0xa8, + 0x3b, 0x60, 0x80, 0xd3, 0x0b, 0x3b, + 0x25, 0x5e, 0x01, 0xa4, 0x35, 0x68, + 0xa9, 0xd6, 0xdd, 0x5c, 0xec, 0xf9, + 0x9b, 0x0c, 0xe9, 0xfd, 0x59, 0x4d, + 0x69, 0xef, 0xf8, 0xfa, 0x88, 0x15, + 0x9b, 0x2d, 0xa2, 0x4c, 0x33, 0xba, + 0x81, 0xa1, 0x4d }; + + const uint8_t nonce7_pers_nopr[16] = + { 0x05, 0x2a, 0x5a, 0xd4, 0xcd, 0x38, 0xde, + 0x90, 0xe5, 0xd3, 0xc2, 0xfc, 0x43, + 0x0f, 0xa5, 0x1e }; + + const uint8_t result7_nopr[16] = + { 0x3f, 0x55, 0x14, 0x4e, 0xec, 0x26, 0x3a, + 0xed, 0x50, 0xf9, 0xc9, 0xa6, 0x41, + 0x53, 0x8e, 0x55 }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(7, entropy7_source_nopr, nonce7_pers_nopr, result7_nopr)); + + // Count 8 + const uint8_t entropy8_source_nopr[64] = + { 0x62, 0x38, 0xd4, 0x48, 0x01, 0x5e, 0x86, + 0xaa, 0x16, 0xaf, 0x62, 0xcd, 0xc2, + 0x87, 0xf1, 0xc1, 0x7b, 0x78, 0xa7, + 0x98, 0x09, 0xfa, 0x00, 0xb8, 0xc6, + 0x55, 0xe0, 0x67, 0x15, 0xcd, 0x2b, + 0x93, 0x5b, 0xf4, 0xdf, 0x96, 0x6e, + 0x3e, 0xc1, 0xf1, 0x4b, 0x28, 0xcc, + 0x1d, 0x08, 0x0f, 0x88, 0x2a, 0x72, + 0x15, 0xe2, 0x58, 0x43, 0x0c, 0x91, + 0xa4, 0xa0, 0xa2, 0xaa, 0x98, 0xd7, + 0xcd, 0x80, 0x53 }; + + const uint8_t nonce8_pers_nopr[16] = + { 0x00, 0x4c, 0xd2, 0xf2, 0x8f, 0x08, 0x3d, + 0x1c, 0xee, 0x68, 0x97, 0x5d, 0x5c, + 0xbb, 0xbe, 0x4f }; + + const uint8_t result8_nopr[16] = + { 0xb1, 0x37, 0x11, 0x9d, 0xbb, 0xd9, 0xd7, + 0x52, 0xa8, 0xdf, 0xce, 0xec, 0x05, + 0xb8, 0x84, 0xb6 }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(8, entropy8_source_nopr, nonce8_pers_nopr, result8_nopr)); + + // Count 9 + const uint8_t entropy9_source_nopr[64] = + { 0x50, 0xd3, 0xc4, 0xec, 0xb1, 0xd6, 0xe9, + 0x5a, 0xeb, 0xb8, 0x7e, 0x9e, 0x8a, + 0x5c, 0x86, 0x9c, 0x11, 0xfb, 0x94, + 0x5d, 0xfa, 0xd2, 0xe4, 0x5e, 0xe9, + 0x0f, 0xb6, 0x19, 0x31, 0xfc, 0xed, + 0xd4, 0x7d, 0x60, 0x05, 0xaa, 0x5d, + 0xf2, 0x4b, 0xb9, 0xef, 0xc1, 0x1b, + 0xbb, 0x96, 0xbb, 0x21, 0x06, 0x5d, + 0x44, 0xe2, 0x53, 0x2a, 0x1e, 0x17, + 0x49, 0x3f, 0x97, 0x4a, 0x4b, 0xf8, + 0xf8, 0xb5, 0x80 }; + + const uint8_t nonce9_pers_nopr[16] = + { 0xf9, 0x85, 0xb3, 0xea, 0x2d, 0x8b, 0x15, + 0xdb, 0x26, 0xa7, 0x18, 0x95, 0xa2, + 0xff, 0x57, 0xcd }; + + const uint8_t result9_nopr[16] = + { 0xeb, 0x41, 0x96, 0x28, 0xfb, 0xc4, 0x41, + 0xae, 0x6a, 0x03, 0xe2, 0x6a, 0xee, + 0xcb, 0x34, 0xa6 }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(9, entropy9_source_nopr, nonce9_pers_nopr, result9_nopr)); + + // Count 10 + const uint8_t entropy10_source_nopr[64] = + { 0xd2, 0x7c, 0xbe, 0xac, 0x39, 0xa6, 0xc8, + 0x99, 0x93, 0x81, 0x97, 0xf0, 0xe6, + 0x1d, 0xc9, 0x0b, 0xe3, 0xa3, 0xa2, + 0x0f, 0xa5, 0xc5, 0xe1, 0xf7, 0xa7, + 0x6a, 0xdd, 0xe0, 0x05, 0x98, 0xe5, + 0x95, 0x55, 0xc1, 0xe9, 0xfd, 0x10, + 0x2d, 0x4b, 0x52, 0xe1, 0xae, 0x9f, + 0xb0, 0x04, 0xbe, 0x89, 0x44, 0xba, + 0xd8, 0x5c, 0x58, 0xe3, 0x41, 0xd1, + 0xbe, 0xe0, 0x14, 0x05, 0x7d, 0xa9, + 0x8e, 0xb3, 0xbc }; + + const uint8_t nonce10_pers_nopr[16] = + { 0x10, 0x0f, 0x19, 0x69, 0x91, 0xb6, 0xe9, + 0x6f, 0x8b, 0x96, 0xa3, 0x45, 0x6f, + 0x6e, 0x2b, 0xaf }; + + const uint8_t result10_nopr[16] = + { 0xe3, 0xe0, 0x9d, 0x0e, 0xd8, 0x27, 0xe4, + 0xf2, 0x4a, 0x20, 0x55, 0x3f, 0xd1, + 0x08, 0x7c, 0x9d }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(10, entropy10_source_nopr, nonce10_pers_nopr, result10_nopr)); + + // Count 11 + const uint8_t entropy11_source_nopr[64] = + { 0x16, 0xf9, 0xf5, 0x35, 0x4d, 0x62, 0x4c, + 0x5a, 0xb1, 0xf8, 0x2c, 0x75, 0x0e, + 0x05, 0xf5, 0x1f, 0x2a, 0x2e, 0xec, + 0xa7, 0xe5, 0xb7, 0x74, 0xfd, 0x96, + 0x14, 0x8d, 0xdb, 0xa3, 0xb3, 0x8d, + 0x34, 0xba, 0x7f, 0x14, 0x72, 0x56, + 0x7c, 0x52, 0x08, 0x72, 0x52, 0x48, + 0x0d, 0x30, 0x5a, 0xd1, 0xc6, 0x9e, + 0x4a, 0xac, 0x84, 0x72, 0xa1, 0x54, + 0xae, 0x03, 0x51, 0x1d, 0x0e, 0x8a, + 0xac, 0x90, 0x5a }; + + const uint8_t nonce11_pers_nopr[16] = + { 0x88, 0xf5, 0x5d, 0x9b, 0xa8, 0xfe, 0xf7, + 0x82, 0x84, 0x83, 0x29, 0x83, 0x21, + 0x13, 0x3f, 0xec }; + + const uint8_t result11_nopr[16] = + { 0x07, 0xcd, 0x82, 0x10, 0x12, 0xef, 0x03, + 0xf1, 0x6d, 0x85, 0x10, 0xc2, 0x3b, + 0x86, 0xba, 0xf3 }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(11, entropy11_source_nopr, nonce11_pers_nopr, result11_nopr)); + + // Count 12 + const uint8_t entropy12_source_nopr[64] = + { 0x70, 0xaf, 0xbc, 0x83, 0xbf, 0x9f, 0xf0, + 0x95, 0x35, 0xd6, 0xf0, 0xdd, 0xc5, + 0x12, 0x78, 0xad, 0x79, 0x09, 0xf1, + 0x1e, 0x6f, 0x19, 0x8b, 0x59, 0x13, + 0x2c, 0x9e, 0x26, 0x9d, 0xeb, 0x41, + 0xba, 0x90, 0x1c, 0x62, 0x34, 0x62, + 0x83, 0xe2, 0x93, 0xb8, 0x71, 0x4f, + 0xd3, 0x24, 0x1a, 0xe8, 0x70, 0xf9, + 0x74, 0xff, 0x33, 0xc3, 0x5f, 0x9a, + 0xff, 0x05, 0x14, 0x4b, 0xe0, 0x39, + 0xd2, 0x4e, 0x50 }; + + const uint8_t nonce12_pers_nopr[16] = + { 0x12, 0x64, 0x79, 0xab, 0xd7, 0x0b, 0x25, + 0xac, 0xd8, 0x91, 0xe1, 0xc4, 0xc9, + 0x20, 0x44, 0xf9 }; + + const uint8_t result12_nopr[16] = + { 0x0f, 0x90, 0xdf, 0x35, 0x07, 0x41, 0xd8, + 0x85, 0x52, 0xa5, 0xb0, 0x3b, 0x64, + 0x88, 0xe9, 0xfb }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(12, entropy12_source_nopr, nonce12_pers_nopr, result12_nopr)); + + // Count 13 + const uint8_t entropy13_source_nopr[64] = + { 0x5e, 0x5a, 0x9e, 0x1e, 0x3c, 0xb8, 0x07, + 0x38, 0xc2, 0x38, 0x46, 0x4e, 0xde, + 0x1b, 0x6b, 0x6a, 0x32, 0x12, 0x61, + 0xa3, 0xb0, 0x06, 0xa9, 0x8a, 0x79, + 0x26, 0x5a, 0xd1, 0xf6, 0x35, 0x57, + 0x3b, 0xba, 0x48, 0xdc, 0xcf, 0x17, + 0xb1, 0x2f, 0x68, 0x68, 0x47, 0x82, + 0x52, 0xf5, 0x56, 0xb7, 0x7c, 0x3e, + 0xc5, 0x7a, 0x3b, 0xf6, 0xbb, 0x65, + 0x99, 0x42, 0x94, 0x53, 0xdb, 0x2d, + 0x05, 0x03, 0x52 }; + + const uint8_t nonce13_pers_nopr[16] = + { 0xa4, 0x5f, 0x2f, 0xca, 0x55, 0x30, 0x89, + 0xfe, 0x04, 0xe7, 0x83, 0x20, 0x59, + 0xdc, 0x79, 0x76 }; + + const uint8_t result13_nopr[16] = + { 0x6e, 0xb8, 0x5a, 0xe2, 0x40, 0x6c, 0x43, + 0x81, 0x4b, 0x68, 0x7f, 0x74, 0xf4, + 0xe9, 0x42, 0xbc }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(13, entropy13_source_nopr, nonce13_pers_nopr, result13_nopr)); + + // Count 14 + const uint8_t entropy14_source_nopr[64] = + { 0x31, 0xcf, 0xe6, 0x0e, 0x5e, 0xd1, 0x2f, + 0xf3, 0x7d, 0x7f, 0x22, 0x70, 0x96, + 0x3d, 0xef, 0x59, 0x87, 0x26, 0x32, + 0x0c, 0x02, 0xb9, 0x10, 0xb5, 0xc6, + 0xc7, 0x95, 0xe2, 0x20, 0x9b, 0x4b, + 0x4a, 0x95, 0x86, 0x6c, 0x64, 0xcb, + 0x09, 0x7a, 0xf1, 0xd6, 0x40, 0x4d, + 0x1e, 0x61, 0x82, 0xed, 0xf9, 0x60, + 0x0e, 0x18, 0x55, 0x34, 0x53, 0x75, + 0xb2, 0x01, 0x80, 0x1d, 0x6f, 0x4c, + 0x4e, 0x4b, 0x32 }; + + const uint8_t nonce14_pers_nopr[16] = + { 0x52, 0xdb, 0xb4, 0x32, 0x41, 0x00, 0x24, + 0x15, 0x96, 0x6e, 0xae, 0xc2, 0x61, + 0x5a, 0xba, 0x27 }; + + const uint8_t result14_nopr[16] = + { 0x2a, 0x27, 0x0f, 0x5e, 0xf8, 0x15, 0x66, + 0x5d, 0xdd, 0x07, 0x52, 0x7c, 0x48, + 0x71, 0x9a, 0xb1 }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(14, entropy14_source_nopr, nonce14_pers_nopr, result14_nopr)); + + // Count 15 + const uint8_t entropyA_source_nopr[64] = + { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14, + 0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe, + 0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d, + 0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20, + 0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9, + 0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46, + 0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e, + 0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e }; + + const uint8_t nonceA_pers_nopr[16] = + { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5, + 0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f }; + + const uint8_t resultA_nopr[16] = + { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88, + 0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f }; + + ASSERT_TRUE(CTR_DRBG_NIST_Test(15, entropyA_source_nopr, nonceA_pers_nopr, resultA_nopr)); +} + +TEST(libopenabe, SymKeyOperations) { + TEST_DESCRIPTION("Testing OpenABE keystore handling of symmetric keys is correct"); + shared_ptr symkey1(new OpenABESymKey); + shared_ptr symkey2 = nullptr; + OpenABERNG *rng = nullptr; + OpenABEKeystore *ks = nullptr; + + ks = new OpenABEKeystore; + rng = new OpenABERNG; + OpenABEByteString uid; + rng->getRandomBytes(&uid, UID_LEN); + // generate a random session key + // symkey1 = new OpenABESymKey; // (OpenABE_SCHEME_AES_GCM, "sessionKey1"); + symkey1->generateSymmetricKey(DEFAULT_SYM_KEY_BYTES); + cout << "SymKey1: " << symkey1->toString() << endl; + cout << "Length: " << symkey1->getLength() << endl; + + ASSERT_TRUE(OpenABE_storeSymmetricKey(ks, "sessionKey1", symkey1) == OpenABE_NOERROR); + + OpenABEByteString sessionKeyExported; + ASSERT_TRUE(OpenABE_exportKey(ks, "sessionKey1", &sessionKeyExported) == OpenABE_NOERROR); + + // cout << "Exported key: " << sessionKeyExported.toHex() << endl; + ASSERT_TRUE(OpenABE_deleteSymmetricKey(ks, "sessionKey1") == OpenABE_NOERROR); + + // attempt to load recently exported key back into keystore + ASSERT_TRUE(OpenABE_loadSymmetricKey(ks, "sessionKey1", &sessionKeyExported) == OpenABE_NOERROR); + + // now retrieve the symmetric key and print contents + symkey2 = OpenABE_getSymmetricKey(ks, "sessionKey1"); + ASSERT_FALSE(symkey2 == nullptr); + + OpenABEByteString bytes; + ASSERT_TRUE(ks->exportKeyToBytes("missingSessionKey", bytes) == OpenABE_ERROR_INVALID_INPUT); + + sessionKeyExported.insertFirstByte(0xAF); // add a bad header len (4 bytes) + sessionKeyExported.insertFirstByte(0xBF); + sessionKeyExported.insertFirstByte(0xCF); + sessionKeyExported.insertFirstByte(0xDF); + ASSERT_ANY_THROW(ks->parseKeyHeader("sessionKey2", bytes, sessionKeyExported)); + + cout << "SymKey2: " << symkey2->toString() << endl; + cout << "Length: " << symkey2->getLength() << endl; + ASSERT_TRUE(symkey1->getLength() == symkey2->getLength()); + ASSERT_TRUE(*symkey1 == *symkey2); + + SAFE_DELETE(rng); + SAFE_DELETE(ks); +} + +TEST(libopenabe, SymKeyAuthEnc) { + TEST_DESCRIPTION("Testing that AES GCM implementation is correct"); + shared_ptr symkey(new OpenABESymKey); + string plaintext1, plaintext2; + OpenABEByteString sym_key_bytes, iv, ct, tag; + + /* generate a random secret key of a certain size */ + symkey->generateSymmetricKey(DEFAULT_SYM_KEY_BYTES); + cout << "SymmKey: " << symkey->toString() << endl; + cout << "Length: " << symkey->getLength() << endl; + + symkey->exportKeyToBytes(sym_key_bytes); + unique_ptr authEnc(new OpenABESymKeyAuthEnc(DEFAULT_AES_SEC_LEVEL, sym_key_bytes)); + + plaintext1 = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x39\x38\x37\x36\x35"; + /* optionally set additional authentication data */ + authEnc->setAddAuthData(NULL, 0); + /* now we can encrypt */ + authEnc->encrypt(plaintext1, &iv, &ct, &tag); + + cout << "Ciphertext =>\n"; + // OpenABEByteString *iv = ct->getIV(); + // OpenABEByteString *ciphertext = ct->getCiphertext(); + // OpenABEByteString *tag = ct->getTag(); + + cout << "IV: " << iv.toHex() << endl; + cout << "CT: " << ct.toHex() << endl; + cout << "TG: " << tag.toHex() << endl; + /* decrypt the ciphertext and check the authentication tag */ + ASSERT_TRUE(authEnc->decrypt(plaintext2, &iv, &ct, &tag)); +} + +TEST(libopenabe, SymKeyAuthEnc_Stream) { + TEST_DESCRIPTION("Testing that SK streaming encryption is correct"); + shared_ptr symkey(new OpenABESymKey); + OpenABEByteString plaintext, ciphertext, iv, tag; + OpenABEByteString ptBlock1, ptBlock2, ctBlock1, ctBlock2; + + /* generate a random secret key of a certain size */ + symkey->generateSymmetricKey(DEFAULT_SYM_KEY_BYTES); + cout << "SymmKey: " << symkey->toString() << endl; + cout << "Length: " << symkey->getLength() << endl; + + unique_ptr authEncStream(new OpenABESymKeyAuthEncStream(DEFAULT_AES_SEC_LEVEL, symkey)); + + ptBlock1 = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x39\x38\x37\x36\x35"; + ptBlock2 = "\xA1\xB2\xC3\xD4\xE5\xF6\xA7\xB8\xC9\xD0\xE1\xF2\xA3\xB4\xC5\xD6"; + + ASSERT_TRUE(authEncStream->encryptInit(&iv) == OpenABE_NOERROR); + // set 0s for the AAD + authEncStream->initAddAuthData(NULL, 0); + ASSERT_TRUE(authEncStream->setAddAuthData() == OpenABE_NOERROR); + + // perform update 1 + ASSERT_TRUE(authEncStream->encryptUpdate(&ptBlock1, &ciphertext) == OpenABE_NOERROR); + + // perform update 2 + ASSERT_TRUE(authEncStream->encryptUpdate(&ptBlock2, &ciphertext) == OpenABE_NOERROR); + + ASSERT_TRUE(authEncStream->encryptFinalize(&ciphertext, &tag) == OpenABE_NOERROR); + + cout << "Final ciphertext: " << ciphertext.toHex() << endl; + + // split ciphertext into blocks + ctBlock1 = ciphertext.getSubset(0, ptBlock1.size()); + ctBlock2 = ciphertext.getSubset(ptBlock1.size(), ptBlock2.size()); + cout << "ct1 : " << ctBlock1.toHex() << endl; + cout << "ct2 : " << ctBlock2.toHex() << endl; + + // now try to decrypt the ciphertexts + ASSERT_TRUE(authEncStream->decryptInit(&iv, &tag) == OpenABE_NOERROR); + + // set 0s for the AAD + authEncStream->initAddAuthData(NULL, 0); + ASSERT_TRUE(authEncStream->setAddAuthData() == OpenABE_NOERROR); + + // perform decrypt updates in order (note: order of blocks must be managed by the user) + ASSERT_TRUE(authEncStream->decryptUpdate(&ctBlock1, &plaintext) == OpenABE_NOERROR); + + ASSERT_TRUE(authEncStream->decryptUpdate(&ctBlock2, &plaintext) == OpenABE_NOERROR); + + ASSERT_TRUE(authEncStream->decryptFinalize(&plaintext) == OpenABE_NOERROR); + + cout << "Original plaintext: " << ptBlock1.toHex() << ptBlock2.toHex() << endl; + cout << "Recovered plaintext: " << plaintext.toHex() << endl; + ASSERT_TRUE(plaintext == (ptBlock1 + ptBlock2)); + + // FAILURE TEST: now try to decrypt the ciphertexts (out of order) + plaintext.clear(); + ASSERT_TRUE(authEncStream->decryptInit(&iv, &tag) == OpenABE_NOERROR); + + // set 0s for the AAD + authEncStream->initAddAuthData(NULL, 0); + ASSERT_TRUE(authEncStream->setAddAuthData() == OpenABE_NOERROR); + + // perform decrypt updates in order (note: order of blocks must be managed by the user) + ASSERT_TRUE(authEncStream->decryptUpdate(&ctBlock2, &plaintext) == OpenABE_NOERROR); + + ASSERT_TRUE(authEncStream->decryptUpdate(&ctBlock1, &plaintext) == OpenABE_NOERROR); + + OpenABE_ERROR err_code = authEncStream->decryptFinalize(&plaintext); + ASSERT_FALSE(err_code == OpenABE_NOERROR); + + cout << "Recovered plaintext: " << plaintext.toHex() << endl; +} + +TEST(libopenabe, SKSchemeStreamContext) { + TEST_DESCRIPTION("Testing that streaming SK scheme context is correct"); + OpenABEByteString plaintext, ciphertext, iv, tag; + OpenABEByteString ptBlock1, ptBlock2, ctBlock1, ctBlock2; + + unique_ptr schemeStreamSKE(new OpenABEContextSchemeStreamSKE); + + ASSERT_TRUE(schemeStreamSKE->keygen("key1") == OpenABE_NOERROR); + + ASSERT_TRUE(schemeStreamSKE->keygen("key2") == OpenABE_NOERROR); + + ptBlock1 = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x39\x38\x37\x36\x35"; + ptBlock2 = "\xA1\xB2\xC3\xD4\xE5\xF6\xA7\xB8\xC9\xD0\xE1\xF2\xA3\xB4\xC5\xD6"; + + ASSERT_TRUE(schemeStreamSKE->encryptInit("key1", &iv) == OpenABE_NOERROR); + + // perform update 1 + ASSERT_TRUE(schemeStreamSKE->encryptUpdate(&ptBlock1, &ciphertext) == OpenABE_NOERROR); + // perform update 2 + ASSERT_TRUE(schemeStreamSKE->encryptUpdate(&ptBlock2, &ciphertext) == OpenABE_NOERROR); + ASSERT_TRUE(schemeStreamSKE->encryptFinalize(&ciphertext, &tag) == OpenABE_NOERROR); + + cout << "Final ciphertext: " << ciphertext.toHex() << endl; + + // split ciphertext into blocks + ctBlock1 = ciphertext.getSubset(0, ptBlock1.size()); + ctBlock2 = ciphertext.getSubset(ptBlock1.size(), ptBlock2.size()); + cout << "ct1 : " << ctBlock1.toHex() << endl; + cout << "ct2 : " << ctBlock2.toHex() << endl; + + // now try to decrypt the ciphertexts + ASSERT_TRUE(schemeStreamSKE->decryptInit("key1", &iv, &tag) == OpenABE_NOERROR); + + // perform decrypt updates in order (note: order of blocks must be managed by the user) + ASSERT_TRUE(schemeStreamSKE->decryptUpdate(&ctBlock1, &plaintext) == OpenABE_NOERROR); + + ASSERT_TRUE(schemeStreamSKE->decryptUpdate(&ctBlock2, &plaintext) == OpenABE_NOERROR); + + ASSERT_TRUE(schemeStreamSKE->decryptFinalize(&plaintext) == OpenABE_NOERROR); + + cout << "Original plaintext: " << ptBlock1.toHex() << ptBlock2.toHex() << endl; + cout << "Recovered plaintext: " << plaintext.toHex() << endl; + ASSERT_TRUE(plaintext == (ptBlock1 + ptBlock2)); + +// plaintext.clear(); +// ASSERT_TRUE(schemeStreamSKE->decryptInit("key2", &iv, &tag) == OpenABE_NOERROR); +// +//// // set 0s for the AAD +//// schemeStreamSKE->initAddAuthData(NULL, 0); +//// ASSERT_TRUE(schemeStreamSKE->setAddAuthData() == OpenABE_NOERROR); +// +// // perform decrypt updates in order (note: order of blocks must be managed by the user) +// ASSERT_TRUE(schemeStreamSKE->decryptUpdate(&ctBlock2, &plaintext) == OpenABE_NOERROR); +// +// ASSERT_TRUE(schemeStreamSKE->decryptUpdate(&ctBlock1, &plaintext) == OpenABE_NOERROR); +// +// OpenABE_ERROR err_code = schemeStreamSKE->decryptFinalize(&plaintext); +// ASSERT_TRUE(err_code == OpenABE_NOERROR); +// +// cout << "Recovered plaintext: " << plaintext.toHex() << endl; +} + +TEST(libopenabe, SymKeyHandleContext) { + TEST_DESCRIPTION("Testing that Symmetric Key handle works correctly"); + OpenABEByteString key; + string raw_key, key_data, ciphertext, plaintext1, plaintext2; + + cout << "Generate sym key..." << endl; + generateSymmetricKey(raw_key, DEFAULT_SYM_KEY_BYTES); + key += raw_key; + cout << "key: " << key.toLowerHex() << endl; + + cout << "Create SymKey handle" << endl; + std::unique_ptr keyHandle(new OpenABESymKeyHandleImpl(raw_key)); + + // test key exporting + keyHandle->exportKey(key_data); + cout << "key_data size: " << key_data.size() << endl; + // test encryption + plaintext1 = "this is plaintext!"; + keyHandle->encrypt(ciphertext, plaintext1); + + // test decryption + keyHandle->decrypt(plaintext2, ciphertext); + + ASSERT_TRUE(plaintext1.compare(plaintext2) == 0); + + // keyHandle->cleanup(); + cout << "Successful Decryption!" << endl; +} + +TEST(libopenabe, PKOPDHKemContext) { + TEST_DESCRIPTION("Testing that PK One-pass DH KEM is correct"); + OpenABEContextPKE *kemContext = NULL; + unique_ptr rng(new OpenABERNG); + shared_ptr senderPK = nullptr; + shared_ptr symkey(new OpenABESymKey), newkey(new OpenABESymKey); + OpenABECiphertext *ciphertext = NULL; + OpenABEByteString senderID; + + // create new KEM context for PKE ECC MQV scheme + kemContext = OpenABE_createContextPKE(&rng, OpenABE_SCHEME_PK_OPDH); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(kemContext->generateParams("NIST_P256") == OpenABE_NOERROR); + + // Compute party A's static public and private key + ASSERT_TRUE(kemContext->generateDecryptionKey("ID_A", "public_A", "private_A") == OpenABE_NOERROR); + + // Compute party B's static public and private key + ASSERT_TRUE(kemContext->generateDecryptionKey("ID_B", "public_B", "private_B") == OpenABE_NOERROR); + + // get PK of sender (assumes it has already been loaded) + senderPK = kemContext->getKeystore()->getPublicKey("public_A"); + senderID = senderPK->getUID(); + + // Encrypt a test key using the KEM mode + // symkey = new OpenABESymKey; + ciphertext = new OpenABECiphertext; + ASSERT_TRUE(kemContext->encryptKEM(NULL, "public_B", &senderID, DEFAULT_SYM_KEY_BITS, symkey, ciphertext) == OpenABE_NOERROR); + + string symKeyStr = symkey->toString(); + cout << "Orig symmetric key: " << symKeyStr << endl; + + // newkey = new OpenABESymKey; + ASSERT_TRUE(kemContext->decryptKEM("public_A", "private_B", ciphertext, DEFAULT_SYM_KEY_BITS, newkey) == OpenABE_NOERROR); + + string newKeyStr = newkey->toString(); + cout << "Recvd symmetric key: " << newKeyStr << endl; + ASSERT_TRUE(symKeyStr.compare(newKeyStr) == 0); + + SAFE_DELETE(ciphertext); + SAFE_DELETE(kemContext); +} + +TEST(libopenabe, PKSchemeContext) { + TEST_DESCRIPTION("Testing that PK scheme context works correctly"); + OpenABERNG rng; + OpenABECiphertext ciphertext; + + // create new KEM context for PKE ECC MQV scheme + unique_ptr schemeContext = OpenABE_createContextPKESchemeCCA(OpenABE_SCHEME_PK_OPDH); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(schemeContext->generateParams("NIST_P256") == OpenABE_NOERROR); + + // Compute party A's static public and private key + ASSERT_TRUE(schemeContext->keygen("ID_A", "public_A", "private_A") == OpenABE_NOERROR); + + // Compute party B's static public and private key + ASSERT_TRUE(schemeContext->keygen("ID_B", "public_B", "private_B") == OpenABE_NOERROR); + + // Test load / delete (perhaps, we should provide convenience functions for this) + OpenABEByteString publicKeyA, publicKeyA_bad, privateKeyB; + + ASSERT_TRUE(schemeContext->exportKey("public_A", publicKeyA) == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->exportKey("private_B", privateKeyB) == OpenABE_NOERROR); + + publicKeyA_bad = publicKeyA; + // swap two positions in header + publicKeyA_bad[5] = publicKeyA_bad[6]; // tweak header a little bit + publicKeyA_bad[6] = publicKeyA[5]; + + // delete them + ASSERT_TRUE(schemeContext->deleteKey("public_A") == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->deleteKey("private_B") == OpenABE_NOERROR); + + // attempt to load a key that was just deleted + ASSERT_TRUE(schemeContext->loadPublicKey("public_A", publicKeyA_bad) != OpenABE_NOERROR); + + // attempt to load a key that was just deleted + ASSERT_TRUE(schemeContext->loadPublicKey("public_A", publicKeyA) == OpenABE_NOERROR); + + // attempt to load a key that was just deleted + ASSERT_TRUE(schemeContext->loadPrivateKey("private_B", privateKeyB) == OpenABE_NOERROR); + + OpenABEByteString plaintext1, plaintext2; + // plaintext1 = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x40\x41\x42\x43\x44\x45\x46"; + rng.getRandomBytes(&plaintext1, 128); + const string pt1 = plaintext1.toString(); + ASSERT_TRUE(schemeContext->encrypt(NULL, "public_B", "public_A", pt1, &ciphertext) == OpenABE_NOERROR); + + cout << "Orig m: " << plaintext1.toHex() << endl; + + string pt2; + ASSERT_TRUE(schemeContext->decrypt("public_A", "private_B", pt2, &ciphertext) == OpenABE_NOERROR); + + plaintext2 = pt2; + cout << "Recv m: " << plaintext2.toHex() << endl; + + ASSERT_TRUE(plaintext1 == plaintext2); +} + +TEST(libopenabe, PKSIGLowLevelContext) { + TEST_DESCRIPTION("Testing that PKSIG low level context is correct"); + OpenABEByteString message, signature; + + unique_ptr pksig(new OpenABEContextPKSIG); + + ASSERT_TRUE(pksig->generateParams("NIST_P256") == OpenABE_NOERROR); + + ASSERT_TRUE(pksig->keygen("public_key", "private_key") == OpenABE_NOERROR); + + // get the secret key + shared_ptr sk = static_pointer_cast(pksig->getKeystore()->getSecretKey("private_key")); + ASSERT_TRUE(sk != nullptr); + + // get the public key + shared_ptr pk = static_pointer_cast(pksig->getKeystore()->getPublicKey("public_key")); + ASSERT_TRUE(pk != nullptr); + + message = "hello world"; + ASSERT_TRUE(pksig->sign(sk.get(), &message, &signature) == OpenABE_NOERROR); + + cout << "Signature: " << signature.toLowerHex() << endl; + cout << "Sig Len: " << signature.size() << endl; + + ASSERT_TRUE(pksig->verify(pk.get(), &message, &signature) == OpenABE_NOERROR); +} + + +TEST(libopenabe, PKSIGSchemeContext) { + TEST_DESCRIPTION("Testing that PKSIG scheme context (wrapper around PKSIG low-level) works correctly"); + unique_ptr schemeContext = nullptr; + OpenABEByteString message, signature; + OpenABEByteString outputPK, outputSK; + + schemeContext = OpenABE_createContextPKSIGScheme(); + + ASSERT_TRUE(schemeContext->generateParams("NIST_P256") == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->keygen("public_key", "private_key") == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->exportKey("public_key", outputPK) == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->exportKey("private_key", outputSK) == OpenABE_NOERROR); + + cout << "outputPK:\n" << outputPK.toString() << endl; + cout << "outputSK:\n" << outputSK.toString() << endl; + + ASSERT_TRUE(schemeContext->deleteKey("public_key") == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->deleteKey("private_key") == OpenABE_NOERROR); + + // attempt to load a key that was just deleted + ASSERT_TRUE(schemeContext->loadPublicKey("public_key", outputPK) == OpenABE_NOERROR); + + // attempt to load a key that was just deleted + ASSERT_TRUE(schemeContext->loadPrivateKey("private_key", outputSK) == OpenABE_NOERROR); + + message = "hello world"; + // sign a message using the private key + ASSERT_TRUE(schemeContext->sign("private_key", &message, &signature) == OpenABE_NOERROR); + + cout << "Signature: " << signature.toLowerHex() << endl; + cout << "Sig Len: " << signature.size() << endl; + + ASSERT_TRUE(schemeContext->verify("public_key", &message, &signature) == OpenABE_NOERROR); +} + +TEST(libopenabe, PasswordHashingTests) { + TEST_DESCRIPTION("Testing that password hashing utility is correct"); + string hash, hash1; + string password1, password2; + + password1 = "password"; + password2 = "passw0rd"; + generateHash(hash, password1); + + cout << "Returned hash: " << hash << endl; + + // verify hash/password1 combo (should pass) + ASSERT_TRUE(checkPassword(hash, password1)); + + // verify hash/password2 combo (should fail) + ASSERT_FALSE(checkPassword(hash, password2)); + + string fake_hash = "abcdefoobar123456789123xyz"; + ASSERT_THROW(checkPassword(fake_hash, password1), OpenABE_ERROR); +} + +TEST(libopenabe, PasswodHashingWithInvalidInputs) { + TEST_DESCRIPTION("Testing that password hashing utility handles very long inputs"); + string hash1, hash2, password1 = "", password2 = ""; + size_t bits_20 = (1 << 20); + size_t bits_24 = (1 << 24); + for(size_t i = 0; i < bits_20; i++) { + password1 += "a"; + } + + for(size_t i = 0; i < bits_24; i++) { + password2 += "a"; + } + + generateHash(hash1, password1); + generateHash(hash2, password2); + ASSERT_TRUE(hash1.compare(hash2) != 0); +} + +TEST(libopenabe, PasswordHashingWithNoInput) { + TEST_DESCRIPTION("Testing that password hashing utility handles invalid inputs with an exception"); + string hash; + ASSERT_ANY_THROW(generateHash(hash, "")); +} + +TEST(libopenabe, CryptoBoxCPABEContext) { + TEST_DESCRIPTION("Testing that crypto box for CP-ABE context works"); + string mpk, msk; + string ct1, ct2; + + OpenABECryptoContext cpabe("CP-ABE"); + + cpabe.generateParams(); + cpabe.exportPublicParams(mpk); + cpabe.exportSecretParams(msk); + + cpabe.keygen("|one|two|three", "key1"); + cpabe.keygen("|one|two", "key2"); + + string pt1 = "hello world!", pt2; + cpabe.encrypt("((one or two) and three)", pt1, ct1); + + cout << "Ciphertext: " << ct1.size() << endl; + + ASSERT_TRUE(cpabe.decrypt("key1", ct1, pt2)); + + string pt3; + ASSERT_FALSE(cpabe.decrypt("key2", ct1, pt3)); + + OpenABECryptoContext cpabe2("CP-ABE"); + + cpabe2.importPublicParams(mpk); + cpabe2.importSecretParams(msk); + + cpabe2.keygen("|four|five|six", "key1"); + cpabe2.keygen("|five", "key2"); + + pt1 = "this is another plaintext!"; + pt2.clear(); + pt3.clear(); + cpabe2.encrypt("(four and five)", pt1, ct2); + ASSERT_ANY_THROW(cpabe2.encrypt("(four or ", pt2, ct1)); + + ASSERT_TRUE(cpabe2.decrypt("key1", ct2, pt2)); + ASSERT_FALSE(cpabe2.decrypt("key2", ct2, pt3)); +} + +TEST(libopenabe, CryptoBoxCPABEContextMinusBase64Encoding) { + TEST_DESCRIPTION("Testing that crypto box for CP-ABE context works (without base64 encoding)"); + string mpk, msk; + string ct1, ct2; + + OpenABECryptoContext cpabe("CP-ABE", false); + + cpabe.generateParams(); + cpabe.exportPublicParams(mpk); + cpabe.exportSecretParams(msk); + + cpabe.keygen("|one|two|three", "key1"); + cpabe.keygen("|one|two", "key2"); + + string pt1 = "hello world!", pt2; + cpabe.encrypt("((one or two) and three)", pt1, ct1); + + cout << "Ciphertext: " << ct1.size() << endl; + + ASSERT_TRUE(cpabe.decrypt("key1", ct1, pt2)); + + string pt3; + ASSERT_FALSE(cpabe.decrypt("key2", ct1, pt3)); + + OpenABECryptoContext cpabe2("CP-ABE", false); + + cpabe2.importPublicParams(mpk); + cpabe2.importSecretParams(msk); + + cpabe2.keygen("|four|five|six", "key1"); + cpabe2.keygen("|five", "key2"); + + pt1 = "this is another plaintext!"; + pt2.clear(); + pt3.clear(); + cpabe2.encrypt("(four and five)", pt1, ct2); + ASSERT_ANY_THROW(cpabe2.encrypt("(four or ", pt2, ct1)); + + ASSERT_TRUE(cpabe2.decrypt("key1", ct2, pt2)); + ASSERT_FALSE(cpabe2.decrypt("key2", ct2, pt3)); +} + +TEST(libopenabe, CryptoBoxCPABEContextBad0) { + TEST_DESCRIPTION("Testing that crypto box for CP-ABE context with invalid ciphertext -- failure case"); + + OpenABECryptoContext cpabe("CP-ABE", false); + + cpabe.generateParams(); +} + +TEST(libopenabe, CryptoBoxCPABEContextBad1) { + TEST_DESCRIPTION("Testing that crypto box for CP-ABE context with invalid scheme identifier -- failure case"); + + unique_ptr cpabe = nullptr; + + ASSERT_ANY_THROW(cpabe.reset(new OpenABECryptoContext("CP-ABES"))); +} + +TEST(libopenabe, CryptoBoxCPABEContextBad2) { + TEST_DESCRIPTION("Testing that crypto box for CP-ABE context with bad inputs -- failure case"); + + OpenABECryptoContext cpabe("CP-ABE"); + + cpabe.generateParams(); + + ASSERT_ANY_THROW(cpabe.keygen("one and three", "key0")); +} + +TEST(libopenabe, CryptoBoxCPABEContextBad3) { + TEST_DESCRIPTION("Testing that crypto box for CP-ABE context with bad inputs -- failure case"); + + OpenABECryptoContext cpabe("CP-ABE"); + + cpabe.generateParams(); + + cpabe.keygen("one|three", "key0"); + + string pt1, ct1; + ASSERT_ANY_THROW(cpabe.encrypt("four|five", pt1, ct1)); +} + +TEST(libopenabe, CryptoBoxKPABEContext) { + TEST_DESCRIPTION("Testing that crypto box for KP-ABE context works"); + string pt1, pt2, pt3, ct1, ct2; + + OpenABECryptoContext kpabe("KP-ABE"); + + kpabe.generateParams(); + + kpabe.keygen("((one or two) and three)", "key1"); + + pt1 = "hello world!"; + kpabe.encrypt("two|three", pt1, ct1); + // enc input "Date:" is specified incorrectly so should throw an exception + ASSERT_ANY_THROW(kpabe.encrypt("two|Date:January 1, 1971", pt1, ct2)); + + ASSERT_TRUE(kpabe.decrypt("key1", ct1, pt2)); + ASSERT_FALSE(kpabe.decrypt("key2", ct1, pt3)); +} + +TEST(libopenabe, CryptoBoxKPABEContextMinusBase64Encoding) { + TEST_DESCRIPTION("Testing that crypto box for KP-ABE context works (without base64 encoding)"); + string pt1, pt2, pt3, ct1, ct2; + + OpenABECryptoContext kpabe("KP-ABE", false); + + kpabe.generateParams(); + + kpabe.keygen("((one or two) and three)", "key1"); + + pt1 = "hello world!"; + kpabe.encrypt("two|three", pt1, ct1); + // enc input "Date:" is specified incorrectly so should throw an exception + ASSERT_ANY_THROW(kpabe.encrypt("two|Date:January 1, 1971", pt1, ct2)); + + ASSERT_TRUE(kpabe.decrypt("key1", ct1, pt2)); + ASSERT_FALSE(kpabe.decrypt("key2", ct1, pt3)); +} + +TEST(libopenabe, CryptoBoxPKEContext) { + TEST_DESCRIPTION("Testing that crypto box for PKE context works"); + string pk, sk; + string pt1, pt2, ct, ct1; + string user1PK, user1SK, user2PK, user2SK; + + OpenPKEContext pke, pke2; + + pke.keygen("user1"); + pke.exportPublicKey("user1", user1PK); + pke.exportPrivateKey("user1", user1SK); + + pke.keygen("user2"); + pke.exportPublicKey("user2", user2PK); + pke.exportPrivateKey("user2", user2SK); + + pt1 = "hello world!"; + pke.encrypt("user2", pt1, ct); + + ASSERT_TRUE(pke.decrypt("user2", ct, pt2)); + + pt2.clear(); + ASSERT_FALSE(pke.decrypt("user1", ct, pt2)); + + pke2.importPrivateKey("user2", user2SK); + + pt2.clear(); + ASSERT_TRUE(pke.decrypt("user2", ct, pt2)); +} + +TEST(libopenabe, CryptoBoxPKEContextMinusBase64Encoding) { + TEST_DESCRIPTION("Testing that crypto box for PKE context works (without base64 encoding)"); + string pk, sk; + string pt1, pt2, ct, ct1; + string user1PK, user1SK, user2PK, user2SK; + + OpenPKEContext pke("NIST_P256", false), pke2("NIST_P256", false); + + pke.keygen("user1"); + pke.exportPublicKey("user1", user1PK); + pke.exportPrivateKey("user1", user1SK); + + pke.keygen("user2"); + pke.exportPublicKey("user2", user2PK); + pke.exportPrivateKey("user2", user2SK); + + pt1 = "hello world!"; + pke.encrypt("user2", pt1, ct); + + ASSERT_TRUE(pke.decrypt("user2", ct, pt2)); + + pt2.clear(); + ASSERT_FALSE(pke.decrypt("user1", ct, pt2)); + + pke2.importPrivateKey("user2", user2SK); + + pt2.clear(); + ASSERT_TRUE(pke.decrypt("user2", ct, pt2)); +} + +TEST(libopenabe, CryptoBoxPKSIGContext) { + TEST_DESCRIPTION("Testing that crypto box for PKSIG context works"); + string pk, sk, msg1, msg2, sig; + + OpenPKSIGContext pksig; + pksig.keygen("user1"); + pksig.exportPublicKey("user1", pk); + pksig.exportPrivateKey("user1", sk); + + msg1 = "hello world!"; + pksig.sign("user1", msg1, sig); + + ASSERT_TRUE(pksig.verify("user1", msg1, sig)); + + msg2 = "an invalid message!"; + ASSERT_FALSE(pksig.verify("user1", msg2, sig)); +} + +TEST(libopenabe, CryptoBoxPKSIGContextMinusBase64Encoding) { + TEST_DESCRIPTION("Testing that crypto box for PKSIG context works (without base64 encoding)"); + string pk, sk, msg1, msg2, sig; + + OpenPKSIGContext pksig("NIST_P256", false); + pksig.keygen("user1"); + pksig.exportPublicKey("user1", pk); + pksig.exportPrivateKey("user1", sk); + + msg1 = "hello world!"; + pksig.sign("user1", msg1, sig); + + ASSERT_TRUE(pksig.verify("user1", msg1, sig)); + + msg2 = "an invalid message!"; + ASSERT_FALSE(pksig.verify("user1", msg2, sig)); +} + +struct thread_data { + int id, time; + OpenABERNG *shared_rng; +}; + +void *oabe_thread(void *args) { + OpenABEStateContext oabe; + OpenABERNG local_rng; + OpenABEByteString buf1, buf2; + struct thread_data *data = (struct thread_data *) args; + data->shared_rng->getRandomBytes(&buf1, 16); // 128-bit key + local_rng.getRandomBytes(&buf2, 16); + usleep(data->time); + cout << "client " << data->id << ": " << buf1.toHex() << "," << buf2.toHex() << endl; + //cout << "ctx_t ptr => " << core_get() << endl; + return NULL; +} + +TEST(libopenabe, OpenABEThreadContext) { + TEST_DESCRIPTION("Testing that OpenABE can be used with multi-threaded applications"); + int count = 4; + pthread_t threads[count]; + struct thread_data data[count]; + OpenABERNG rng; + for(int i = 0; i < count; i++) { + data[i].time = (i + 1) * 1000; + data[i].id = i + 1; + data[i].shared_rng = &rng; + if(pthread_create(&threads[i], NULL, oabe_thread, (void *) &data[i])) { + cerr << "Failed to create thread!" << endl; + return; + } + } + + for(int i = 0; i < count; i++) { + if(pthread_join(threads[i], NULL)) { + cerr << "Failed to join thread." << endl; + return; + } + } + return; +} + +} + +int main(int argc, char **argv) +{ + cout << "libopenabe v" << (OpenABE_LIBRARY_VERSION / 100.) << " test utility." << endl << endl; + + InitializeOpenABE(); + + ::testing::InitGoogleTest(&argc, argv); + int rc = RUN_ALL_TESTS(); + + ShutdownOpenABE(); + + return rc; +} + diff --git a/src/test_pke.cpp b/src/test_pke.cpp new file mode 100644 index 00000000..a47687f5 --- /dev/null +++ b/src/test_pke.cpp @@ -0,0 +1,124 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file test_pke.cpp +/// +/// \brief Unit testing utility for OpenABE schemes. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace oabe; + +#define TEST_MSG_LEN 32 +#define DEFAULT_PARAMETER_STRING "NIST_P256" +#define TEST_DESCRIPTION(desc) RecordProperty("description", desc) +#define TESTSUITE_DESCRIPTION(desc) ::testing::Test::RecordProperty("description", desc) + + +TEST(PK_ODPH, TestCCASecurityForScheme) { + TEST_DESCRIPTION("Testing CCA-secure PK OPDH context with randomly generated messages"); + OpenABEByteString bytes, ctBlob, hdr1, hdr2; + string plaintext1, plaintext2; + OpenABECiphertext ciphertext, ciphertext2; + OpenABERNG rng; + rng.getRandomBytes(&bytes, TEST_MSG_LEN); + plaintext1 = bytes.toString(); + // create new KEM context for PKE ECC MQV scheme + unique_ptr schemeContext = OpenABE_createContextPKESchemeCCA(OpenABE_SCHEME_PK_OPDH); + ASSERT_TRUE(schemeContext != nullptr); + + // Generate a set of parameters for an ABE authority + ASSERT_TRUE(schemeContext->generateParams(DEFAULT_PARAMETER_STRING) == OpenABE_NOERROR); + + // Compute party A's static public and private key + ASSERT_TRUE(schemeContext->keygen("ID_A", "public_A", "private_A") == OpenABE_NOERROR); + + // Compute party B's static public and private key + ASSERT_TRUE(schemeContext->keygen("ID_B", "public_B", "private_B") == OpenABE_NOERROR); + + // Test load / delete (perhaps, we should provide convenience functions for this) + OpenABEByteString publicKeyA, publicKeyA_bad, privateKeyB; + + schemeContext->exportKey("public_A", publicKeyA); + schemeContext->exportKey("private_B", privateKeyB); + + publicKeyA_bad = publicKeyA; + // swap two positions in header + publicKeyA_bad[5] = publicKeyA_bad[6]; // tweak header a little bit + publicKeyA_bad[6] = publicKeyA[5]; + + // delete them + ASSERT_TRUE(schemeContext->deleteKey("public_A") == OpenABE_NOERROR); + ASSERT_TRUE(schemeContext->deleteKey("private_B") == OpenABE_NOERROR); + + // attempt to load a key that was just deleted + ASSERT_FALSE(schemeContext->loadPublicKey("public_A", publicKeyA_bad) == OpenABE_NOERROR); + + // attempt to load a key that was just deleted + ASSERT_TRUE(schemeContext->loadPublicKey("public_A", publicKeyA) == OpenABE_NOERROR); + + // attempt to load a key that was just deleted + ASSERT_TRUE(schemeContext->loadPrivateKey("private_B", privateKeyB) == OpenABE_NOERROR); + + ASSERT_TRUE(schemeContext->encrypt(NULL, "public_B", "public_A", plaintext1, &ciphertext) == OpenABE_NOERROR); + + ciphertext.exportToBytes(ctBlob); + ciphertext2.loadFromBytes(ctBlob); + ASSERT_TRUE(ciphertext == ciphertext2); + // verify header is thesame + ciphertext.getHeader(hdr1); + ciphertext2.getHeader(hdr2); + ASSERT_TRUE(hdr1 == hdr2); + + ASSERT_TRUE(schemeContext->decrypt("public_A", "private_B", plaintext2, &ciphertext2) == OpenABE_NOERROR); + + ASSERT_TRUE(plaintext1.compare(plaintext2) == 0); +} + + +int main(int argc, char **argv) { + int rc; + + InitializeOpenABE(); + + ::testing::InitGoogleTest(&argc, argv); + rc = RUN_ALL_TESTS(); + + ShutdownOpenABE(); + + return rc; +} diff --git a/src/test_policy.cpp b/src/test_policy.cpp new file mode 100644 index 00000000..8f0b5716 --- /dev/null +++ b/src/test_policy.cpp @@ -0,0 +1,146 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file test_policy.cpp +/// +/// \brief Functional testing utility for OpenABE. This executable is capable +/// of running all functional tests, depending on user settings. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace oabe; + +bool TestPolicy(const char *str) +{ + string policy_str(str); + std::unique_ptr policy = createPolicyTree(policy_str); + + if(policy != nullptr) { + cout << "Policy Full: " << policy->toString() << endl; + cout << "Policy Compact: " << policy->toCompactString() << endl; + + std::unique_ptr policy2 = nullptr; + policy2.reset(policy->clone()); + cout << "Policy2 Full: " << policy2->toString() << endl; + cout << "Policy2 Compact: " << policy2->toCompactString() << endl; + return true; + } else { + cerr << "Error occurred during parsing." << endl; + } + return false; +} + +bool TestAttributeList(const char *str) { + try { + std::unique_ptr attrList = createAttributeList(str); + if (attrList != nullptr) { + cout << "AttrList Full: " << attrList->toString() << endl; + cout << "AttrList Compact: " << attrList->toCompactString() << endl; + std::unique_ptr attrList2 = nullptr; + attrList2.reset(attrList->clone()); + + cout << "AttrList2 Full: " << attrList2->toString() << endl; + cout << "AttrList2 Compact: " << attrList2->toCompactString() << endl; + const vector *raw_attrs = attrList->getAttributeList(); + cout << "Number of raw attributes: " << raw_attrs->size() << endl; + return true; + } + } catch(OpenABE_ERROR & error) { + cerr << "Error: " << OpenABE_errorToString(error) << endl; + } + return false; +} + +bool TestCheckSatisfy(const string& policy_str, const string& attributes, bool verbose) { + pair result; + try { + std::unique_ptr policy = createPolicyTree(policy_str); + std::unique_ptr attrList = createAttributeList(attributes); + if (policy != nullptr && attrList != nullptr) { + if (verbose) { + cout << "Policy: " << policy->toString() << endl; + cout << "Policy Compact: " << policy->toCompactString() << endl; + cout << endl; + cout << "AttrList: " << attrList->toString() << endl; + cout << "AttrList Compact: " << attrList->toCompactString() << endl; + cout << endl; + } + result = checkIfSatisfied(policy.get(), attrList.get()); + cout << "Check if satisfied => " << (result.first ? "true" : "false") << endl; + cout << "Number of matches => " << result.second << endl; + return result.first; + } else { + throw OpenABE_ERROR_INVALID_INPUT; + } + } catch(OpenABE_ERROR& error) { + cout << "Error: " << OpenABE_errorToString(error) << endl; + } + return false; +} + +int main(int argc, char **argv) +{ + bool verbose = false; + if(argc < 3) { + cout << "Usage " << string(argv[0]) << ": [ policy, attributes or logic ] [ input args ] [ verbose ]" << endl; + exit(-1); + } + const string cmd(argv[1]); + + if (cmd == "policy") { + return (TestPolicy(argv[2]) ? 0 : 1); + } else if(cmd == "attributes") { + return (TestAttributeList(argv[2]) ? 0 : 1); + } else if(cmd == "logic") { + if (argc == 5) { + const string verb = argv[4]; + if (verb == "true") { + verbose = true; + } + } else if (argc < 4) { + cout << "expecting a 'policy' and an 'attribute list'" << endl; + return -1; + } + const string policy_str = argv[2]; + const string attr_list = argv[3]; + return (TestCheckSatisfy(policy_str, attr_list, verbose) ? 0 : 1); + } else { + cout << "Command Options: 'policy', 'attributes' or 'logic' " << endl; + exit(-1); + } + + return -1; +} diff --git a/src/test_ske.cpp b/src/test_ske.cpp new file mode 100644 index 00000000..fae3447b --- /dev/null +++ b/src/test_ske.cpp @@ -0,0 +1,261 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file test_ske.cpp +/// +/// \brief Unit testing utility for OpenABE schemes. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace oabe; + +#define TEST_MSG_LEN 32 +#define TEST_MSGBLOCK_LEN 16 + +#define TEST_DESCRIPTION(desc) RecordProperty("description", desc) +#define TESTSUITE_DESCRIPTION(desc) ::testing::Test::RecordProperty("description", desc) + + +TEST(SK, TestStreamAuthEncForSKScheme) { + TEST_DESCRIPTION("Testing Stream SK scheme enc/dec using randomly generated keys"); + OpenABERNG rng; + shared_ptr symkey(new OpenABESymKey); + OpenABEByteString plaintext, ciphertext, iv, tag; + OpenABEByteString ptBlock1, ptBlock2, ctBlock1, ctBlock2; + + // generate a random secret key of a certain size + symkey->generateSymmetricKey(DEFAULT_SYM_KEY_BYTES); + + unique_ptr authEncStream(new OpenABESymKeyAuthEncStream(DEFAULT_AES_SEC_LEVEL, symkey)); + + rng.getRandomBytes(&ptBlock1, TEST_MSGBLOCK_LEN); + rng.getRandomBytes(&ptBlock2, TEST_MSGBLOCK_LEN); + + ASSERT_TRUE(authEncStream->encryptInit(&iv) == OpenABE_NOERROR); + // set 0s for the AAD + authEncStream->initAddAuthData(NULL, 0); + ASSERT_TRUE(authEncStream->setAddAuthData() == OpenABE_NOERROR); + + // perform update 1 + ASSERT_TRUE(authEncStream->encryptUpdate(&ptBlock1, &ciphertext) == OpenABE_NOERROR); + + // perform update 2 + ASSERT_TRUE(authEncStream->encryptUpdate(&ptBlock2, &ciphertext) == OpenABE_NOERROR); + ASSERT_TRUE(authEncStream->encryptFinalize(&ciphertext, &tag) == OpenABE_NOERROR); + + // split ciphertext into blocks + ctBlock1 = ciphertext.getSubset(0, ptBlock1.size()); + ctBlock2 = ciphertext.getSubset(ptBlock1.size(), ptBlock2.size()); + + // now try to decrypt the ciphertexts + ASSERT_TRUE(authEncStream->decryptInit(&iv, &tag) == OpenABE_NOERROR); + + // set 0s for the AAD + authEncStream->initAddAuthData(NULL, 0); + ASSERT_TRUE(authEncStream->setAddAuthData() == OpenABE_NOERROR); + + // perform decrypt updates in order (note: order of blocks must be managed by the user) + ASSERT_TRUE(authEncStream->decryptUpdate(&ctBlock1, &plaintext) == OpenABE_NOERROR); + ASSERT_TRUE(authEncStream->decryptUpdate(&ctBlock2, &plaintext) == OpenABE_NOERROR); + ASSERT_TRUE(authEncStream->decryptFinalize(&plaintext) == OpenABE_NOERROR); + + ASSERT_TRUE(plaintext == (ptBlock1 + ptBlock2)); + // FAILURE TEST: now try to decrypt the ciphertexts (out of order) + plaintext.clear(); + ASSERT_TRUE(authEncStream->decryptInit(&iv, &tag) == OpenABE_NOERROR); + + // set 0s for the AAD + authEncStream->initAddAuthData(NULL, 0); + ASSERT_TRUE(authEncStream->setAddAuthData() == OpenABE_NOERROR); + // perform decrypt updates in order (note: order of blocks must be managed by the user) + ASSERT_TRUE(authEncStream->decryptUpdate(&ctBlock2, &plaintext) == OpenABE_NOERROR); + ASSERT_TRUE(authEncStream->decryptUpdate(&ctBlock1, &plaintext) == OpenABE_NOERROR); + ASSERT_FALSE(authEncStream->decryptFinalize(&plaintext) == OpenABE_NOERROR); +} + +class KDFNistTestVector : public ::testing::Test { + protected: + virtual void SetUp() { } + string password, salt; + OpenABEByteString DK, DK0, key, P, S; + int dkLen, c; +}; + +TEST_F(KDFNistTestVector, DK1Test) { + TEST_DESCRIPTION("Testing KDFs are implemented according to RFC 2898: DK1"); + /* PBKDF2 Test Vectors as defined in RFC 6070 */ + /* test 1 */ + uint8_t dk1[] = {0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, + 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37, + 0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48, + 0x08, 0x05, 0x98, 0x7c, 0xb7, 0x0b, 0xe1, 0x7b}; // (32 octets) + P = "password"; + S = "salt"; + c = 1; + dkLen = 32; + + DK.appendArray(dk1, dkLen); + DK0 = OpenABEPBKDF(P, dkLen, S, c); + cout << "DK1: " << DK0.toHex() << endl; + ASSERT_TRUE(DK == DK0); +} + +TEST_F(KDFNistTestVector, DK2Test) { + TEST_DESCRIPTION("Testing KDFs are implemented according to RFC 2898: DK2"); + /* test 2 */ + uint8_t dk2[] = {0xae, 0x4d, 0x0c, 0x95, 0xaf, 0x6b, 0x46, 0xd3, + 0x2d, 0x0a, 0xdf, 0xf9, 0x28, 0xf0, 0x6d, 0xd0, + 0x2a, 0x30, 0x3f, 0x8e}; // (20 octets) + + DK.clear(); + P = "password"; + S = "salt"; + c = 2; + dkLen = 20; + + DK.appendArray(dk2, dkLen); + DK0 = OpenABEPBKDF(P, dkLen, S, c); + cout << "DK2: " << DK0.toHex() << endl; + ASSERT_TRUE(DK == DK0); +} + +TEST_F(KDFNistTestVector, DK3Test) { + TEST_DESCRIPTION("Testing KDFs are implemented according to RFC 2898: DK3"); + /* test 3 is successful but takes a while */ + uint8_t dk3[] = {0xcf, 0x81, 0xc6, 0x6f, 0xe8, 0xcf, 0xc0, 0x4d, 0x1f, + 0x31, 0xec, 0xb6, 0x5d, 0xab, 0x40, 0x89, 0xf7, 0xf1, + 0x79, 0xe8}; + DK.clear(); + P = "password"; + S = "salt"; + c = 16777216; + dkLen = 20; + + DK.appendArray(dk3, dkLen); + DK0 = OpenABEPBKDF(P, dkLen, S, c); + cout << "DK3: " << DK0.toHex() << endl; + ASSERT_TRUE(DK == DK0); +} + +TEST_F(KDFNistTestVector, DK4Test) { + TEST_DESCRIPTION("Testing KDFs are implemented according to RFC 2898: DK4"); + /* test 4 */ + uint8_t dk4[] = {0x34, 0x8c, 0x89, 0xdb, 0xcb, 0xd3, 0x2b, 0x2f, 0x32, + 0xd8, 0x14, 0xb8, 0x11, 0x6e, 0x84, 0xcf, 0x2b, 0x17, + 0x34, 0x7e, 0xbc, 0x18, 0x00, 0x18, 0x1c}; // (25 octets) + + DK.clear(); + P = "passwordPASSWORDpassword"; // (24 octets) + S = "saltSALTsaltSALTsaltSALTsaltSALTsalt"; // (36 octets) + c = 4096; + dkLen = 25; + + DK.appendArray(dk4, dkLen); + DK0 = OpenABEPBKDF(P, dkLen, S, c); + cout << "DK4: " << DK0.toHex() << endl; + ASSERT_TRUE(DK == DK0); +} + +TEST_F(KDFNistTestVector, DK5Test) { + TEST_DESCRIPTION("Testing KDFs are implemented according to RFC 2898: DK5"); + /* test 5 */ + uint8_t dk5[] = {0x89, 0xb6, 0x9d, 0x05, 0x16, 0xf8, 0x29, 0x89, + 0x3c, 0x69, 0x62, 0x26, 0x65, 0x0a, 0x86, 0x87}; // (16 octets) + DK.clear(); + P = string("pass\0word", 9); // (9 octets) + S = string("sa\0lt", 5); // (5 octets) + c = 4096; + dkLen = 16; + + DK.appendArray(dk5, dkLen); + DK0 = OpenABEPBKDF(P, dkLen, S, c); + cout << "DK5: " << DK0.toHex() << endl; + ASSERT_TRUE(DK == DK0); +} + + +TEST(KDF, PasswordHashingSuccess) { + TEST_DESCRIPTION("Testing that password hashing succeed in general cases"); + string hash1, hash2; + string password1, password2; + + password1 = "password"; + password2 = "passw0rd"; + generateHash(hash1, password1); + generateHash(hash2, password2); + + ASSERT_TRUE(checkPassword(hash1, password1)); + ASSERT_FALSE(checkPassword(hash1, password2)); + ASSERT_TRUE(checkPassword(hash2, password2)); + ASSERT_FALSE(checkPassword(hash2, password1)); +} + +TEST(KDF, CheckPassWithNonHexHashString) { + TEST_DESCRIPTION("Testing check password with ascii-looking hash string"); + ASSERT_THROW(checkPassword("foosdfasdfasdfasdfasdfasdfasdfadfafoosdfasdfasdfasdfasdfzxyfasdf", "password1"), OpenABE_ERROR); +} + +TEST(KDF, CheckPassWithInvalidHexString) { + TEST_DESCRIPTION("Testing check password with invalid hex string (e.g., 0xff)"); + ASSERT_THROW(checkPassword("123\xff\xff", "password1"), OpenABE_ERROR); +} + +TEST(KDF, CheckPassWithEmptyHash) { + TEST_DESCRIPTION("Testing check password with an empty hash string"); + ASSERT_THROW(checkPassword("", "password1"), OpenABE_ERROR); +} + +TEST(KDF, CheckWithEmptyPassword) { + TEST_DESCRIPTION("Testing check password with an empty password and invalid string"); + string hash; + generateHash(hash, "password1"); + ASSERT_THROW(checkPassword(hash, ""), OpenABE_ERROR); +} + + +int main(int argc, char **argv) { + int rc; + + InitializeOpenABE(); + + ::testing::InitGoogleTest(&argc, argv); + rc = RUN_ALL_TESTS(); + + ShutdownOpenABE(); + + return rc; +} diff --git a/src/test_zml.cpp b/src/test_zml.cpp new file mode 100644 index 00000000..770d57d3 --- /dev/null +++ b/src/test_zml.cpp @@ -0,0 +1,487 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file test_zml.cpp +/// +/// \brief Unit testing utility for Zeutro Math Library +/// +/// \author J. Ayo Akinyele +/// +/// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace oabe; +using namespace oabe::crypto; + +#define COLOR_STR_GREEN "\033[32m" +#define COLOR_STR_NORMAL "\033[0m" +#define COLOR_STR_RED "\033[31m" + +#define EXIT(msg) cout << msg << endl; goto CLEANUP +#define NUM_PAIRING_TESTS 10 +#define ASSERT_RESULT(condition, msg) if(condition) { \ + cout << "FAIL: " << msg << endl; \ + return false; } + +// Global test counters +uint32_t gNumTests = 0; +uint32_t gSuccessfulTests = 0; +#define TEST_DESCRIPTION(desc) RecordProperty("description", desc) +#define TESTSUITE_DESCRIPTION(desc) ::testing::Test::RecordProperty("description", desc) + +namespace { + +class ZeutroMathLib : public ::testing::Test { +protected: + virtual void SetUp() { + string seed; + pgroup_.reset(new OpenABEPairing(DEFAULT_BP_PARAM)); + rng_.reset(new OpenABERNG()); + } + + // virtual void TearDown() {} + unique_ptr pgroup_; + unique_ptr rng_; + // OpenABEByteString entropy_, hashSeed_; + // unique_ptr rng_; +}; + +TEST_F(ZeutroMathLib, InitZP) { + TEST_DESCRIPTION("Testing that init ZP works correctly"); + ZP a; + pgroup_->initZP(a, 1234567890); + string b = "499602D2"; // string representation of 1234567890 + string str_a = a.getBytesAsString(); + cout << "ZP: " << str_a << endl; + + ASSERT_EQ(str_a, b); +} + +TEST_F(ZeutroMathLib, InitPairingGroup) { + TEST_DESCRIPTION("Testing that pairing group init works as expected"); + int len = 0; + char *str = zml_bignum_toHex(pgroup_->order, &len); + string s0 = string(str, len); + zml_bignum_safe_free(str); + cout << "order: " << s0 << endl; + ASSERT_TRUE(s0 != ""); +} + +TEST_F(ZeutroMathLib, NegateZP) { + TEST_DESCRIPTION("Testing that ZP negation works correctly"); + ZP a = pgroup_->randomZP(rng_.get()); + ZP zero; + pgroup_->initZP(zero, 0); + cout << "Output: a = " << a << endl; + cout << "Negation: -a = " << -a << endl; + ZP b = (a + -a); + cout << "a + -a = " << b << endl; + ASSERT_TRUE(a != -a); + ASSERT_EQ(b, zero); +} + +TEST_F(ZeutroMathLib, AddZP) { + TEST_DESCRIPTION("Testing modulo addition is correct"); + ZP a = pgroup_->randomZP(rng_.get()); + ZP b = pgroup_->randomZP(rng_.get()); + // make sure it is commutative + ASSERT_EQ(a + b, b + a); +} + +TEST_F(ZeutroMathLib, SubtractZP) { + TEST_DESCRIPTION("Testing modulo subtraction is correct"); + ZP a = pgroup_->randomZP(rng_.get()); + ZP b = pgroup_->randomZP(rng_.get()); + // subtraction is equivalent to negation and addition + ASSERT_EQ(a - b, a + -b); +} + +TEST_F(ZeutroMathLib, RandomZP) { + TEST_DESCRIPTION("Testing that random ZP works correctly"); + ZP a = pgroup_->randomZP(rng_.get()); + ZP b = pgroup_->randomZP(rng_.get()); + ASSERT_TRUE(a != b); +} + +TEST_F(ZeutroMathLib, MultInverseZP) { + TEST_DESCRIPTION("Testing that multiplicative inverse of a ZP element works correctly"); + ZP a = pgroup_->randomZP(rng_.get()); + ZP c = a; + c.multInverse(); + ZP one; + pgroup_->initZP(one, 1); + cout << "c = inv(a) : " << c << endl; + cout << "a * c = " << (a * c) << endl; + + ASSERT_EQ(one, a * c); +} + +TEST_F(ZeutroMathLib, MultiplyAndDivideZP) { + TEST_DESCRIPTION("Testing that multiplication and division for ZP elements works correctly"); + ZP x = pgroup_->randomZP(rng_.get()); + ZP y = pgroup_->randomZP(rng_.get()); + ZP z = x * y; + cout << "z = x * y => " << z << endl; + ZP t = z / y; + // cout << "(z / y) == x ? " << ((t == x) ? "true" : "false") << endl; + ASSERT_EQ(t, x); + ZP u = z / x; + // cout << "(z / x) == y ? " << ((u == y) ? "true" : "false") << endl; + ASSERT_EQ(u, y); +} + +TEST_F(ZeutroMathLib, ByteStringsForZP) { + TEST_DESCRIPTION("Testing that byte string rep is consistent for ZP elements"); + ZP x = pgroup_->randomZP(rng_.get()); + OpenABEByteString z1; + z1 = x.getByteString(); + string hex_of_raw = z1.toHex(); + cout << "x in raw bin: " << hex_of_raw << endl; + string s = x.getBytesAsString(); + cout << "x in str hex: " << s << endl; + + ASSERT_EQ(hex_of_raw, s); +} + +TEST_F(ZeutroMathLib, SerializeZP) { + TEST_DESCRIPTION("Testing that ZP serialize/deserialize works correctly"); + OpenABEByteString z1; + ZP x0 = pgroup_->randomZP(rng_.get()); + x0.serialize(z1); + cout << "x0 out: " << z1.toLowerHex() << endl; + ZP x1; + pgroup_->initZP(x1, 0); + x1.deserialize(z1); + + ASSERT_EQ(x0, x1); +} + +TEST_F(ZeutroMathLib, DivideZPByAConstant) { + TEST_DESCRIPTION("Testing that ZP can be divided by an integer"); + ZP x = pgroup_->randomZP(rng_.get()); + + ZP y1 = x / ZP(2); + ZP y2 = x / ZP(-2); + cout << "x / 2 = " << y1 << endl; + cout << "x / -2 = " << y2 << endl; + + ASSERT_EQ(x, y1 * ZP(2)); + ASSERT_EQ(x, y2 * ZP(-2)); +} + +TEST_F(ZeutroMathLib, ExponentiateZP) { + TEST_DESCRIPTION("Testing that exponentiation with ZP works correctly"); + ZP x = pgroup_->randomZP(rng_.get()); + ZP a; + pgroup_->initZP(a, 1234567890); + + ZP y = power(x, a); + cout << "power(x, 1234567890) => " << y << endl; + // cout << "power(x, a) => " << power(x, a) << endl; + ASSERT_EQ(y, power(x, 1234567890)); +} + +TEST_F(ZeutroMathLib, DivisionWithZPConstants) { + TEST_DESCRIPTION("Testing that division still works for small constants (used in LSSS recovery)"); + ZP zero, one, two; + pgroup_->initZP(zero, 0); + pgroup_->initZP(one, 1); + pgroup_->initZP(two, 2); + + ZP z0 = (zero - one) / (two - one); + // ZP z0 = ((ZP(0) - ZP(1)) / (ZP(2) - ZP(1))); + cout << "z0: " << z0 << endl; + + ASSERT_TRUE(z0.ismember()); +} + +TEST_F(ZeutroMathLib, LeftAndRightShiftZP) { + TEST_DESCRIPTION("Testing logical shift operation for ZP"); + + ZP x = pgroup_->randomZP(rng_.get()); + + ASSERT_EQ(x, (x << 128) >> 128); +} + +TEST_F(ZeutroMathLib, LogicalOperatorsWithZP) { + TEST_DESCRIPTION("Testing the logical comparison operators for ZP"); + ZP zero, ten, twenty; + pgroup_->initZP(zero, 0); + pgroup_->initZP(ten, 10); + pgroup_->initZP(twenty, 20); + + ZP x = pgroup_->randomZP(rng_.get()); + ASSERT_TRUE(ten < x); + ASSERT_TRUE(x > twenty); + ASSERT_TRUE(ten <= twenty); + ASSERT_TRUE(x >= zero); + ASSERT_FALSE(x != x); +} + +////// G1 unit tests ////// +TEST_F(ZeutroMathLib, RandomG1) { + TEST_DESCRIPTION("Testing that random G1 works correctly"); + G1 a = pgroup_->randomG1(rng_.get()); + G1 b = pgroup_->randomG1(rng_.get()); +#if defined(BP_WITH_OPENSSL) + ASSERT_TRUE(a == b); +#else + ASSERT_TRUE(a != b); +#endif +} + +TEST_F(ZeutroMathLib, MulG1Tests) { + TEST_DESCRIPTION("Testing that multiplication with G1 works correctly"); + G1 g = pgroup_->randomG1(rng_.get()); + G1 h = pgroup_->randomG1(rng_.get()); + cout << "(mul) z = (g * h) => " << g * h << endl; + ASSERT_EQ(g * h, h * g); +} + +TEST_F(ZeutroMathLib, DivG1Tests) { + TEST_DESCRIPTION("Testing that division with G1 works correctly"); + G1 g = pgroup_->randomG1(rng_.get()); + G1 h = pgroup_->randomG1(rng_.get()); + G1 i = g / h; + cout << "(div) i == (g / h) => " << i << endl; + ASSERT_EQ(g, i * h); +} + +TEST_F(ZeutroMathLib, NegateG1Tests) { + TEST_DESCRIPTION("Testing that negation with G1 works correctly"); + G1 g = pgroup_->randomG1(rng_.get()); + G1 k = -g; + cout << "(negation) k = -g: " << k << endl; + ASSERT_EQ(g, -k); +} + +TEST_F(ZeutroMathLib, ExpG1Tests) { + TEST_DESCRIPTION("Testing that exponentiation with G1 works correctly"); + G1 g = pgroup_->randomG1(rng_.get()); + ZP r = pgroup_->randomZP(rng_.get()); + G1 a = g.exp(r); + cout << "(exp) a = (g^r) => " << a << endl; + ZP z = r; + z.multInverse(); + ASSERT_EQ(a.exp(z), g); +} + +TEST_F(ZeutroMathLib, SerializeG1) { + TEST_DESCRIPTION("Testing that G1 serialize/deserialize works correctly"); + G1 g = pgroup_->randomG1(rng_.get()); + OpenABEByteString tmp; + g.serialize(tmp); + cout << "serialized a => " << tmp.toHex() << endl; + + G1 b = pgroup_->initG1(); + b.deserialize(tmp); + ASSERT_EQ(g, b); +} + +TEST_F(ZeutroMathLib, MembershipTestG1) { + TEST_DESCRIPTION("Testing that G1 membership check is correct"); + G1 g = pgroup_->randomG1(rng_.get()); + ASSERT_TRUE(g.ismember(pgroup_->order)); +} + +TEST_F(ZeutroMathLib, HashToG1) { + TEST_DESCRIPTION("Testing hashing to G1 works as expected"); + OpenABEByteString f; + string message1 = "hello world", message2 = "hello w0rld"; + + rng_->getRandomBytes(&f, HASH_LEN); + G1 F = pgroup_->hashToG1(f, message1); + cout << "(hash to G1) F => " << F << endl; + + G1 H = pgroup_->hashToG1(f, message2); + cout << "(hash to G1) H => " << H << endl; + + ASSERT_TRUE(F != H); +} + + +////// G2 unit tests ////// +TEST_F(ZeutroMathLib, RandomG2) { + TEST_DESCRIPTION("Testing that random G2 works correctly"); + G2 a = pgroup_->randomG2(rng_.get()); + G2 b = pgroup_->randomG2(rng_.get()); +#if defined(BP_WITH_OPENSSL) + ASSERT_TRUE(a == b); +#else + ASSERT_TRUE(a != b); +#endif +} + +TEST_F(ZeutroMathLib, MulG2Tests) { + TEST_DESCRIPTION("Testing that multiplication with G2 works correctly"); + G2 g = pgroup_->randomG2(rng_.get()); + G2 h = pgroup_->randomG2(rng_.get()); + cout << "(mul) z = (g * h) => " << g * h << endl; + ASSERT_EQ(g * h, h * g); +} + +TEST_F(ZeutroMathLib, DivG2Tests) { + TEST_DESCRIPTION("Testing that division with G2 works correctly"); + G2 g = pgroup_->randomG2(rng_.get()); + G2 h = pgroup_->randomG2(rng_.get()); + G2 i = g / h; + cout << "(div) i == (g / h) => " << i << endl; + ASSERT_EQ(g, i * h); +} + +TEST_F(ZeutroMathLib, NegateG2Tests) { + TEST_DESCRIPTION("Testing that negation with G2 works correctly"); + G2 g = pgroup_->randomG2(rng_.get()); + G2 k = -g; + cout << "(negation) k = -g: " << k << endl; + ASSERT_EQ(g, -k); +} + +TEST_F(ZeutroMathLib, ExpG2Tests) { + TEST_DESCRIPTION("Testing that exponentiation with G2 works correctly"); + G2 g = pgroup_->randomG2(rng_.get()); + ZP r = pgroup_->randomZP(rng_.get()); + G2 a = g.exp(r); + cout << "(exp) a = (g^r) => " << a << endl; + ZP z = r; + z.multInverse(); + ASSERT_EQ(a.exp(z), g); +} + +TEST_F(ZeutroMathLib, SerializeG2) { + TEST_DESCRIPTION("Testing that G2 serialize/deserialize works correctly"); + G2 g = pgroup_->randomG2(rng_.get()); + OpenABEByteString tmp; + g.serialize(tmp); + cout << "serialized a => " << tmp.toHex() << endl; + + G2 b = pgroup_->initG2(); + b.deserialize(tmp); + ASSERT_EQ(g, b); +} + +TEST_F(ZeutroMathLib, MembershipTestG2) { + TEST_DESCRIPTION("Testing that G1 membership check is correct"); + G2 g = pgroup_->randomG2(rng_.get()); + ASSERT_TRUE(g.ismember(pgroup_->order)); +} + +////// GT unit tests ////// +TEST_F(ZeutroMathLib, MulGTTests) { + TEST_DESCRIPTION("Testing that multiplication with GT works correctly"); + G1 g1 = pgroup_->randomG1(rng_.get()); + G2 g2 = pgroup_->randomG2(rng_.get()); + GT gt1 = pgroup_->pairing(g1,g2); + + GT h = gt1 * gt1; + ASSERT_EQ(gt1, h / gt1); +} + +TEST_F(ZeutroMathLib, DivGTTests) { + TEST_DESCRIPTION("Testing that division with GT works correctly"); + G1 g1 = pgroup_->randomG1(rng_.get()); + G2 g2 = pgroup_->randomG2(rng_.get()); + GT gt1 = pgroup_->pairing(g1,g2); + + GT h = gt1 / gt1; + ASSERT_EQ(gt1, h * gt1); +} + +TEST_F(ZeutroMathLib, NegateGTTests) { + TEST_DESCRIPTION("Testing that negation with GT works correctly"); + G1 g1 = pgroup_->randomG1(rng_.get()); + G2 g2 = pgroup_->randomG2(rng_.get()); + GT gt = pgroup_->pairing(g1,g2); + + GT k = -gt; + cout << "(negation) k = -gt: " << k << endl; + ASSERT_EQ(gt, -k); +} + +TEST_F(ZeutroMathLib, ExpGTTests) { + TEST_DESCRIPTION("Testing that exponentiation with GT works correctly"); + G1 g1 = pgroup_->randomG1(rng_.get()); + G2 g2 = pgroup_->randomG2(rng_.get()); + GT gt = pgroup_->pairing(g1,g2); + + ZP r = pgroup_->randomZP(rng_.get()); + GT a = gt.exp(r); + cout << "(exp) a = (g^r) => " << a << endl; + ZP z = r; + z.multInverse(); + ASSERT_EQ(a.exp(z), gt); +} + +TEST_F(ZeutroMathLib, SerializeGT) { + TEST_DESCRIPTION("Testing that GT serialize/deserialize works correctly"); + G1 g1 = pgroup_->randomG1(rng_.get()); + G2 g2 = pgroup_->randomG2(rng_.get()); + GT gt = pgroup_->pairing(g1,g2); + + OpenABEByteString tmp; + gt.serialize(tmp); + cout << "serialized a => " << tmp.toHex() << endl; + + GT b = pgroup_->initGT(); + b.deserialize(tmp); + ASSERT_EQ(gt, b); +} + +TEST_F(ZeutroMathLib, MembershipTestGT) { + TEST_DESCRIPTION("Testing that GT membership check is correct"); + G1 g1 = pgroup_->randomG1(rng_.get()); + G2 g2 = pgroup_->randomG2(rng_.get()); + GT gt = pgroup_->pairing(g1,g2); + ASSERT_TRUE(gt.ismember(pgroup_->order)); +} + +} + +int main(int argc, char **argv) +{ + int rc; + + InitializeOpenABE(); + + ::testing::InitGoogleTest(&argc, argv); + rc = RUN_ALL_TESTS(); + + ShutdownOpenABE(); + + return rc; +} diff --git a/src/test_zml1.cpp b/src/test_zml1.cpp new file mode 100644 index 00000000..7343ec1b --- /dev/null +++ b/src/test_zml1.cpp @@ -0,0 +1,565 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file test_zml1.cpp +/// +/// \brief Unit testing utility for Zeutro Math Library +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(ENABLE_PROFILER) +#include +#endif + +using namespace std; +using namespace oabe; +using namespace oabe::crypto; + +#define COLOR_STR_GREEN "\033[32m" +#define COLOR_STR_NORMAL "\033[0m" +#define COLOR_STR_RED "\033[31m" + +#define EXIT(msg) cout << msg << endl; goto CLEANUP +#define NUM_PAIRING_TESTS 10 +#define ASSERT_RESULT(condition, msg) if(condition) { \ + cout << "FAIL: " << msg << endl; \ + return false; } + +// Global test counters +uint32_t gNumTests = 0; +uint32_t gSuccessfulTests = 0; + +////////// +// Utility routines +////////// + +void +LogTestResult(string testName, bool (*testPtr)(const string& arg), + const string fname, const string curve_param = "") +{ + string colorGreen(COLOR_STR_GREEN); + string colorNormal(COLOR_STR_NORMAL); + string colorRed(COLOR_STR_RED); + string curve_id(curve_param); + + cout << "Testing if " << testName << "..." << endl; +#if defined(ENABLE_PROFILER) + if (fname != "") ProfilerStart(fname.c_str()); +#endif + bool testResult = testPtr(curve_id); +#if defined(ENABLE_PROFILER) + if (fname != "") ProfilerStop(); +#endif + if (testResult == true) { + cout << "\t" << colorGreen << "[PASS]" << colorNormal << endl; + gSuccessfulTests++; + } else { + cout << colorRed << "\t[FAIL]" << colorNormal << endl; + } + + gNumTests++; +} + +bool +Test_InitializeLibrary(const string& arg) +{ + InitializeOpenABE(); + return true; +} + +bool +Test_ShutdownLibrary(const string& arg) +{ + ShutdownOpenABE(); + return true; +} + +bool +Test_ZP_operations(const string& curve_id) +{ + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEPairing pgroup(curve_id); +// OpenABEPairing pgroup(DEFAULT_BP_PARAM); +// OpenABERNG rng; + std::string seed; + OpenABEByteString entropy, hashSeed; + entropy.fromHex("ff00de1f793fa5307ea2c3809a457c1cce25ed9eba2c320e7a1bd5fb72aeeeaa"); + cout << "Entropy len: " << entropy.size() << endl; + sha256ToHex(seed, "the seed"); + hashSeed.fromHex(seed); + OpenABECTR_DRBG rng(entropy); + rng.setSeed(hashSeed); + int large_num = 10000; + + try { + ZP a; + pgroup.initZP(a, 1234567890); + + int len = 0; + char *str = zml_bignum_toHex(pgroup.order, &len); + string s0 = string(str, len); + zml_bignum_safe_free(str); + cout << "order: " << s0 << endl; + + cout << "Output: a = " << a << endl; + cout << "Negation: -a = " << -a << endl; + cout << "a + -a = " << (a + -a) << endl; + + ZP c = a; + c.multInverse(); + cout << "c = inv(a) : " << c << endl; + cout << "a * c = " << (a * c) << endl; + + //OpenABERNG rng; + for (int i = 0; i < large_num; i++) { + ZP tmp = pgroup.randomZP(&rng); + } + ZP x = pgroup.randomZP(&rng); + cout << "x : " << x << endl; + + // test writing out bytestrings + OpenABEByteString z1, z2; + + z1 = x.getByteString(); + cout << "x in raw bin: " << z1.toHex() << endl; + + string s = x.getBytesAsString(); + cout << "x in str hex: " << s << endl; + + // serialize + x.serialize(z2); + cout << "x out: " << z2.toLowerHex() << endl; + ZP x1; + pgroup.initZP(x1, 0); + x1.deserialize(z2); + if (x == x1) { + cout << "ser/des OK. x = " << x1 << endl; + } else { + cout << "FAILED to deserialize correctly!" << endl; + } + + ZP y = pgroup.randomZP(&rng); + + ZP z = x * y; + cout << "z = x * y => " << z << endl; + ZP t = z / y; + cout << "(z / y) == x ? " << ((t == x) ? "true" : "false") << endl; + ZP u = z / x; + cout << "(z / x) == y ? " << ((u == y) ? "true" : "false") << endl; + + // test division by constants + cout << "x / 2 = " << x / ZP(2) << endl; + cout << "x / -2 = " << x / ZP(-2) << endl; + + cout << "power(x, 1234567890) => " << power(x, 1234567890) << endl; + cout << "power(x, a) => " << power(x, a) << endl; + + ZP zero, one, two; + pgroup.initZP(zero, 0); + pgroup.initZP(one, 1); + pgroup.initZP(two, 2); + + ZP z0 = (zero - one) / (two - one); + // ZP z0 = ((ZP(0) - ZP(1)) / (ZP(2) - ZP(1))); + cout << "z0: " << z0 << endl; + + if (z0.ismember()) + cout << "z0 is a member" << endl; + else + cout << "z0 is NOT a member" << endl; + + + } catch (OpenABE_ERROR& err) { + cout << "Caught error: " << ::OpenABE_errorToString(err) << " (" << err << ")" << endl; + result = err; + } + + // Return the result + return (result == OpenABE_NOERROR); +} + +bool +Test_G1_operations(const string& curve_id) +{ + Benchmark benchOps; + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEPairing pgroup(DEFAULT_BP_PARAM); +// OpenABERNG rng; + std::string seed; + OpenABEByteString entropy, hashSeed; + entropy.fromHex("ff00de1f793fa5307ea2c3809a457c1cce25ed9eba2c320e7a1bd5fb72aeeeaa01e6d0"); + sha256ToHex(seed, "the seed"); + hashSeed.fromHex(seed); + OpenABECTR_DRBG rng(entropy); + rng.setSeed(hashSeed); + + try { + G1 g = pgroup.randomG1(&rng); + cout << "g => " << g << endl; + + G1 h = g * g; + cout << "(mul) h = (g * g) => " << h << endl; + + G1 k = -h; + cout << "(negation) k = -h: " << k << endl; + + // expecting this to be true! (if not, what's wrong?) + G1 i = h / g; + cout << "(div) i == (h / g) => " << ((i == g) ? "true" : "false") << endl; + cout << "i => " << i << endl; + + ZP r = pgroup.randomZP(&rng); + benchOps.start(); + G1 a = g.exp(r); + benchOps.stop(); + cout << "(exp) a = (g^r) => " << a << endl; + cout << "(G1 exp time) " << benchOps.computeTimeInMilliseconds() << " ms" << endl; + OpenABEByteString tmp; + a.serialize(tmp); + cout << "serialized a => " << tmp.toHex() << endl; + + G1 b = pgroup.initG1(); + b.deserialize(tmp); + cout << "b (rec a) => " << b << endl; + + cout << "a == b ? " << ((a == b) ? "true" : "false") << endl; + + cout << "(membership check) a "; + if (a.ismember(pgroup.order)) { + cout << "is a member!" << endl; + } else { + cout << "is NOT a member!" << endl; + } + + // test hashing to G1 + OpenABEByteString f; + rng.getRandomBytes(&f, HASH_LEN); + G1 F = pgroup.hashToG1(f, "hello world!"); + cout << "(hash to G1) F => " << F << endl; + + G1 H = pgroup.hashToG1(f, "hello world1"); + cout << "(hash to G1) H => " << H << endl; + + if (F != H) { + cout << "Successful hashed two similar strings to different points." << endl; + } else { + cout << "COLLISION ERROR! Same value for different strings?!" << endl; + } + + } catch (OpenABE_ERROR& err) { + cout << "Caught error: " << ::OpenABE_errorToString(err) << " (" << err << ")" << endl; + result = err; + } + + // Return the result + return (result == OpenABE_NOERROR); +} + +bool +Test_G2_operations(const string& curve_id) +{ + Benchmark benchOps; + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEPairing pgroup(DEFAULT_BP_PARAM); +// OpenABERNG rng; + std::string seed; + OpenABEByteString entropy, hashSeed; + entropy.fromHex("ff00de1f793fa5307ea2c3809a457c1cce25ed9eba2c320e7a1bd5fb72aeeeaa01e6d0"); + sha256ToHex(seed, "the seed"); + hashSeed.fromHex(seed); + OpenABECTR_DRBG rng(entropy); + rng.setSeed(hashSeed); + + try { + G2 g = pgroup.randomG2(&rng); + cout << "g => " << g << endl; + + G2 h = g * g; + cout << "(mul) h = (g * g) => " << h << endl; + + G2 k = -h; + cout << "(negation) k = -h: " << k << endl; + + // expecting this to be true! (if not, what's wrong?) + G2 i = h / g; + cout << "(div) i == (h / g) => " << ((i == g) ? "true" : "false") << endl; + cout << "i => " << i << endl; + + ZP r = pgroup.randomZP(&rng); + benchOps.start(); + G2 a = g.exp(r); + benchOps.stop(); + cout << "(exp) a = (g^r) => " << a << endl; + cout << "(G2 exp time) " << benchOps.computeTimeInMilliseconds() << " ms" << endl; + + OpenABEByteString tmp; + a.serialize(tmp); + cout << "serialized a => " << tmp.toHex() << endl; + + G2 b = pgroup.initG2(); + b.deserialize(tmp); + cout << "b (rec a) => " << b << endl; + + cout << "a == b ? " << ((a == b) ? "true" : "false") << endl; + + cout << "(membership check) a "; + if (a.ismember(pgroup.order)) { + cout << "is a member!" << endl; + } else { + cout << "is NOT a member!" << endl; + } + + } catch (OpenABE_ERROR& err) { + cout << "Caught error: " << ::OpenABE_errorToString(err) << " (" << err << ")" << endl; + result = err; + } + + // Return the result + return (result == OpenABE_NOERROR); +} + +bool +Test_GT_operations(const string& curve_id) +{ + Benchmark benchOps; + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEPairing pgroup(DEFAULT_BP_PARAM); +// OpenABERNG rng; + std::string seed; + OpenABEByteString entropy, hashSeed; + entropy.fromHex("ff00de1f793fa5307ea2c3809a457c1cce25ed9eba2c320e7a1bd5fb72aeeeaa01e6d0"); + sha256ToHex(seed, "the seed"); + hashSeed.fromHex(seed); + OpenABECTR_DRBG rng(entropy); + rng.setSeed(hashSeed); + + try { + G1 g1 = pgroup.randomG1(&rng); + cout << "g1 => " << g1 << endl; + + G2 g2 = pgroup.randomG2(&rng); + cout << "g2 => " << g2 << endl; + + GT gt = pgroup.pairing(g1, g2); + cout << "gt => " << gt << endl; + + GT h = gt * gt; + cout << "(mul) h = (gt * gt) => " << h << endl; + + GT k = -h; + cout << "(negation) k = -h: " << k << endl; + + // expecting this to be true! (if not, what's wrong?) + GT i = h / gt; + cout << "(div) i == (h / gt) => " << ((i == gt) ? "true" : "false") << endl; + cout << "i => " << i << endl; + + ZP r = pgroup.randomZP(&rng); + benchOps.start(); + GT a = gt.exp(r); + benchOps.stop(); + cout << "(GT exp time) " << benchOps.computeTimeInMilliseconds() << " ms" << endl; + cout << "(exp) a = (gt^r) => " << a << endl; + + OpenABEByteString tmp; + a.serialize(tmp); + cout << "serialized a => " << tmp.toHex() << endl; + + GT b = pgroup.initGT(); + b.deserialize(tmp); + cout << "b (rec a) => " << b << endl; + + cout << "a == b ? " << ((a == b) ? "true" : "false") << endl; + + cout << "(membership check) a "; + if (a.ismember(pgroup.order)) { + cout << "is a member!" << endl; + } else { + cout << "is NOT a member!" << endl; + } + } catch (OpenABE_ERROR& err) { + cout << "Caught error: " << ::OpenABE_errorToString(err) << " (" << err << ")" << endl; + result = err; + } + + // Return the result + return (result == OpenABE_NOERROR); +} + + +bool +Test_BP_operations(const string& curve_id) +{ + Benchmark benchOps; + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEPairing pgroup(DEFAULT_BP_PARAM); + OpenABEByteString entropy; + entropy.fromHex("ff12de1f793fa5307ea2c3809a457c1cce25ed9eba2c320e7a1bd5fb72aeeeaa01e6d0"); + OpenABERNG rng; + //OpenABECTR_DRBG rng(entropy); + + try { + // pairing test + G1 g1 = pgroup.randomG1(&rng); + cout << "g1 => " << g1 << endl; + + G2 g2 = pgroup.randomG2(&rng); + cout << "g2 => " << g2 << endl; + + ZP a1 = pgroup.randomZP(&rng); + ZP b1 = pgroup.randomZP(&rng); + G1 g = g1.exp(a1); + G2 h = g2.exp(b1); + + benchOps.start(); + GT gta = pgroup.pairing(g, h); + benchOps.stop(); + cout << "gt => e(g1^a, g2^b) : " << gta << endl; + cout << "(pair time) " << benchOps.computeTimeInMilliseconds() << " ms" << endl; + + GT gtb = pgroup.pairing(g1, g2).exp(a1 * b1); + cout << "bp is correct: e(g1^a, g2^b) == e(g1, g2)^(ab) => " << (gta == gtb ? "true" : "false") << endl; + + // pairing and multi-pairing tests + vector g1s; + vector g2s; + // Generate a random element of G1, G2 and ZP + G1 p0 = pgroup.randomG1(&rng); + G1 p1 = pgroup.randomG1(&rng); + G2 q0 = pgroup.randomG2(&rng); + G2 q1 = pgroup.randomG2(&rng); + + GT gt1 = pgroup.pairing(p0, q0) * pgroup.pairing(p1, q1); + // cout << "pairing => " << gt1 << endl; + + g1s.push_back(p0); + g1s.push_back(p1); + g2s.push_back(q0); + g2s.push_back(q1); + + GT gt2 = pgroup.initGT(); + benchOps.start(); + pgroup.multi_pairing(gt2, g1s, g2s); + benchOps.stop(); + cout << "(multi pair time) " << benchOps.computeTimeInMilliseconds() << " ms" << endl; + + // cout << "pairing prod => " << gt2 << endl; + + if (gt1 == gt2) { + cout << "First test is a SUCCESS!" << endl; + } else { + cout << "Values don't match!!" << endl; + } + + g1s.clear(); + g2s.clear(); + ZP a = pgroup.randomZP(&rng); + ZP b = pgroup.randomZP(&rng); + ZP c = pgroup.randomZP(&rng); + ZP d = pgroup.randomZP(&rng); + + g1s.push_back(p0.exp(a)); + g1s.push_back(p0.exp(b)); + + g2s.push_back(q0.exp(c)); + g2s.push_back(q0.exp(d)); + + // e(g1^a, g2^c) * e(g1^b, g2^d) + GT gt3 = pgroup.pairing(g1s.at(0), g2s.at(0)) * pgroup.pairing(g1s.at(1), g2s.at(1)); + + GT gt4 = pgroup.initGT(); + pgroup.multi_pairing(gt4, g1s, g2s); + + if (gt3 == gt4) { + cout << "Second test is a SUCCESS!" << endl; + } else { + cout << "Values don't match!" << endl; + } + cout << "Test complete!" << endl; + // hash to G1 and G2 + } catch (OpenABE_ERROR& err) { + cout << "Caught error: " << ::OpenABE_errorToString(err) << " (" << err << ")" << endl; + result = err; + } + + // Return the result + return (result == OpenABE_NOERROR); +} + +int +Test_RunAllTests(const string& curve_id) +{ + gNumTests = gSuccessfulTests = 0; + int result = 0; + + // Run through all of the tests for the Zeutro Math Library + LogTestResult("library can be initialized", Test_InitializeLibrary, ""); + LogTestResult("ZP operations are correct", Test_ZP_operations, "Test_ZP_operations", curve_id); + +// LogTestResult("G1 operations are correct", Test_G1_operations, "Test_G1_operations", curve_id); +// LogTestResult("G2 operations are correct", Test_G2_operations, "Test_G2_operations", curve_id); +// LogTestResult("GT operations are correct", Test_GT_operations, "Test_GT_operations", curve_id); +// LogTestResult("Pairing operations are correct", Test_BP_operations, "Test_BP_operations", curve_id); + // The following test must be last! + LogTestResult("library can be shut down", Test_ShutdownLibrary, ""); + + // Summarize test results + if (gSuccessfulTests < gNumTests) { + cout << endl << "ERROR: SOME TESTS FAILED" << endl; + result = 1; + } + + cout << endl << gSuccessfulTests << " out of " << gNumTests << " tests passed." << endl << endl; + return result; +} + +int main(int argc, char **argv) +{ + string CURVE_ID = DEFAULT_BP_PARAM; + cout << "libopenabe v" << (OpenABE_LIBRARY_VERSION / 100.) << " test utility." << endl << endl; + if (argc == 2) { + CURVE_ID = string(argv[1]); + } + + if (CURVE_ID.compare("BN_P254") == 0 || CURVE_ID.compare("BN_P382") == 0) { + cout << "Testing '" << DEFAULT_MATH_LIB << "' with '" << CURVE_ID << "'" << endl; + return Test_RunAllTests(CURVE_ID); + } else { + cerr << "Invalid curve specified: " << CURVE_ID << endl; + return -1; + } +} diff --git a/src/test_zml2.cpp b/src/test_zml2.cpp new file mode 100644 index 00000000..999622c1 --- /dev/null +++ b/src/test_zml2.cpp @@ -0,0 +1,201 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file test_zml2.cpp +/// +/// \brief Unit testing utility for Zeutro Math Library +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(ENABLE_PROFILER) +#include +#endif + +using namespace std; +using namespace oabe; +using namespace oabe::crypto; + +#define COLOR_STR_GREEN "\033[32m" +#define COLOR_STR_NORMAL "\033[0m" +#define COLOR_STR_RED "\033[31m" + +#define EXIT(msg) cout << msg << endl; goto CLEANUP +#define NUM_PAIRING_TESTS 10 +#define ASSERT_RESULT(condition, msg) if(condition) { \ + cout << "FAIL: " << msg << endl; \ + return false; } + +// Global test counters +uint32_t gNumTests = 0; +uint32_t gSuccessfulTests = 0; + +////////// +// Utility routines +////////// + +void +LogTestResult(string testName, bool (*testPtr)(), const string fname) +{ + string colorGreen(COLOR_STR_GREEN); + string colorNormal(COLOR_STR_NORMAL); + string colorRed(COLOR_STR_RED); + + cout << "Testing if " << testName << "..." << endl; +#if defined(ENABLE_PROFILER) + if (fname != "") ProfilerStart(fname.c_str()); +#endif + bool testResult = testPtr(); +#if defined(ENABLE_PROFILER) + if (fname != "") ProfilerStop(); +#endif + if (testResult == true) { + cout << "\t" << colorGreen << "[PASS]" << colorNormal << endl; + gSuccessfulTests++; + } else { + cout << colorRed << "\t[FAIL]" << colorNormal << endl; + } + + gNumTests++; +} + +bool +Test_InitializeLibrary() +{ + InitializeOpenABE(); + return true; +} + +bool +Test_ShutdownLibrary() +{ + ShutdownOpenABE(); + return true; +} + +bool +Test_BP_EC_Group() +{ + OpenABE_ERROR err_code = OpenABE_NOERROR; + OpenABEEllipticCurve egroup(DEFAULT_EC_PARAM); + OpenABEPairing pgroup(DEFAULT_BP_PARAM); + OpenABERNG rng; + OpenABEByteString result; + + try { + G1 g = pgroup.randomG1(&rng); + cout << "(BPGroup) g: " << g << endl; + + ZP t = pgroup.randomZP(&rng); + G1 k = g.exp(t); + cout << "t: " << t << endl; + + t.serialize(result); + ZP s = pgroup.initZP(); + s.deserialize(result); + cout << "s: " << s << endl; + cout << "(s == t): " << ((s == t) ? "true" : "false") << endl; + + result.clear(); + k.serialize(result); + cout << "k bytes: " << result.toLowerHex() << endl; + G1 j = pgroup.initG1(); + j.deserialize(result); + cout << "(k == j): " << ((k == j) ? "true" : "false") << endl; + + // ECGroup tests + G_t h = egroup.getGenerator(); + cout << "(ECGroup) h : " << h << endl; + + ZP_t a = egroup.randomZP(&rng); + G_t A = h.exp(a); + cout << "A : " << A << endl; + result.clear(); + A.serialize(result); + cout << "A bytes: " << result.toLowerHex() << endl; + + G_t B = egroup.initG(); + B.deserialize(result); + cout << "B: " << B << endl; + + cout << "(A == B): " << ((A == B) ? "true" : "false") << endl; + + result.clear(); + a.serialize(result); + cout << "a: " << result.toLowerHex() << endl; + + ZP_t b = egroup.initZP(); + b.deserialize(result); + cout << "b: " << b << endl; + cout << "(a == b): " << ((a == b) ? "true" : "false") << endl; + + } catch (OpenABE_ERROR& err) { + cout << "Caught error: " << ::OpenABE_errorToString(err) << " (" << err << ")" << endl; + err_code = err; + } + + // Return the result + return (err_code == OpenABE_NOERROR); +} + +int +Test_RunAllTests() +{ + gNumTests = gSuccessfulTests = 0; + int result = 0; + + // Run through all of the tests for the Zeutro Math Library + LogTestResult("library can be initialized", Test_InitializeLibrary, ""); + LogTestResult("ECGroup and BPGroup work correctly in memory space", Test_BP_EC_Group, ""); + LogTestResult("library can be shut down", Test_ShutdownLibrary, ""); + + // Summarize test results + if (gSuccessfulTests < gNumTests) { + cout << endl << "ERROR: SOME TESTS FAILED" << endl; + result = 1; + } + + cout << endl << gSuccessfulTests << " out of " << gNumTests << " tests passed." << endl << endl; + return result; +} + +int main(int argc, char **argv) +{ + cout << "libopenabe v" << (OpenABE_LIBRARY_VERSION / 100.) << " test utility." << endl << endl; + cout << "Testing '" << DEFAULT_MATH_LIB << "' with '" << DEFAULT_BP_PARAM << "'" << endl; + + return Test_RunAllTests(); +} diff --git a/src/test_zsym.cpp b/src/test_zsym.cpp new file mode 100644 index 00000000..c1778e53 --- /dev/null +++ b/src/test_zsym.cpp @@ -0,0 +1,74 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . + + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace oabe; + +int main(int argc, char **argv) { + string the_key, derived_key, key_data, ciphertext, plaintext1, plaintext2; + + string the_key_str, derived_key_str; + cout << "Generate random key..." << endl; + crypto::generateSymmetricKey(the_key, 32); + the_key_str = crypto::printAsHex(the_key); + cout << "Key: " << the_key_str << endl; + + std::unique_ptr keyHandle(new crypto::OpenABESymKeyHandleImpl(the_key)); + keyHandle->exportKey(derived_key); + derived_key_str = crypto::printAsHex(derived_key); + cout << "Derived Key: " << derived_key_str << endl; + + // assert that key and derived key are not equal + if (the_key_str.compare(derived_key_str) != 0) { + cout << "Exported a different key!" << endl; + } + + // test encryption + plaintext1 = "this is plaintext!"; + keyHandle->encrypt(ciphertext, plaintext1); + + cout << "Ciphertext: " << crypto::printAsHex(ciphertext) << endl; + + // test decryption + keyHandle->decrypt(plaintext2, ciphertext); + + if (plaintext1 != plaintext2) { + cout << "Decryption failed!!" << endl; + return 1; + } + + cout << "Successful Decryption!" << endl; + return 0; +} diff --git a/src/tools/zlsss.cpp b/src/tools/zlsss.cpp new file mode 100644 index 00000000..9044f4cf --- /dev/null +++ b/src/tools/zlsss.cpp @@ -0,0 +1,685 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zlsss.cpp +/// +/// \brief Implementation for linear secret sharing. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// +/// + +#define __ZLSSS_CPP__ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABELSSS class + ********************************************************************************/ +namespace oabe { + +OpenABELSSSElement::OpenABELSSSElement(std::string label, ZP &element) + : m_Label(label), m_Element(element) { + std::pair pr = check_attribute(label); + this->m_Prefix = pr.first; +} + +/*! + * Constructor for the OpenABELSSS class. + * + */ + +OpenABELSSS::OpenABELSSS(OpenABEPairing *pairing, OpenABERNG *rng) : ZObject(), m_Pairing(pairing) +{ + this->debug = false; + this->m_Pairing->addRef(); + this->m_RNG = rng; + this->m_Pairing->initZP(zero, 0); +} + + +/*! + * Destructor for the OpenABECiphertext class. + * + */ + +OpenABELSSS::~OpenABELSSS() +{ + this->m_Pairing->deRef(); +} + +/*! + * Given a secret (an element of ZP) and a OpenABEFunctionInput describing + * the access structure, performs secret sharing over the given access + * structure. At present, the input must be a OpenABEPolicy. + * + * The result is a vector of elements (OpenABELSSSElement) each of which + * contains three values: a label (attribute name), a secret share, + * an a "unique label" (attribute name made unique to deal with the + * fact that multiple + + recorded within the OpenABELSSS object and may be + * obtained using the getRows() method. + * + * @param[in] input - OpenABEFunctionInput object describing the access structure + * @param[in] elt - a ZP object to share + * @throw - an exception if there is a problem sharing the element + */ + +void +OpenABELSSS::shareSecret(const OpenABEFunctionInput *input, ZP &elt) +{ + // Verify that the input is a supported type (OpenABEPolicy) + const OpenABEPolicy *policy = dynamic_cast(input); + if (policy == nullptr) { + OpenABE_LOG_AND_THROW("Sharing input must be a Policy", OpenABE_ERROR_INVALID_INPUT); + } + // Clear any existing results + this->clearExistingResults(); + + // Recursively share the secret + this->performSecretSharing(policy, elt); +// { +// // If there was an error, clear any partial results and +// // throw a general exception +// this->m_ResultMap.clear(); +// OpenABE_LOG_AND_THROW("Could not share secret", OpenABE_ERROR_SECRET_SHARING_FAILED); +// } +} + +/*! + * Given an access structure (policy) and an input (attribute list) + * generates the coefficients necessary to recover the secret. + * In the present implementation left must be a policy and right must + * an attribute list. + * + * @param[in] policy - OpenABEPolicy object describing the access structure + * @param[in] attrList - OpenABEAttributeList object describing the attribute list + * @throw - an exception if there is a problem with recovery + */ + +bool +OpenABELSSS::recoverCoefficients(OpenABEPolicy *policy, OpenABEAttributeList *attrList) +{ + ASSERT_NOTNULL(policy); + ASSERT_NOTNULL(attrList); + // Clear any existing results + this->clearExistingResults(); + + // Recursively compute the coefficients + if (this->performCoefficientRecovery(policy, attrList) == false) { + // If there was an error, clear any partial results and + // return false (indicating failure). + this->m_ResultMap.clear(); + + // Return false + return false; + } + + // Success, return true + return true; +} + +/*! + * Utility routine. Given an access structure (policy) and an element, + * perform secret sharing on the given element. + * + * @param[in] left - OpenABEFunctionInput object describing the access structure + * @param[in] right - OpenABEFunctionInput object describing the input + * @throw - an exception if there is a problem sharing the element + */ + +void +OpenABELSSS::performSecretSharing(const OpenABEPolicy *policy, ZP &elt) +{ + OpenABETreeNode *node = NULL; + + if(policy->hasDuplicateNodes()) { + policy->getDuplicateInfo(this->m_AttrCount); + } + + node = policy->getRootNode(); + assert(node != NULL); + + iterativeShareSecret(node, elt); +} + +/*! + * Recursive helper routine. Given a node within a policy tree and an element + * to be shared, compute the secret shares of all sub-nodes. Then recurse + * on each one. + * + * @param[in] node - OpenABETreeNode object describing the node + * @param[in] elt - Element to be secret shared + * @throw - an exception if there is a problem sharing the element + */ + +bool +OpenABELSSS::performCoefficientRecovery(OpenABEPolicy *policy, OpenABEAttributeList *attrList) +{ + OpenABETreeNode *node = NULL; + + if(policy->hasDuplicateNodes()) { + policy->getDuplicateInfo(this->m_AttrCount); + } + + node = policy->getRootNode(); + assert(node != NULL); + + // First, scan down through the tree to identify which leaves must be satisfied + // in order to recover the secret. We will need to compute one coefficient + // for each leaf. The result is stored as a 'mark' in each tree node -- + // from the leaves up to the root. + bool result = iterativeScanTree(node, attrList); + if(!result) { + OpenABE_LOG("Insufficient attributes to recover the secret key."); + return result; + } + + // Now that we've marked the nodes, we need to parse back down to the root, + // computing the necessary coefficients at each stage. When we hit a leaf node, + // the coefficient will be added to the m_ResultMap result list. + ZP one; + this->m_Pairing->initZP(one, 1); + return iterativeCoefficientRecover(node, one); +} + +/*! + * Utility routine (iterative version). Given an access structure (policy) and an element, + * perform secret sharing on the given element. + * + * @param[in] treeNode - OpenABETreeNode for the subtree + * @param[in] elt - ZP to be shared + * @return - bool indicating success/failure + * @throw - an exception if there is a problem sharing the element + */ + +void +OpenABELSSS::iterativeShareSecret(OpenABETreeNode *treeNode, ZP &elt) +{ + std::stack nodes; + std::stack eltList; + OpenABETreeNode *visitedNode = NULL; + ZP theSecret, coefficient; + this->m_Pairing->initZP(theSecret, 0); + this->m_Pairing->initZP(coefficient, 0); + // push the root to the stack + nodes.push(treeNode); + eltList.push(elt); + OpenABEElementList coefficients; + + do { + uint32_t threshold = 0, totalSubnodes = 0; + coefficients.clear(); + + visitedNode = nodes.top(); + theSecret = eltList.top(); + nodes.pop(); + eltList.pop(); + ASSERT_NOTNULL(visitedNode); + + // Base case: + // If the node is a leaf node, simply add the given element to the results + // and return. + if (visitedNode->getNodeType() == GATE_TYPE_LEAF) { + this->addShareToResults(visitedNode, theSecret); + } + else { + // First convert this node into a pair of values "threshold" and + // "totalSubnodes" such that any "threshold"--out-of-"totalSubnodes" + // shares permit secret recovery. + totalSubnodes = visitedNode->getNumSubnodes(); + assert((threshold = visitedNode->getThresholdValue()) != 0); + + // Generate a polynomial consisting of "threshold" coefficients + for (uint32_t i = 0; i < threshold; i++) { + // Each coefficient is a random element of same field + // as the element + ZP coefficient = this->m_Pairing->randomZP(this->m_RNG); + coefficients.push_back(coefficient); + } + // set position 0 as the passed in secret + coefficients[0] = theSecret; + // Now evaluate the polynomial at points (1, 2, ..., totalSubnodes) to + // obtain the shares + for (uint32_t i = 0; i < totalSubnodes; i++) { + // Evaluate the polynomial at point (i+1) and recurse on the resulting value + ZP share = this->evaluatePolynomial(coefficients, (i+1)); + nodes.push(visitedNode->getSubnode(i)); + eltList.push(share); + } + } + } while(!nodes.empty()); + + coefficients.clear(); +} + +/*! + * Utility routine (iterative version). Given an access structure (policy) where each node has been + * 'marked' if it's necessary to recover the secret, move through and calculate + * the coefficients for each leaf node. + * + * @param[in] treeNode - OpenABETreeNode for the subtree + * @param[in] inCoeff - ZP to be shared + * @return - bool indicating success/failure + * @throw - an exception if there is a problem sharing the element + */ + +bool +OpenABELSSS::iterativeCoefficientRecover(OpenABETreeNode *treeNode, ZP &inCoeff) +{ + std::stack nodes; + std::stack coeffs; + OpenABETreeNode *visitedNode = NULL; + ZP tmpInCoeff, coefficient; + this->m_Pairing->initZP(tmpInCoeff, 0); + this->m_Pairing->initZP(coefficient, 0); + // push the root to the stack + nodes.push(treeNode); + coeffs.push(inCoeff); + bool result = false; + + do { + uint32_t threshold = 0; + + visitedNode = nodes.top(); + tmpInCoeff = coeffs.top(); + nodes.pop(); + coeffs.pop(); + ASSERT_NOTNULL(visitedNode); + + // Base case: + // If the node is a leaf node, simply add the input coefficient to the results + // and return. + if (visitedNode->getNodeType() == GATE_TYPE_LEAF) { + this->addShareToResults(visitedNode, tmpInCoeff); + result = true; + } + else { + // First get the number of subnodes for this tree node. + uint32_t numSubnodes = visitedNode->getNumSubnodes(); + + // Process the node according to its type + switch (visitedNode->getNodeType()) { + case GATE_TYPE_AND: + threshold = numSubnodes; // AND gate: all subnodes satisfied + break; + case GATE_TYPE_OR: + threshold = 1; // OR gate: any one subnodes satisfied + break; +#if 0 + case GATE_TYPE_THRESHOLD: + threshold = visitedNode->getThresholdValue(); + break; + default: + // Unrecognized node type + OpenABE_LOG_AND_THROW("Unrecognized node type", OpenABE_ERROR_SECRET_SHARING_FAILED); + break; +#endif + } + + // Now for each subnode in our list, calculate the coefficient and recurse + for (uint32_t i = 0; i < numSubnodes; i++) { + if(visitedNode->getSubnode(i)->getMark() == true) { + // compute coefficient for this node + coefficient = tmpInCoeff * calculateCoefficient(visitedNode, i, threshold, numSubnodes); + nodes.push(visitedNode->getSubnode(i)); + coeffs.push(coefficient); + result = true; + } + } + } + } while(!nodes.empty()); + + return result; +} + + +/*! + * Utility routine. Calculates a Lagrange interpolation coefficient for + * share "index" out of "total" shares for a "threshold" secret sharing. + * + * @param[in] index - Index of the coefficient + * @param[in] threshold - Threshold value + * @param[in] total - Total number of elements + * @return - An element containing the coefficient + * @throw - an exception if there is a problem sharing the element + */ + +ZP +OpenABELSSS::calculateCoefficient(OpenABETreeNode *treeNode, uint32_t index, uint32_t threshold, uint32_t total) +{ + ZP result; + this->m_Pairing->initZP(result, 1); + this->m_Pairing->initZP(this->indexPlusOne, index + 1); + + // Product for all marked subnodes (excluding index) of ( (0 - (X(i))) / (X(subnode_index) - (X(i))) ) + // Note that X(i) = i+1. + for (uint32_t i = 0; i < threshold; i++) { + /* Check if this subnode is being used for the recovery. */ + this->m_Pairing->initZP(this->iPlusOne, i + 1); + if (treeNode->getSubnode(i)->getMark() == true) { + if (i != index) { + result *= result * ((this->zero - this->iPlusOne) / (this->indexPlusOne - this->iPlusOne)); + } + } + } + + return result; +} + +/*! + * Utility routine. Add a share to the internal secret sharing results vector. + * + * @param[in] treeNode - OpenABETreeNode object containing label of the leaf node + * @param[in] elt - The secret share + * @return - false if there is an error + * @throw - an exception if there is a problem sharing the element + */ + +void +OpenABELSSS::addShareToResults(OpenABETreeNode *treeNode, ZP &elt) +{ + OpenABELSSSElement lsssElement(treeNode->getCompleteLabel(), elt); + this->m_ResultMap[this->makeUniqueLabel(treeNode)] = lsssElement; + // JAA: uncomment to debug labels + // cout << "Unique label: " << this->makeUniqueLabel(treeNode) << endl; + // cout << treeNode->getCompleteLabel() << " -> " << elt << endl; +} + +/*! + * Evaluate a polynomial at a specified (integer) x coordinate. Takes a list of coefficients + * and the x-coord as a uint32_t. + * + * @param[in] coefficients - OpenABEElementList object containing the coordinates + * @param[in] x - The x coordinate to evaluate + * @return - A ZP containing the result + * @throw - an exception if there is a problem + */ + +ZP +OpenABELSSS::evaluatePolynomial(OpenABEElementList &coefficients, + uint32_t x) +{ + // Make sure the coefficients vector is non-trivial + assert(coefficients.size() > 0); +// { +// OpenABE_LOG_AND_THROW("Coefficients vector has no elements", OpenABE_ERROR_SECRET_SHARING_FAILED); +// } + + ZP share, xpow; + this->m_Pairing->initZP(share, 0); + this->m_Pairing->initZP(xpow, x); + unsigned int i = 0; + + for (OpenABEElementListIterator it = coefficients.begin(); it != coefficients.end(); ++it) { + share += ( *it * power(xpow, i) ); + //JAA cout << "coeff = " << *it << " at x = " << xpow << ", i = " << i << endl; + i++; + } + + return share; +} + +/*! + * Utility routine. If the label has previously been used, it makes a new + * (unique) label by concatenating the label with the number of times + * this label has been used, e.g.: + * Label "attribute" has not been used before: "0%attribute". + * Label "attribute" has been used 1 time: "1%attribute". Etc. + * + * @param[in] label - string containing the label + * @return - unique label + */ + +string +OpenABELSSS::makeUniqueLabel(const OpenABETreeNode *treeNode) +{ + // get the label + string label = treeNode->getCompleteLabel(); + // if the label is duplicated in the policy tree, then add index + if(this->m_AttrCount.count(label) != 0) { + return label + "%" + to_string(treeNode->getIndex()); + } + return label; +} + +/*! + * Utility routine (iterative version). Given an attribute list, scan the entire tree, 'marking' nodes that are + * required to satisfy the policy. Returns the number of leaves required to satisfy this + * subtree. + * + * @param[in] treeNode - root of the subtree + * @return - number of leaves required to satisfy this subtree + */ + +bool iterativeScanTree(OpenABETreeNode *treeNode, OpenABEAttributeList *attributeList) +{ + uint32_t threshold; + std::stack nodes; + OpenABETreeNode *topNode = NULL; + bool isInternalNode, allSubnodesVisited; + + nodes.push(treeNode); + + while(!nodes.empty()) { + isInternalNode = true; + // peek at the top + topNode = nodes.top(); + ASSERT_NOTNULL(topNode); + switch (topNode->getNodeType()) { + case GATE_TYPE_AND: + // AND gate: all subnodes must be present to satisfy subtree + threshold = topNode->getNumSubnodes(); + break; + case GATE_TYPE_OR: + // OR gate: any one subnode will satisfy the entire subtree + threshold = 1; + break; +#if 0 + case GATE_TYPE_THRESHOLD: + // THRESHOLD gate: any k-of-n subnodes will satisfy the entire subtree + threshold = topNode->getThresholdValue(); + break; +#endif + case GATE_TYPE_LEAF: + isInternalNode = false; + break; + default: + // Unrecognized node type + OpenABE_LOG_AND_THROW("Unrecognized node type", OpenABE_ERROR_SECRET_SHARING_FAILED); + break; + } + + allSubnodesVisited = true; + if (isInternalNode) { + for (uint32_t i = 0; i < topNode->getNumSubnodes(); i++) { + // push all the subnodes on the stack (that we have not visited so far) + if(!topNode->getSubnode(i)->m_Visited) { + nodes.push(topNode->getSubnode(i)); + allSubnodesVisited = false; + } + } + } else { + // Visit the node + // This is a leaf node, so let's see if there's a match + // cout << "Find attribute: " << topNode->getLabel() << " in " << attributeList->toString() << endl; + // cout << "Result: " << attributeList->matchAttribute(topNode->getLabel()) << endl; + bool leaf_matched = attributeList->matchAttribute(topNode->getCompleteLabel()); + topNode->setMark(leaf_matched, leaf_matched ? 1 : 0); + // mark this node as visited then pop from the stack + topNode->m_Visited = true; + nodes.pop(); + } + + if (allSubnodesVisited && isInternalNode) { + // visit the internal node + determineIfNodeShouldBeMarked(threshold, topNode); + // bool internal_node_satisfied = determineIfNodeShouldBeMarked(threshold, topNode); + // if (internal_node_satisfied) { + // cout << "Gate satisfied. Num matches: " << topNode->getNumSatisfied() endl; + // } + topNode->m_Visited = true; + nodes.pop(); + } + } + + // cout << "Satisfied: " << (treeNode->getMark() ? "true" : "false") << endl; + // cout << "How many matches: " << treeNode->getNumSatisfied() << endl; + return treeNode->getMark(); +} + +// comparator for pair of integers +struct less_than { + bool operator()(const std::pair &left, const std::pair &right) { + return (left.second < right.second); + } +}; + +bool determineIfNodeShouldBeMarked(uint32_t threshold, OpenABETreeNode *node) +{ + vector> list; + uint32_t enough_nodes = threshold, cnt = 0; + bool result; + if (node->getNodeType() == GATE_TYPE_AND) { + // mark this node as being satisfied (at first) + result = true; + int sum = 0; + for(uint32_t i = 0; i < node->getNumSubnodes(); i++) { + if(!node->getSubnode(i)->getMark()) { + // mark this node as not being satisfied + // (found at least one unmatched subnode) + result = false; + } + sum += node->getSubnode(i)->getNumSatisfied(); + } + + if (result) { + node->setMark(result, sum); + } else { + node->setMark(false, 0); + } + } else if(node->getNodeType() == GATE_TYPE_OR) { + result = false; + // build up list + for (uint32_t i = 0; i < node->getNumSubnodes(); i++) { + cnt = node->getSubnode(i)->getNumSubnodes(); + if(cnt == 0) { + cnt++; + } + // only sorting nodes that are marked 'true' + if (node->getSubnode(i)->getMark()) { + list.push_back(std::make_pair(i, cnt)); + } + } + // sort the list (usually size 2) + std::sort(list.begin(), list.end(), less_than()); + uint32_t i; + // iterate through list in increasing order of subnodes to + // determine satisfiability of subtree + for (size_t k = 0; k < list.size(); k++) { + i = list[k].first; + // cout << "index: " << i << ", subnodes: " << list[k].second << + // ", satisfied: " << (node->getSubnode(i)->getMark() ? "true": "false") << endl; + if (node->getSubnode(i)->getMark() && enough_nodes > 0) { + enough_nodes--; + result = true; + } else if(node->getSubnode(i)->getMark() && enough_nodes == 0) { + // mark remaining nodes as false + node->getSubnode(i)->setMark(false, 0); + } + } + + if (result) { + node->setMark(result, list[0].second); + } else { + node->setMark(false, 0); + } + } + else { + result = false; + } + + return result; +} + +pair checkIfSatisfied(OpenABEPolicy *policy, OpenABEAttributeList *attr_list, bool reset_flags) { + ASSERT_NOTNULL(policy); + ASSERT_NOTNULL(attr_list); + // check whether list satisfies the policy + bool isSatisfied = iterativeScanTree(policy->getRootNode(), attr_list); + int numNodesSatisfied = policy->getRootNode()->getNumSatisfied(); + // reset flags + if(reset_flags) { + resetFlags(policy->getRootNode()); + } + // return result of check + return make_pair(isSatisfied, numNodesSatisfied); +} + + +#ifndef OpenABE_NO_TEST_ROUTINES + +// +// Used for testing only +// + +ZP +OpenABELSSS::LSSStestSecretRecovery(const OpenABELSSSRowMap& coefficients, const OpenABELSSSRowMap& shares) { + // Set 'result' to zero + ZP result; + this->m_Pairing->initZP(result, 0); + + // For each share, find the matching coefficient + for(OpenABELSSSRowMap::const_iterator shareIt = shares.begin(); shareIt != shares.end(); ++shareIt) { + // First identify the coefficient that matches this share + OpenABELSSSRowMap::const_iterator coeffIt = coefficients.find(shareIt->first); + if (coeffIt == coefficients.end()) { + // OpenABE_LOG_AND_THROW("Could not find a matching coefficient in the list", OpenABE_ERROR_SECRET_SHARING_FAILED); + // Note: this condition occurs in one of two situations: + // 1) there is legitimately a missing coefficient in the list (due to recoveryCoefficient error) + // 2) we are dealing with an OR policy, in which case only 1 of the coefficients is necessary to recover secret + continue; + } + + // Now compute result += (share * coeff) + result += (coeffIt->second.element() * shareIt->second.element()); + } + + return result; +} +#endif + +} diff --git a/src/tools/zprng.cpp b/src/tools/zprng.cpp new file mode 100644 index 00000000..28bd19e6 --- /dev/null +++ b/src/tools/zprng.cpp @@ -0,0 +1,452 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zprng.cpp +/// +/// \brief Implementation for OpenABE RNG/PRNG +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEPRNG class + ********************************************************************************/ +namespace oabe { + +OpenABERNG::OpenABERNG(): ZObject() { +} + +OpenABERNG::~OpenABERNG() { +} + +/******************************************************************************** + * Implementation of the OpenABEPRNG class + ********************************************************************************/ + +static void AesEvpBlockEncrypt(const EVP_CIPHER *cipher, const uint8_t* key, + const uint8_t* pl_ptr, uint8_t *ct_ptr, size_t pl_len) { + ASSERT_NOTNULL(cipher); + EVP_CIPHER_CTX *ctx = nullptr; + ctx = EVP_CIPHER_CTX_new(); + EVP_CIPHER_CTX_set_padding(ctx, false); + // note that cipher AND key must be in sync (key len should be appropriate input size of + // cipher (e.g., 128-bits by default) + EVP_EncryptInit_ex (ctx, cipher, NULL, (uint8_t*)key, NULL); + + int olen = 512, tmp_len, out_len; + uint8_t out[olen]; + memset(out, 0, olen); + EVP_EncryptUpdate(ctx, out, &tmp_len, (uint8_t*) pl_ptr, (int)pl_len); + + EVP_EncryptFinal_ex(ctx, out + tmp_len, &out_len); + // check that tmp_len == out_len + // copy back the output ciphertext + memcpy(ct_ptr, out, out_len); + // cleanup memory + EVP_CIPHER_CTX_free(ctx); +} + +static void AES_ECB(const uint8_t *key, const uint8_t *plaintext, uint8_t *ciphertext, size_t len) { + // make sure key and plaintext are of sufficient length + const EVP_CIPHER *cipher = EVP_aes_256_ecb(); + AesEvpBlockEncrypt(cipher, key, plaintext, ciphertext, len); +} + +//static void AES_CTR(const uint8_t *key, const uint8_t *plaintext, size_t len) { +// // 1. need an IV too here +// // 2. make sure key and plaintext are of sufficient length +// AesEvpBlockEncrypt(EVP_aes_256_ctr(), key, plaintext, len); +//} + +static void initCtrDrbgContext(OpenABECtrDrbg& ctx, uint8_t *key, size_t key_len) { + memcpy(ctx->key, key, key_len); + OpenABEZeroize(ctx->counter, AES_BLOCK_SIZE); + ctx->reseed_counter = 0; + ctx->reseed_interval = OpenABE_CTR_DRBG_RESEED_INTERVAL; +} + +static void clearCtrDrbgContext(OpenABECtrDrbg& ctx) { + OpenABEZeroize(ctx->key, OpenABE_CTR_DRBG_KEYSIZE_BYTES); + OpenABEZeroize(ctx->counter, AES_BLOCK_SIZE); + ctx->reseed_counter = 0; + ctx->reseed_interval = 0; + ctx->entropy_src = NULL; + ctx->entropy_callback = NULL; +} + +int ctr_drbg_seed_entropy_len(OpenABECtrDrbg& ctx, + int (*entropy_callback)(void *, unsigned char *, size_t), + void *entropy_src, + const uint8_t *person_string, + size_t person_string_len, + size_t entropy_len) { + int result; + + uint8_t key[OpenABE_CTR_DRBG_KEYSIZE_BYTES]; + memset(key, 0, OpenABE_CTR_DRBG_KEYSIZE_BYTES); + // Initialize with an empty key + initCtrDrbgContext(ctx, key, OpenABE_CTR_DRBG_KEYSIZE_BYTES); + // Set the entropy callback function + ctx->entropy_callback = entropy_callback; + // Set the entropy source buffer + ctx->entropy_src = entropy_src; + // Set the entropy length + ctx->entropy_len = entropy_len; + // Do an initial reseed + if ((result = ctr_drbg_reseed(ctx, person_string, person_string_len)) != 0) + return result; + return 0; +} + +//static void debug(const string msg, uint8_t *buf, size_t len) { +// OpenABEByteString tmp_buf; +// tmp_buf.appendArray(buf, len); +// cout << msg << tmp_buf.toLowerHex() << endl; +//} + +static int block_cipher_df(uint8_t *output, const uint8_t *data, size_t data_len) { + int max_buf_len = OpenABE_CTR_DRBG_MAX_SEED_INPUT + OpenABE_CTR_DRBG_BLOCKSIZE + 16; + uint8_t buf[max_buf_len]; + uint8_t tmp[OpenABE_CTR_DRBG_SEEDLEN]; + uint8_t key[OpenABE_CTR_DRBG_KEYSIZE_BYTES]; + uint8_t chain[OpenABE_CTR_DRBG_BLOCKSIZE]; + uint8_t *p, *iv; + size_t i, j; + size_t buf_len, use_len; + + if (data_len > OpenABE_CTR_DRBG_MAX_SEED_INPUT) + return OpenABE_ERR_CTR_DRBG_INPUT_TOO_BIG; + + memset(buf, 0, max_buf_len); + /* + * Construct IV (16 bytes) and S in buffer + * IV = Counter (in 32-bits) padded to 16 with zeroes + * S = Length input string (in 32-bits) || Length of output (in 32-bits) || + * data || 0x80 + * (Total is padded to a multiple of 16-bytes with zeroes) + */ + p = buf + OpenABE_CTR_DRBG_BLOCKSIZE; + *p++ = ( data_len >> 24 ) & 0xFF; + *p++ = ( data_len >> 16 ) & 0xFF; + *p++ = ( data_len >> 8 ) & 0xFF; + *p++ = ( data_len ) & 0xFF; + p += 3; + *p++ = OpenABE_CTR_DRBG_SEEDLEN; + memcpy(p, data, data_len); + p[data_len] = 0x80; + + buf_len = OpenABE_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1; + + for (i = 0; i < OpenABE_CTR_DRBG_KEYSIZE_BYTES; i++) { + key[i] = i; + } + + // Reduce data to OpenABE_CTR_DRBG_SEEDLEN bytes of data + for (j = 0; j < OpenABE_CTR_DRBG_SEEDLEN; j += OpenABE_CTR_DRBG_BLOCKSIZE) { + p = buf; + memset(chain, 0, OpenABE_CTR_DRBG_BLOCKSIZE); + use_len = buf_len; + + while (use_len > 0) { + for (i = 0; i < OpenABE_CTR_DRBG_BLOCKSIZE; i++) + chain[i] ^= p[i]; + p += OpenABE_CTR_DRBG_BLOCKSIZE; + use_len -= (use_len >= OpenABE_CTR_DRBG_BLOCKSIZE) ? + OpenABE_CTR_DRBG_BLOCKSIZE : use_len; + // Block encrypt + AES_ECB(key, chain, chain, OpenABE_CTR_DRBG_BLOCKSIZE); + } + + memcpy(tmp + j, chain, OpenABE_CTR_DRBG_BLOCKSIZE); + // Update IV + buf[3]++; + } + + // Final encryption with reduced data + memcpy(key, tmp, OpenABE_CTR_DRBG_KEYSIZE_BYTES); + iv = tmp + OpenABE_CTR_DRBG_KEYSIZE_BYTES; + p = output; + + for (j = 0; j < OpenABE_CTR_DRBG_SEEDLEN; j += OpenABE_CTR_DRBG_BLOCKSIZE) { + // Block encrypt + AES_ECB(key, iv, iv, OpenABE_CTR_DRBG_BLOCKSIZE); + memcpy(p, iv, OpenABE_CTR_DRBG_BLOCKSIZE); + p += OpenABE_CTR_DRBG_BLOCKSIZE; + } + + return 0; +} + +static int update_internal(OpenABECtrDrbg& ctx, const uint8_t data[OpenABE_CTR_DRBG_SEEDLEN]) { + unsigned char tmp[OpenABE_CTR_DRBG_SEEDLEN]; + unsigned char *p = tmp; + size_t i, j; + + memset( tmp, 0, OpenABE_CTR_DRBG_SEEDLEN ); + + for (j = 0; j < OpenABE_CTR_DRBG_SEEDLEN; j += OpenABE_CTR_DRBG_BLOCKSIZE) { + // Increase counter + for (i = OpenABE_CTR_DRBG_BLOCKSIZE; i > 0; i--) + if (++ctx->counter[i - 1] != 0) + break; + + // Encrypt counter block + AES_ECB(ctx->key, ctx->counter, p, OpenABE_CTR_DRBG_BLOCKSIZE); + p += OpenABE_CTR_DRBG_BLOCKSIZE; + } + + for (i = 0; i < OpenABE_CTR_DRBG_SEEDLEN; i++) { + tmp[i] ^= data[i]; + } + + // Update key and counter + memcpy(ctx->key, tmp, OpenABE_CTR_DRBG_KEYSIZE_BYTES); + memcpy(ctx->counter, tmp + OpenABE_CTR_DRBG_KEYSIZE_BYTES, OpenABE_CTR_DRBG_BLOCKSIZE ); + + return 0; +} + +void ctr_drbg_update(OpenABECtrDrbg& ctx, const uint8_t *additional, size_t add_len) { + uint8_t add_input[OpenABE_CTR_DRBG_SEEDLEN]; + + if (add_len > 0) { + if (add_len > OpenABE_CTR_DRBG_MAX_SEED_INPUT) { + add_len = OpenABE_CTR_DRBG_MAX_SEED_INPUT; + } + block_cipher_df(add_input, additional, add_len); + // Update internal state of K and V + update_internal(ctx, add_input); + } +} + +int ctr_drbg_reseed(OpenABECtrDrbg& ctx, const uint8_t *additional, size_t len) { + uint8_t seed[OpenABE_CTR_DRBG_MAX_SEED_INPUT]; + size_t seedlen = 0; + // make sure entropy len is less than max input + if (ctx->entropy_len + len > OpenABE_CTR_DRBG_MAX_SEED_INPUT) { + return OpenABE_ERR_CTR_DRBG_INPUT_TOO_BIG; + } + memset(seed, 0, OpenABE_CTR_DRBG_MAX_SEED_INPUT); + // Copy entropy_len bytes of entropy to seed + if (ctx->entropy_callback(ctx->entropy_src, seed, ctx->entropy_len) != 0) { + return OpenABE_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED; + } + seedlen += ctx->entropy_len; + // Add additional data (only if additional is not null) + if (additional && len) { + memcpy(seed + seedlen, additional, len); + seedlen += len; + } + + // Reduce or stretch to 384 bits + block_cipher_df(seed, seed, seedlen); + // Update internal state of K and V + update_internal(ctx, seed); + // Reset the reseed counter + ctx->reseed_counter = 1; + return 0; +} + +int ctr_drbg_init_seed(OpenABECtrDrbg& ctx, + int (*entropy_callback)(void *, uint8_t *, size_t), + OpenABEByteString& entropy_source_buf, + const uint8_t *nonce, + size_t nonce_len) { + // make sure entropy_source_buf is right length + if (entropy_source_buf.size() < OpenABE_CTR_DRBG_ENTROPYLEN) { + throw OpenABE_ERROR_INVALID_LENGTH; + } + return ctr_drbg_seed_entropy_len(ctx, entropy_callback, (uint8_t *)entropy_source_buf.getInternalPtr(), + nonce, nonce_len, + OpenABE_CTR_DRBG_ENTROPYLEN); +} + +int ctr_drbg_generate_random_with_add(OpenABECtrDrbg& ctx, uint8_t *output, size_t output_len, + const uint8_t *additional, size_t add_len) { + int ret = 0; + uint8_t add_input[OpenABE_CTR_DRBG_SEEDLEN]; + uint8_t *p = output; + uint8_t tmp[OpenABE_CTR_DRBG_BLOCKSIZE]; + int i; + size_t use_len; + + if (output_len > OpenABE_CTR_DRBG_MAX_REQUEST) { + return OpenABE_ERR_CTR_DRBG_REQUEST_TOO_BIG; + } + if (add_len > OpenABE_CTR_DRBG_MAX_INPUT_LENGTH) { + return OpenABE_ERR_CTR_DRBG_INPUT_TOO_BIG; + } + memset(add_input, 0, OpenABE_CTR_DRBG_SEEDLEN); + + // Reseed if counter is greater than reseed interval + if (ctx->reseed_counter > ctx->reseed_interval) { + if ((ret = ctr_drbg_reseed(ctx, additional, add_len)) != 0) + return ret; + add_len = 0; + } + + if (add_len > 0) { + // Reduce additional input to 384-bits (default) + block_cipher_df(add_input, additional, add_len); + // Update internal state of K and V + update_internal(ctx, add_input); + } + + while (output_len > 0) { + // Increase counter + for (i = OpenABE_CTR_DRBG_BLOCKSIZE; i > 0; i--) { + if(++ctx->counter[i - 1] != 0) + break; + } + // Block_encrypt + AES_ECB(ctx->key, ctx->counter, tmp, OpenABE_CTR_DRBG_BLOCKSIZE); + use_len = (output_len > OpenABE_CTR_DRBG_BLOCKSIZE) ? OpenABE_CTR_DRBG_BLOCKSIZE : + output_len; + // Copy random block to destination + memcpy(p, tmp, use_len); + p += use_len; + output_len -= use_len; + } + // Update internal K and V + update_internal(ctx, add_input); + ctx->reseed_counter++; + + return 0; +} + +OpenABECtrDrbgContext::OpenABECtrDrbgContext(OpenABEByteString &entropy) { + ctx_.reset(new OpenABECtrDrbg_); + ASSERT(entropy.size() >= OpenABE_CTR_DRBG_ENTROPYLEN, OpenABE_ERROR_INVALID_LENGTH); + short_entropy_ = entropy; +} + +OpenABECtrDrbgContext::OpenABECtrDrbgContext(const uint8_t *entropy, uint32_t entropy_len) { + ctx_.reset(new OpenABECtrDrbg_); + ASSERT(entropy_len >= OpenABE_CTR_DRBG_ENTROPYLEN, OpenABE_ERROR_INVALID_LENGTH); + short_entropy_.appendArray((uint8_t *)entropy, entropy_len); +} + +OpenABECtrDrbgContext::~OpenABECtrDrbgContext() { + short_entropy_.zeroize(); + clearCtrDrbgContext(ctx_); +} + +void +OpenABECtrDrbgContext::initSeed(int (*entropy_func)(void *, uint8_t *, size_t), + const uint8_t *nonce, size_t nonce_len) { + ctr_drbg_init_seed(ctx_, entropy_func, short_entropy_, nonce, nonce_len); +} + +static int entropy_callback(void *data, uint8_t *target_buf, size_t target_len) { + const uint8_t *src = (uint8_t *)data; + memcpy(target_buf, src, target_len); + return 0; +} + +void +OpenABECtrDrbgContext::initSeed(const uint8_t *nonce, size_t nonce_len) { + ctr_drbg_init_seed(ctx_, entropy_callback, short_entropy_, nonce, nonce_len); +} + + +int OpenABECtrDrbgContext::getRandomBytes(uint8_t *output, size_t output_len) { + // make sure we've called init on ctx. otherwise, throw an error + std::lock_guard write_lock(lock_); + return ctr_drbg_generate_random_with_add(ctx_, output, output_len, NULL, 0); +} + +int OpenABECtrDrbgContext::getRandomBytes(OpenABEByteString *output, size_t output_len) { + output->clear(); + std::lock_guard write_lock(lock_); + return ctr_drbg_generate_random_with_add(ctx_, (uint8_t*)output->getInternalPtr(), output_len, NULL, 0); +} + +int OpenABECtrDrbgContext::reSeed(const uint8_t *buf_ptr, size_t buf_len) { + return ctr_drbg_reseed(ctx_, buf_ptr, buf_len); +} + +int OpenABECtrDrbgContext::reSeed(OpenABEByteString *buf) { + uint8_t *buf_ptr = NULL; + size_t buf_len = 0; + + if (buf != nullptr) { + buf_ptr = buf->getInternalPtr(); + buf_len = buf->size(); + } + return this->reSeed(buf_ptr, buf_len); +} + +OpenABECTR_DRBG::OpenABECTR_DRBG(OpenABEByteString& entropy): isInit_(false) { + ctrDrbgContext_.reset(new OpenABECtrDrbgContext(entropy)); +} + +OpenABECTR_DRBG::OpenABECTR_DRBG(uint8_t *entropy_buf, uint32_t entropy_len): isInit_(false) { + ctrDrbgContext_.reset(new OpenABECtrDrbgContext(entropy_buf, entropy_len)); +} + +void +OpenABECTR_DRBG::setSeed(OpenABEByteString& nonce) { + ctrDrbgContext_->initSeed(nonce.getInternalPtr(), nonce.size()); + isInit_ = true; +} + +int OpenABECTR_DRBG::getRandomBytes(uint8_t *buf, size_t buf_len) { + ASSERT(isInit_, OpenABE_ERROR_CTR_DRB_NOT_INITIALIZED); + int ret = ctrDrbgContext_->getRandomBytes(buf, buf_len); + if (ret < 0) { + return 0; + } + // means we're good + return 1; +} + +int OpenABECTR_DRBG::getRandomBytes(OpenABEByteString *buf, size_t buf_len) { + ASSERT(isInit_, OpenABE_ERROR_CTR_DRB_NOT_INITIALIZED); + uint8_t out[buf_len]; + buf->clear(); + int ret = ctrDrbgContext_->getRandomBytes(out, buf_len); + if (ret < 0) { + // an error occurred + return 0; + } + buf->appendArray(out, buf_len); + memset(out, 0, buf_len); + return 1; // means we're good +} + + + +} diff --git a/src/utils/zattributelist.cpp b/src/utils/zattributelist.cpp new file mode 100644 index 00000000..50bfe4a1 --- /dev/null +++ b/src/utils/zattributelist.cpp @@ -0,0 +1,255 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file ZAttributeList.cpp +/// +/// \brief Class implementation for storing attribute lists. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __OpenABEATTRIBUTELIST_CPP__ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEAttributeList class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the ZAttributeList class. + * + */ + +OpenABEAttributeList::OpenABEAttributeList() : OpenABEFunctionInput() { + this->m_Type = FUNC_ATTRLIST_INPUT; +} + +/*! + * Constructor for the ZAttributeList class. + * + */ + +OpenABEAttributeList::OpenABEAttributeList(uint32_t numArgs, std::vector args) + : OpenABEFunctionInput() { + string c; + if (numArgs != args.size()) + throw OpenABE_ERROR_INVALID_INPUT; + + for (size_t i = 0; i < args.size(); i++) { + if (args[i] != "") + this->addAttribute(args[i]); + } + + this->m_Type = FUNC_ATTRLIST_INPUT; +} + +OpenABEAttributeList::OpenABEAttributeList(const OpenABEAttributeList ©) { + this->m_Type = copy.getFunctionType(); + this->m_Attributes = copy.m_Attributes; + this->m_OriginalAttributes = copy.m_OriginalAttributes; + this->m_prefixSet = copy.m_prefixSet; +} + +/*! + * Destructor for the ZAttributeList class. + * + */ + +OpenABEAttributeList::~OpenABEAttributeList() { this->m_Attributes.clear(); } + +/*! + * Return a copy of the string list. + * + */ + +void OpenABEAttributeList::getStringList(std::vector &attrStrings) { + attrStrings = this->m_Attributes; +} + +/*! + * Sync orig attributes from attrList based on a prefix. + * + */ + +void OpenABEAttributeList::syncOrigAttributes(const string &prefix, + OpenABEAttributeList &attrList) { + for (auto &it : attrList.m_OriginalAttributes) { + if (it.find(prefix) != string::npos) { + this->m_OriginalAttributes.push_back(it); + } + } +} + +/*! + * Search for a string in the string list. + * + */ + +bool OpenABEAttributeList::matchAttribute(const string &attribute) { + return (std::find(m_Attributes.begin(), m_Attributes.end(), attribute) != + m_Attributes.end()); +} + +bool OpenABEAttributeList::addAttribute(string attribute) { + string c, str; + // first extract prefix here (e.g., prefix:attribute) + // before parsing the attribute itself + if (attribute.find(COLON) != string::npos) { + // attribute contains a ':' + vector list = split(attribute, COLON); + if (list.size() > 1) { + // first item in list is treated as + this->m_prefixSet.insert(list[0]); + } + } + + // do a quick find for the '=' symbol: if not, then proceed as usual + if (attribute.find(EQUALS) == string::npos) { + this->m_Attributes.push_back(attribute); + } else { + // otherwise, parse as a numerical attribute (using regex) + // NOTE: we already handled prefixes in first part so would be redundant here + std::unique_ptr attr_list = oabe::createAttributeList(ATTR_SEP + attribute); + const vector *m_attrs = attr_list->getAttributeList(); + const vector *orig_attrs = attr_list->getOriginalAttributeList(); + if (m_attrs && orig_attrs) { + for (auto& a : *m_attrs) + this->m_Attributes.push_back(a); + for (auto& b : *orig_attrs) + this->m_OriginalAttributes.push_back(b); + } + } + + return true; +} + +void OpenABEAttributeList::setAttributes(vector &attr_list, + vector &orig_attr_list, + set &prefix_list) { + this->m_Attributes = attr_list; + this->m_OriginalAttributes = orig_attr_list; + this->m_prefixSet = prefix_list; +} + +ostream &operator<<(ostream &os, const OpenABEAttributeList &attributeList) { + int i = 0; + OpenABEAttributeList attributeList2 = attributeList; + for (std::vector::iterator it = attributeList2.m_Attributes.begin(); + it != attributeList2.m_Attributes.end(); ++it) { + os << i << ":" << *it << endl; + i++; + } + return os; +} + +std::string OpenABEAttributeList::toString() const { + string s; + s.push_back(ATTR_SEP); + for (std::vector::const_iterator it = this->m_Attributes.begin(); + it != this->m_Attributes.end(); ++it) { + if (it->compare("") != 0) { + s += *it; + // add delimiter + s.push_back(ATTR_SEP); + } + } + return s; +} + +std::string OpenABEAttributeList::toCompactString() const { + string s; + s.push_back(ATTR_SEP); + for (auto &it : this->m_Attributes) { + // if the attribute doesn't contain an expint, then proceed + if (it.find(EXPINT) == string::npos) { + s += it; + s.push_back(ATTR_SEP); + } + } + + // add any original attributes to the end + for (auto &it : this->m_OriginalAttributes) { + s += it; + s.push_back(ATTR_SEP); + } + return s; +} + +void OpenABEAttributeList::serialize(OpenABEByteString &result) const { + result = this->toCompactString(); +} + +void OpenABEAttributeList::deserialize(const OpenABEByteString &input) {} + +bool OpenABEAttributeList::isEqual(ZObject *z) const { + OpenABEAttributeList *z1 = dynamic_cast(z); + if (z1 != NULL) { + vector list(z1->m_Attributes.size() + this->m_Attributes.size()); + // order does not matter. verify the same attributes are present + vector::iterator iter = std::set_difference( + z1->m_Attributes.begin(), z1->m_Attributes.end(), + this->m_Attributes.begin(), this->m_Attributes.end(), list.begin()); + return iter->size() == 0; // > 0 means false + } + // return false; + throw OpenABE_ERROR_INVALID_INPUT; +} + +//bool OpenABEAttributeList::isNumeric(const string s) { +// for (size_t i = 0; i < s.size(); i++) { +// if (!isdigit(s[i])) { +// return false; +// } +// } +// return true; +//} + +std::unique_ptr createAttributeList(const std::string &s) { + oabe::Driver driver(false); + if (s.size() == 0) { + return nullptr; + } + /* construct attribute list */ + try { + driver.parse_string(ATTRLIST_PREFIX, s); + return driver.getAttributeList(); + } catch (OpenABE_ERROR &error) { + cerr << "caught exception: " << OpenABE_errorToString(error) << endl; + return nullptr; + } +} +} diff --git a/src/utils/zbenchmark.cpp b/src/utils/zbenchmark.cpp new file mode 100644 index 00000000..e1d3bc07 --- /dev/null +++ b/src/utils/zbenchmark.cpp @@ -0,0 +1,209 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file ZAttributeList.cpp +/// +/// \brief Benchmark utility implementation +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include + +using namespace std; + +int sec_in_microsecond = 1000000; +int ms_in_microsecond = 1000; + +void Benchmark::start() +{ + startT = chrono::system_clock::now(); +} + +void Benchmark::stop() +{ + endT = chrono::system_clock::now(); +} + +int Benchmark::getTimeInMicroseconds() +{ + if(initBench) { + return chrono::duration_cast(endT - startT).count(); + } + return -1; +} + +double Benchmark::computeTimeInMilliseconds() +{ + if (initBench) { + double microsec_result = (double) this->getTimeInMicroseconds(); + double rawResult = microsec_result / ms_in_microsecond; + ss << rawResult << ", "; + sum += rawResult; + iterationCount++; + return rawResult; + } + return -1.0; // didn't call start +} + +string Benchmark::getRawResultString() +{ + return ss.str(); +} + +double Benchmark::getAverage() +{ + return sum / iterationCount; +} + +ListStr::ListStr(void) +{ + // increases as elements are appended + index = 0; +} + +ListStr::~ListStr() +{ + for(int i = 0; i < (int) list.size(); i++) + list.erase(i); +} + +ListStr::ListStr(const ListStr& cList) +{ + //copy constructor + index = cList.index; + list = cList.list; +} + +void ListStr::append(string & s) +{ + list[index] = s; + index++; +} + +void ListStr::append(string s) +{ + list[index] = s; + index++; +} + +void ListStr::insert(int index, string s) +{ + list[index] = s; + index++; +} + +void ListStr::insert(int index, string & s) +{ + list[index] = s; + this->index++; +} + +int ListStr::searchKey(string index) +{ + for(int i = 0; i < (int) list.size(); i++) { + if(CheckEqual(index, list[i])) { return i; } + } + return -1; +} + +string& ListStr::operator[](const int index) +{ + if(index == this->index) { // means we are creating reference. + this->index++; + return list[index]; + } + else if(index < MAX_LIST) { + return list[index]; + } + + int len = (int) list.size(); + if(index >= 0 && index < len) { + return list[index]; + } + else { + throw new string("Invalid access.\n"); + } +} + +ListStr& ListStr::operator=(const ListStr& cList) +{ + if(this == &cList) + return *this; + + // delete current list contents first + int i; + for(i = 0; i < (int) list.size(); i++) + list.erase(i); + this->index = 0; + + this->index = cList.index; + list = cList.list; + return *this; +} + +int ListStr::length() +{ + return (int) list.size(); +} + +string ListStr::printAtIndex(int index) +{ + stringstream ss; + int i; + + if(index >= 0 && index < (int) list.size()) { + i = index; + ss << list[i]; + } + + string s = ss.str(); + return s; +} + +ostream& operator<<(ostream& s, const ListStr& cList) +{ + ListStr cList2 = cList; + for(int i = 0; i < cList2.length(); i++) { + if (cList2.printAtIndex(i) != "") + s << i << ": " << cList2.printAtIndex(i) << endl; + } + + return s; +} + +/* test inequality for two strings */ +bool CheckEqual(string value1, string value2) +{ + string s1 = value1; + string s2 = value2; + if (std::strcmp(s1.c_str(), s2.c_str()) == 0) + return true; + else + return false; +} diff --git a/src/utils/zciphertext.cpp b/src/utils/zciphertext.cpp new file mode 100644 index 00000000..5cc7fc7f --- /dev/null +++ b/src/utils/zciphertext.cpp @@ -0,0 +1,217 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zciphertext.cpp +/// +/// \brief Class implementation for storing OpenABE ciphertexts. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __OpenABECONTAINER_CPP__ + +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABECiphertext class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABECiphertext class. + * + */ +OpenABECiphertext::OpenABECiphertext() : OpenABEContainer() { + this->curveID = OpenABE_NONE_ID; + this->algorithmID = OpenABE_SCHEME_NONE; + this->libraryVersion = OpenABE_LIBRARY_VERSION; + this->uid.fillBuffer(0, UID_LEN); + this->uid_set_extern = false; +} + +OpenABECiphertext::OpenABECiphertext(std::shared_ptr group) + : OpenABEContainer(group) { + this->curveID = OpenABE_NONE_ID; + this->algorithmID = OpenABE_SCHEME_NONE; + this->libraryVersion = OpenABE_LIBRARY_VERSION; + this->uid.fillBuffer(0, UID_LEN); + this->uid_set_extern = false; +} + +OpenABECiphertext::OpenABECiphertext(const OpenABEByteString &uid) : OpenABEContainer() { + this->curveID = OpenABE_NONE_ID; + this->algorithmID = OpenABE_SCHEME_NONE; + this->libraryVersion = OpenABE_LIBRARY_VERSION; + if (uid.size() >= UID_LEN) { + this->uid = uid; + this->uid_set_extern = true; + } else { + // failed to set externally, so one will be generated randomly + this->uid.fillBuffer(0, UID_LEN); + this->uid_set_extern = false; + } +} + +/*! + * Destructor for the OpenABECiphertext class. + * + */ +OpenABECiphertext::~OpenABECiphertext() {} + +/*! + * Export routine for the OpenABECiphertext class (includes header and container elements). + * + */ +void OpenABECiphertext::exportToBytes(OpenABEByteString &output) { + OpenABEByteString ciphertextHeader, ciphertextBytes; + // libVersion || curveID || AlgID || uid || id + this->getHeader(ciphertextHeader); + // serialize the ciphertext elements + this->serialize(ciphertextBytes); + // first pack the key header + // then pack the key bytes + output.clear(); + output.smartPack(ciphertextHeader); + output.smartPack(ciphertextBytes); + return; +} + +/*! + * Import routine for the OpenABECiphertext class (includes header and container elements). + * + */ +void OpenABECiphertext::loadFromBytes(OpenABEByteString &input) { + size_t hdrLen = 3 + UID_LEN; + if (input.size() < hdrLen) { + throw OpenABE_ERROR_INVALID_INPUT; + } + + OpenABEByteString ciphertextHeader, ciphertextBytes; + size_t index = 0; + // convert to OpenABEByteStrings + ciphertextHeader = input.smartUnpack(&index); + + if (ciphertextHeader.size() == hdrLen) { + // assert that libID matches current libID + ASSERT(ciphertextHeader.at(0) <= OpenABE_LIBRARY_VERSION, + OpenABE_ERROR_INVALID_LIBVERSION); + this->libraryVersion = ciphertextHeader.at(0); + // fetch remaining ciphertext bytes + ciphertextBytes = input.smartUnpack(&index); + ASSERT(ciphertextBytes.size() > 0, OpenABE_ERROR_INVALID_CIPHERTEXT_BODY); + + // compose portions of header + this->curveID = OpenABE_getCurveID(ciphertextHeader.at(1)); + this->algorithmID = OpenABE_getSchemeID(ciphertextHeader.at(2)); + this->uid = ciphertextHeader.getSubset(3, UID_LEN); + if (this->group == nullptr && this->curveID != OpenABE_NONE_ID) { + OpenABE_setGroupObject(this->group, this->curveID); + } + + this->deserialize(ciphertextBytes); + } else { + throw OpenABE_ERROR_INVALID_CIPHERTEXT_HEADER; + } + return; +} + +/*! + * Export routine for the OpenABECiphertext class (sames as before but without header). + * + */ +void OpenABECiphertext::exportToBytesWithoutHeader(OpenABEByteString &output) { + OpenABEByteString ciphertextBytes; + // serialize the ciphertext elements + this->serialize(ciphertextBytes); + // first pack the key header + // then pack the key bytes + output.clear(); + output.smartPack(ciphertextBytes); + return; +} + +/*! + * Import routine for the OpenABECiphertext class (same as before but without header). + * + */ +void OpenABECiphertext::loadFromBytesWithoutHeader(OpenABEByteString &input) { + OpenABEByteString ciphertextBytes; + size_t index = 0; + + ciphertextBytes = input.smartUnpack(&index); + ASSERT(ciphertextBytes.size() > 0, OpenABE_ERROR_INVALID_CIPHERTEXT_BODY); + // deserialize bytes into this container + this->deserialize(ciphertextBytes); + return; +} + +/*! + * Obtain the serialized form of the OpenABEKey header. + * + */ +void OpenABECiphertext::setHeader(OpenABECurveID curveID, OpenABE_SCHEME scheme_type, + OpenABERNG *rng) { + /* set the header of the ciphertext */ + this->curveID = curveID; + this->algorithmID = scheme_type; + this->libraryVersion = OpenABE_LIBRARY_VERSION; + if (!this->uid_set_extern) { + // only if one hasn't been set externally + ASSERT_NOTNULL(rng); + rng->getRandomBytes(&this->uid, UID_LEN); + } +} + +void OpenABECiphertext::setHeader(OpenABECurveID curveID, OpenABE_SCHEME scheme_type, + OpenABEByteString &uid) { + /* set the header of the ciphertext */ + this->curveID = curveID; + this->algorithmID = scheme_type; + this->libraryVersion = OpenABE_LIBRARY_VERSION; + this->uid.clear(); + this->uid = uid; +} + +/*! + * Obtain the serialized form of the OpenABEKey header. + * + */ +void OpenABECiphertext::getHeader(OpenABEByteString &header) { + header.clear(); + header.push_back(this->libraryVersion); + header.push_back(this->curveID); + header.push_back(this->algorithmID); + header += this->uid; +} + +} diff --git a/src/utils/zcontainer.cpp b/src/utils/zcontainer.cpp new file mode 100644 index 00000000..3f3afbe2 --- /dev/null +++ b/src/utils/zcontainer.cpp @@ -0,0 +1,278 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontainer.cpp +/// +/// \brief Generic container class for ciphertexts and keys. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __OpenABECONTAINER_CPP__ + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEContainer class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEContainer class. + * + */ + +OpenABEContainer::OpenABEContainer() : ZObject() { + this->group = nullptr; +} + +OpenABEContainer::OpenABEContainer(std::shared_ptr group) : ZObject() { + this->group = group; +} + +/*! + * Destructor for the OpenABEContainer class. + * + */ + +OpenABEContainer::~OpenABEContainer() { + std::map::iterator iter; + for (iter = this->val.begin(); iter != this->val.end(); iter++) { + delete iter->second; + } + this->val.clear(); +} + +/*! + * Set component by name. + * + * @param Name of the ciphertext component + * @param Object containing the component + */ + +void OpenABEContainer::setComponent(const string &name, const ZObject *component) { + ZObject *copy = component->clone(); + + this->val[name] = copy; +} + +/*! + * Obtain a component based on the given key. Return a pointer to the object + * or throw an error. + * + * @return Number of components in the ciphertext + */ + +ZObject *OpenABEContainer::getComponent(const string &name) { + ZObject *result = this->val[name]; + + if (result == nullptr) { + cerr << "OpenABEContainer::getComponent: missing '" << name << "'" << endl; + throw OpenABE_ERROR_ELEMENT_NOT_FOUND; + } + + return result; +} + +OpenABE_ERROR +OpenABEContainer::deleteComponent(const string name) { + map::iterator iter1 = this->val.find(name); + if (iter1 != this->val.end()) { + this->val.erase(iter1); + return OpenABE_NOERROR; + } + return OpenABE_ERROR_ELEMENT_NOT_FOUND; +} + +/*! + * Destructor for the OpenABEContainer class. + * + * @return Number of components in the ciphertext + */ + +uint32_t OpenABEContainer::numComponents() { return this->val.size(); } + +OpenABE_ERROR OpenABEContainer::zeroize() { + return OpenABE_ERROR_NOT_IMPLEMENTED; +} + +/*! + * Serialize the entire object. + * + * @return Byte vector containing the result + */ +void OpenABEContainer::serialize(OpenABEByteString &result) const { + OpenABEByteString res, key, bytes; + std::map::const_iterator it; + std::stringstream ss; + for (it = this->val.begin(); it != this->val.end(); ++it) { + it->second->serialize(bytes); + key = it->first; + result.smartPack(key); + result.smartPack(bytes); + } +} + +void OpenABEContainer::deserializeElement(std::string key, OpenABEByteString &value) { + if (value.size() == 0) { + throw OpenABE_ERROR_INVALID_INPUT; + } + uint8_t type = value.at(0); + + if (type == OpenABE_ELEMENT_INT) { + unique_ptr i(new OpenABEUInteger(0)); + i->deserialize(value); + this->setComponent(key, i.get()); + } else if (type >= OpenABE_ELEMENT_ZP && type <= OpenABE_ELEMENT_GT) { + ASSERT(this->group != nullptr, OpenABE_ERROR_INVALID_GROUP_PARAMS); + std::shared_ptr bp = dynamic_pointer_cast(group); + ASSERT(bp != nullptr, OpenABE_ERROR_INVALID_GROUP_PARAMS); + if (type == OpenABE_ELEMENT_ZP) { + unique_ptr s(new ZP); + s->setOrder(bp->order); + s->deserialize(value); + this->setComponent(key, s.get()); + } else if (type == OpenABE_ELEMENT_G1) { + unique_ptr g(new G1(bp)); + g->deserialize(value); + this->setComponent(key, g.get()); + } else if (type == OpenABE_ELEMENT_G2) { + unique_ptr g(new G2(bp)); + g->deserialize(value); + this->setComponent(key, g.get()); + } else { + unique_ptr g(new GT(bp)); + g->deserialize(value); + this->setComponent(key, g.get()); + } + } else if (type == OpenABE_ELEMENT_BYTESTRING) { + unique_ptr b(new OpenABEByteString); + b->deserialize(value); + this->setComponent(key, b.get()); + } else if (type == OpenABE_ELEMENT_POLICY) { + const string b = value.toString(); + unique_ptr p = oabe::createPolicyTree(b); + if (p == nullptr) { + throw OpenABE_ERROR_INVALID_POLICY_TREE; + } + this->setComponent(key, p.get()); + } else if (type == OpenABE_ELEMENT_ATTRIBUTES) { + const string b = value.toString(); + unique_ptr a = oabe::createAttributeList(b); + if (a == nullptr) { + throw OpenABE_ERROR_INVALID_ATTRIBUTE_LIST; + } + this->setComponent(key, a.get()); + } else if (type == OpenABE_ELEMENT_ZP_t || type == OpenABE_ELEMENT_G_t) { + ASSERT(this->group != nullptr, OpenABE_ERROR_INVALID_GROUP_PARAMS); + std::shared_ptr ec = dynamic_pointer_cast(group); + ASSERT(ec != nullptr, OpenABE_ERROR_INVALID_GROUP_PARAMS); + + if (type == OpenABE_ELEMENT_ZP_t) { + unique_ptr s(new ZP_t); + s->setOrder(ec->order); + s->deserialize(value); + this->setComponent(key, s.get()); + } else { + unique_ptr g(new G_t(ec)); + g->deserialize(value); + this->setComponent(key, g.get()); + } + } else { + cout << "Invalid Input type: " << type << endl; + throw OpenABE_INVALID_INPUT_TYPE; + } + + return; +} + +void OpenABEContainer::deserialize(OpenABEByteString &blob) { + OpenABEByteString result, key, value; + result = blob; + size_t index = 0; + + do { + key = result.smartUnpack(&index); + value = result.smartUnpack(&index); + this->deserializeElement(key.toString(), value); + } while (index < result.size()); + return; +} + +void OpenABEContainer::deserialize(string &blob) { + OpenABEByteString result; + result = blob; + return this->deserialize(result); +} + +std::vector OpenABEContainer::getKeys() { + std::vector keyList; + std::map::iterator iter; + for (iter = this->val.begin(); iter != this->val.end(); iter++) { + keyList.push_back(iter->first); + } + + return keyList; +} + +bool operator==(const OpenABEContainer &c1, const OpenABEContainer &c2) { + // check that the 'keys' of the containers are equal + std::vector keyList1 = const_cast(c1).getKeys(); + std::vector keyList2 = const_cast(c2).getKeys(); + std::vector keyList3(keyList1.size() + keyList2.size()); + std::vector::iterator iter = + std::set_difference(keyList1.begin(), keyList1.end(), keyList2.begin(), + keyList2.end(), keyList3.begin()); + size_t keydiff = iter->size(); + if (keydiff > 0) { + return false; + } + + // check that 'values' of container are equal + for (std::vector::iterator it = keyList1.begin(); + it != keyList1.end(); ++it) { + ZObject *lhs = const_cast(c1).getComponent(*it); + ZObject *rhs = const_cast(c2).getComponent(*it); + if (lhs->isEqual(rhs)) { + continue; + } else { + keydiff++; + } + } + + if (keydiff > 0) + return false; + return true; +} +} diff --git a/src/utils/zcryptoutils.cpp b/src/utils/zcryptoutils.cpp new file mode 100644 index 00000000..fc619e0b --- /dev/null +++ b/src/utils/zcryptoutils.cpp @@ -0,0 +1,354 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcryptoutils.cpp +/// +/// \brief Miscellaneous cryptographic utilities. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __OpenABECRYPTOUTILS_CPP__ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Global utility routines + ********************************************************************************/ +namespace oabe { + +/*! + * Utility for hashing a group element into a string. + * + */ + +bool OpenABEUtilsHashToString(GT &input, uint32_t keyLen, OpenABEByteString &result, + OpenABEHashFunctionType hashType) { + stringstream concatResult; + OpenABEByteString serializedResult; + uint32_t numBytes = 0; + + result.clear(); + input.disableCompression(); + input.serialize(serializedResult); + input.enableCompression(); + + for (uint32_t i = 0; numBytes < keyLen; i++, numBytes += SHA256_LEN) { + concatResult.clear(); + concatResult << numBytes << serializedResult << serializedResult.size(); + std::string hash; + sha256(hash, (uint8_t *)(concatResult.str().c_str()), + concatResult.str().size()); + result.appendArray((uint8_t *)hash.c_str(), SHA256_LEN); + } + + return true; +} + +string OpenABEHashKey(const string attr_key) { + OpenABEByteString hex_digest; + string hash; + if (attr_key.size() > 16) { + sha256(hash, (uint8_t *)(attr_key.c_str()), attr_key.size()); + hex_digest += hash.substr(0,8); + return hex_digest.toLowerHex(); + } + return attr_key; +} + +void OpenABEComputeHash(OpenABEByteString& key, OpenABEByteString& input, OpenABEByteString& output) { + string digest, error_msg = ""; + EVP_MD_CTX *md_ctx = EVP_MD_CTX_create(); + const EVP_MD *md = EVP_sha256(); + size_t digest_size; + + if (input.size() == 0) { + error_msg = "No bytes to digest"; + goto out; + } + + if (!md_ctx) { + error_msg = "EVP_MD_CTX_create"; + goto out; + } + + if (!EVP_DigestInit(md_ctx, md)) { + error_msg = "EVP_DigestInit"; + goto out; + } + + // load the key + if (!EVP_DigestUpdate(md_ctx, key.getInternalPtr(), key.size())) { + error_msg = "EVP_DigestUpdate: load the key"; + goto out; + } + // load the data + if (!EVP_DigestUpdate(md_ctx, input.getInternalPtr(), input.size())) { + error_msg = "EVP_DigestUpdate: load the input"; + goto out; + } + + digest_size = EVP_MD_size(md); + // Just to be safe, check digest_size before resizing the output + if (digest_size > EVP_MAX_MD_SIZE) { + error_msg = "EVP_MD_size"; + goto out; + } + digest.resize(EVP_MD_size(md)); + + if (!EVP_DigestFinal_ex(md_ctx, (unsigned char *)&digest[0], nullptr)) { + error_msg = "EVP_DigestFinal_ex"; + goto out; + } + output = digest; +out: + if (md_ctx) { + EVP_MD_CTX_destroy(md_ctx); + } + if (error_msg != "") { + throw CryptoException(error_msg); + } +} + +/*! + * Generate a salted hash from a given password and encode the resulting + * salt and hash back to user. + * + * @param[out] hash - empty string variable to store the generated salt and computed hash. + * @param[in] password - a password or passphrase to generate a hash against. + * @return + */ +void generateHash(std::string &hash, const std::string &password) { + OpenABERNG rng; + OpenABEByteString pword, salt, result, genHash; + ASSERT(password.size() > 0, OpenABE_ERROR_INVALID_INPUT); + /* set the password */ + pword = password; + /* generate a salt */ + rng.getRandomBytes(&salt, SALT_LEN); + /* produce a hash using the default iteration count */ + genHash = OpenABEPBKDF(pword, HASH_LEN, salt); + /* return hash = salt + outputHash */ + result = salt + genHash; + hash = result.toLowerHex(); + /* clear buffers */ + pword.clear(); + salt.clear(); + genHash.clear(); +} + +/*! + * Check password against a given salted hash. + * + * @param[in] hash - a generated hash. + * @param[in] password - a password or passphrase to check against the hash. + * @return true or false + */ +bool checkPassword(const std::string &hash, const std::string &password) { + OpenABEByteString result, pword, outputHash; + bool answer; + ASSERT(hash.size() > 0, OpenABE_ERROR_INVALID_INPUT); + /* convert hex string into a binary buffer */ + ASSERT(result.fromHex(hash), OpenABE_ERROR_INVALID_INPUT); + ASSERT(result.size() == (SALT_LEN + HASH_LEN), OpenABE_ERROR_INVALID_INPUT); + + /* split the input into salt and hash */ + OpenABEByteString salt = result.getSubset(0, SALT_LEN); + OpenABEByteString inputHash = + result.getSubset(SALT_LEN, result.size() - SALT_LEN); + + /* check the password with the recovered salt */ + pword = password; + outputHash = OpenABEPBKDF(pword, HASH_LEN, salt); + /* check if output hash is equivalent to input hash + -- if so, return true...otherwise, false */ + if (inputHash == outputHash) + answer = true; + else + answer = false; + /* cleanup */ + pword.clear(); + salt.clear(); + outputHash.clear(); + return answer; +} + +OpenABE_ERROR encryptUnderPassword(const std::string password, + OpenABEByteString &inputBlob, + OpenABEByteString &encOutputBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString pword, salt, key, output, iv, ct, tag; + string inBlob, key_str; + unique_ptr authEnc = nullptr; + OpenABERNG rng; + + try { + inBlob = inputBlob.toString(); + // convert the 'password' into a key + generate a salt. + pword = password; + // generate salt + rng.getRandomBytes(&salt, SALT_LEN); + // derive the key using PBKDF2 under generated salt + key = OpenABEPBKDF(pword, DEFAULT_SYM_KEY_BYTES, salt); + // use derived key to encrypt input blob + authEnc.reset( + new oabe::crypto::OpenABESymKeyAuthEnc(DEFAULT_AES_SEC_LEVEL, key)); + // encrypt the input blob + authEnc->encrypt(inBlob, &iv, &ct, &tag); + output.smartPack(iv); + output.smartPack(ct); + output.smartPack(tag); + // concatenate bytes into caller's encOutputBlob object + encOutputBlob += salt; + encOutputBlob += output; + } catch (OpenABE_ERROR &error) { + result = error; + } + + key.zeroize(); + salt.zeroize(); + return result; +} + +OpenABE_ERROR decryptUnderPassword(const string password, + OpenABEByteString &inputCTBlob, + OpenABEByteString &plainOutputBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString pwd, ctBlob, salt, key; + OpenABEByteString iv, ct, tag; + unique_ptr authEnc = nullptr; + string ptBlob; + + try { + // validate the input lengths + ASSERT(inputCTBlob.size() > SALT_LEN, OpenABE_ERROR_INVALID_INPUT); + // first recover the salt + salt = inputCTBlob.getSubset(0, SALT_LEN); + // then recover the ciphertext + ctBlob = inputCTBlob.getSubset(SALT_LEN, inputCTBlob.size() - SALT_LEN); + // now parse sym ciphertext + size_t index = 0; + iv = ctBlob.smartUnpack(&index); + ct = ctBlob.smartUnpack(&index); + tag = ctBlob.smartUnpack(&index); + // convert the 'password' into a key + generate a salt. + pwd = password; + // derive the key (with default number of iterations) + key = OpenABEPBKDF(pwd, DEFAULT_SYM_KEY_BYTES, salt); + // use key to decrypt CT + authEnc.reset( + new oabe::crypto::OpenABESymKeyAuthEnc(DEFAULT_AES_SEC_LEVEL, key)); + if (!authEnc->decrypt(ptBlob, &iv, &ct, &tag)) { + ptBlob.clear(); + throw OpenABE_ERROR_DECRYPTION_FAILED; + } + plainOutputBlob = ptBlob; + } catch (OpenABE_ERROR &error) { + result = error; + } + + key.zeroize(); + salt.zeroize(); + return result; +} + +void sha256(uint8_t *digest, uint8_t *val, size_t val_len) { + std::string d; + const std::string value = std::string((const char *)val, val_len); + sha256(d, value); + memcpy(digest, (uint8_t *)d.c_str(), SHA256_LEN); +} + +void sha256(string &digest, uint8_t *val, size_t val_len) { + const string value = string((const char *)val, val_len); + sha256(digest, value); +} + +void sha256(string &digest, const string &value) { + string error_msg = ""; + EVP_MD_CTX *md_ctx = EVP_MD_CTX_create(); + const EVP_MD *md = EVP_sha256(); + size_t digest_size; + + if (value.size() == 0) { + error_msg = "No bytes to digest"; + goto out; + } + + if (!md_ctx) { + error_msg = "EVP_MD_CTX_create"; + goto out; + } + + if (!EVP_DigestInit(md_ctx, md)) { + error_msg = "EVP_DigestInit"; + goto out; + } + + if (!EVP_DigestUpdate(md_ctx, value.data(), value.size())) { + error_msg = "EVP_DigestUpdate"; + goto out; + } + + digest_size = EVP_MD_size(md); + // Just to be safe, check digest_size before resizing the output + if (digest_size > EVP_MAX_MD_SIZE) { + error_msg = "EVP_MD_size"; + goto out; + } + digest.resize(EVP_MD_size(md)); + + if (!EVP_DigestFinal_ex(md_ctx, (unsigned char *)&digest[0], nullptr)) { + error_msg = "EVP_DigestFinal_ex"; + goto out; + } + +out: + if (md_ctx) { + EVP_MD_CTX_destroy(md_ctx); + } + if (error_msg != "") { + throw CryptoException(error_msg); + } +} + +void sha256ToHex(std::string &hex_digest, const std::string &value) { + OpenABEByteString tmp; + string bin_digest; + sha256(bin_digest, value); + tmp = bin_digest; + hex_digest = tmp.toLowerHex(); +} +} diff --git a/src/utils/zdriver.cpp b/src/utils/zdriver.cpp new file mode 100644 index 00000000..96273c8d --- /dev/null +++ b/src/utils/zdriver.cpp @@ -0,0 +1,841 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zdriver.cpp +/// +/// \brief Driver implementation for parsing +/// and constructing OpenABE policy structures. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef __ZPOLICY_H__ +#include +#endif + +#ifndef __ZINTEGER_H__ +#include +#endif + +#ifndef __ZATTRIBUTELIST_H__ +#include +#endif + +const size_t DAY_IN_SECS = 60*60*24; + +using namespace std; + +namespace oabe { + +////////////////////// Driver for OpenABEPolicy ////////////////////// + +Driver::Driver(bool _debug) : trace_scanning(false), trace_parsing(false) { + final_policy = nullptr; + debug = _debug; +} + +Driver::~Driver() {} + +bool Driver::parse_stream(std::istream &in, const std::string &sname) { + streamname = sname; + + Scanner scanner(&in); + scanner.set_debug(trace_scanning); + this->lexer = &scanner; + + Parser parser(*this); + parser.set_debug_level(trace_parsing); + return (parser.parse() == 0); +} + +bool Driver::parse_string(const std::string &prefix, const std::string &input, + const std::string &sname) { + std::istringstream iss(prefix + input); + this->original_input = input; + if (prefix == POLICY_PREFIX) { + this->isPolicy = true; + } else if (prefix == ATTRLIST_PREFIX) { + this->isPolicy = false; + } else { + return false; + } + return parse_stream(iss, sname); +} + +void Driver::error(const class location &l, const std::string &m) { + std::cerr << "Driver::error " << l << ": " << m << std::endl; + // clear state + this->original_input = ""; + if (this->isPolicy) { + this->final_policy.reset(); + } else { + this->final_attrlist.reset(); + } +} + +void Driver::set_policy(OpenABETreeNode *subtree) { + if (this->final_policy == nullptr) { + this->final_policy = std::unique_ptr(new OpenABEPolicy); + this->final_policy->setRootNode(subtree); + } else { + this->final_policy->setRootNode(subtree); + } + if (this->debug) + std::cout << "Final policy set!" << std::endl; + this->final_policy->setDuplicateInfo(this->attr_count, this->attr_dup); + if (this->attr_prefix.size() > 0) { + this->final_policy->setPrefixSet(this->attr_prefix); + } + this->final_policy->setCompactString(this->original_input); +} + +void Driver::set_attrlist(std::vector *attr_list) { + if (this->debug) { + cout << "Length: " << attr_list->size() << endl; + for (auto &l : *attr_list) { + cout << "ATTR: " << l << endl; + } + cout << "Original Attr Len: " << orig_attributes.size() << endl; + for (auto &j : orig_attributes) { + cout << "ATTR: " << j << endl; + } + cout << "Prefix set length: " << attr_prefix.size() << endl; + for (auto &i : attr_prefix) { + cout << "PREFIX: " << i << endl; + } + + cout << "Date Prefix set length: " << date_prefix.size() << endl; + for (auto &i : date_prefix) { + cout << "PREFIX: " << i << endl; + } + } + this->final_attrlist.reset(new OpenABEAttributeList); + this->final_attrlist->setAttributes(*attr_list, orig_attributes, attr_prefix); + if (attr_list != nullptr) + delete attr_list; + return; +} + +// handler for LEAF '=' number +vector *Driver::attr_num(const std::string &c, OpenABEUInteger *number) { + vector *attrs = new vector(); + if (this->attr_count[c] >= 1) { + if (this->debug) + cerr << "'" << c << "' already specified as an attribute. Excluding from attribute list." << endl; + return attrs; + } + assign_stmt(*attrs, c, *number); + + stringstream ss; + ss << c << ASSIGN_EQ << *number; + orig_attributes.push_back(ss.str()); + return attrs; +} + +vector *Driver::set_date_in_attrlist(const std::string &prefix, + const std::string &month, + OpenABEUInteger *m, OpenABEUInteger *d, + OpenABEUInteger *y) { + uint32_t s_days = validate_date(prefix, m, d, y); + stringstream ss; + ss << prefix << ASSIGN_EQ << month << " " << *d << ", " << *y; + + OpenABEUInteger ui(s_days, 32); + vector *attrs = new vector(); + if (this->date_prefix.count(prefix) == 0) { + const string attr = prefix + COLON + TIME_KEYWORD; + assign_stmt(*attrs, attr, ui); + orig_attributes.push_back(ss.str()); + this->date_prefix.insert(prefix); + } + return attrs; +} + +bool Driver::parse_attribute(const std::string &c) { + pair attr = check_attribute(c); + const string prefix = attr.first; + const string attribute = attr.second; + if (this->attr_count.count(c) == 0) { + // first time, set to 1 + this->attr_count[c] = 1; + } else { // already exist in list, so increment by 1 + return false; + } + + if (prefix != "") { + this->attr_prefix.insert(prefix); + } + + return true; +} + +vector *Driver::leaf_attr(const std::string &c) { + if (this->debug) { + cout << "Parse as leaf attribute: " << c << endl; + } + // record prefix of attributes (if applicable) + if (parse_attribute(c)) { + vector *attrs = new vector(); + attrs->push_back(c); + return attrs; + } + return nullptr; +} + +std::vector *Driver::concat_attr(std::vector *attr1, + std::vector *attr2) { + if (attr1 == nullptr) { + attr1 = new vector(); + } + if (attr2 != nullptr) { + for (auto &j : *attr2) + attr1->push_back(j); + } + + return attr1; +} + +OpenABETreeNode *Driver::leaf_node(const std::string &c) { + int index = 0; + if (this->debug) { + cout << "Constructing leaf node: " << c << endl; + } + pair attr = check_attribute(c); + const string prefix = attr.first; + const string attribute = attr.second; + + if (this->attr_count.count(c) == 0) { + // first time, set to 1 + this->attr_count[c] = 1; + } else { // already exist, so increment by 1 + index = this->attr_count[c]; + this->attr_count[c] += 1; + this->attr_dup.insert(c); + } + + if (prefix != "") { + this->attr_prefix.insert(prefix); + } + + return new OpenABETreeNode(attribute, prefix, index); +} + +OpenABETreeNode *Driver::kof2_tree(int k, OpenABETreeNode *l, OpenABETreeNode *r) { + OpenABETreeNode *rootNode = new OpenABETreeNode(); + zGateType node_type; + + switch (k) { + case 1: + node_type = GATE_TYPE_OR; + break; + case 2: + node_type = GATE_TYPE_AND; + break; + default: + node_type = GATE_TYPE_THRESHOLD; + break; + } + + rootNode->setNodeType(node_type); + rootNode->addSubnode(l); + rootNode->addSubnode(r); + rootNode->setThresholdValue(k); + if (this->debug) { + cout << "Constructing " << OpenABETreeNode_ToString(node_type) << " type.\n" + << endl; + } + return rootNode; +} + +OpenABETreeNode *Driver::kofn_tree(uint32_t threshold_k, + std::vector &attributeList) { + OpenABETreeNode *rootNode = new OpenABETreeNode(); + zGateType node_type; + size_t k; + + switch (threshold_k) { + case 1: + node_type = GATE_TYPE_OR; + break; + case 2: + node_type = GATE_TYPE_AND; + break; + default: + node_type = GATE_TYPE_THRESHOLD; + break; + } + + rootNode->setNodeType(node_type); + for (k = 0; k < attributeList.size(); k++) { + if (this->debug) + std::cout << "Subnode " << k << ": " << attributeList[k]->toString() + << std::endl; + rootNode->addSubnode(attributeList[k]); + } + rootNode->setThresholdValue(threshold_k); + if (this->debug) + std::cout << "Constructing " << OpenABETreeNode_ToString(node_type) + << " type.\n" << std::endl; + return rootNode; +} + +OpenABEUInteger *create_expint(uint32_t value, uint16_t bits) { + return new OpenABEUInteger(value, bits); +} + +OpenABEUInteger *create_flexint(uint32_t value) { + return new OpenABEUInteger(value, MAX_INT_BITS); +} + +bool checkValidBit(uint32_t value, uint32_t bits) { + if (bits < 4 || bits > 32) { + std::cerr << "must be equal to or greater than 4 and no more than 32 bits." + << std::endl; + return false; + } else { + bool isPowerTwo = (!(bits & (bits - 1))); + if (!isPowerTwo) { + std::cerr << "'" << bits << "' bits not a power of two." << std::endl; + return false; + } + // check if 'value' is within range of bits! + // uint32_t max_value = pow(2, bits)-1; + uint32_t max_value = 0; + switch (bits) { + case 4: + max_value = max_4bits; + break; + case 8: + max_value = max_8bits; + break; + case 16: + max_value = max_16bits; + break; + case 32: + max_value = max_32bits; + break; + // case 64: max_value = max_64bits; + // break; + default: + std::cerr << "checkValidBit: missing bits in switch statement" + << std::endl; + break; + } + if (value > max_value) { + std::cerr << "cannot represent all of '" << value << "' using " << bits + << " bits only." << endl; + return false; + } + } + + return true; +} + +OpenABETreeNode *Driver::bit_marker_list(bool flex, bool gt, std::string attr, + int bits, uint32_t value) { + OpenABETreeNode *p = NULL; + int i; + + i = 0; + while (gt ? (((uint32_t)1) << i & value) : !(((uint32_t)1) << i & value)) + i++; + + p = this->leaf_node(bit_marker(flex, attr, i, gt, bits)); + for (i = i + 1; i < bits; i++) { + if (gt) { + p = this->kof2_tree(((uint32_t)1 << i & value) ? 2 : 1, + this->leaf_node(bit_marker(flex, attr, i, gt, bits)), + p); + } else { + p = this->kof2_tree(((uint32_t)1 << i & value) ? 1 : 2, + this->leaf_node(bit_marker(flex, attr, i, gt, bits)), + p); + } + } + + return p; +} + +OpenABETreeNode *Driver::flexint_leader(bool gt, std::string attr, uint32_t value) { + // printf("called flexint_leader: gt=%d, attr=%s, value=%d\n", gt, attr, + // value); + int k; + std::vector attributes; + uint32_t i = 0; + + for (k = 2; k <= 16; k *= 2) { + if ((gt && ((uint32_t)1 << k) > value) || + (!gt && ((uint32_t)1 << k) >= value)) { + attributes.push_back(this->leaf_node( + attr + FLEXINT + to_string(gt ? value + 1 : value - 1))); + } + i++; + } + + if (i == 0) { + return NULL; + } else if (i == 1) { + return attributes[0]; + } + + return this->kofn_tree((gt ? 1 : i), attributes); +} + +OpenABETreeNode *Driver::cmp_policy(OpenABEUInteger *number, bool gt, + std::string attr) { + OpenABETreeNode *p = NULL; + + /* create the subtree */ + int bits = number->getBits(); + bool flex = bits == 0 ? true : false; + uint32_t value = number->getVal(); + // (value >= ((uint64_t)1 << 32) ? 64 + // : + p = this->bit_marker_list( + flex, gt, attr, + bits ? bits : (value >= ((uint32_t)1 << 16) + ? 32 + : value >= ((uint32_t)1 << 8) + ? 16 + : value >= ((uint32_t)1 << 4) + ? 8 + : value >= ((uint32_t)1 << 2) ? 4 : 2), + value); + return p; +} + +std::string bit_marker(bool flex, std::string base, int bit, int val, + int bit_count) { + std::string lx, rx, s; + std::stringstream ss; + lx = std::string(32 - bit - 1, 'x'); + rx = std::string(bit, 'x'); + // s = string(base, lx, !!val, rx); + s = ""; + if (flex) { + // flexint + s = base + FLEXINT + lx; + } else { + // expint (4 up to 32) + ss << std::setw(2) << std::setfill('0') << to_string(bit_count); + s = base + EXPINT + ss.str() + "_" + lx; + } + // s += to_string(!!val) + rx; + s += to_string(val ? 1 : 0) + rx; + return s; +} + +OpenABETreeNode *Driver::eq_policy(const std::string &c, OpenABEUInteger *number) { + OpenABETreeNode *p = NULL; + int bits = number->getBits(); + bool flex = bits ? false : true; + int bit_count = bits ? bits : 32; + + std::bitset<32> num(number->getVal()); + // std::cout << "flex: " << flex << ", bit_count: " << bit_count << std::endl; + // std::cout << "Bits: " << num << std::endl; + int last = flex ? num.size() : bit_count; + // std::cout << "Bit rep: " << num[last]; + p = this->leaf_node(bit_marker(flex, c, last - 1, num[last - 1], bit_count)); + + for (int i = last - 1; i > 0; i--) { + // std::cout << num[i-1]; + p = this->kof2_tree(2, p, this->leaf_node(bit_marker( + flex, c, i - 1, num[i - 1], bit_count))); + } + // std::cout << std::endl; + return p; +} + +OpenABETreeNode *Driver::lt_policy(const std::string &attr, OpenABEUInteger *number) { + return this->cmp_policy(number, false, attr); +} + +OpenABETreeNode *Driver::gt_policy(const std::string &attr, OpenABEUInteger *number) { + return this->cmp_policy(number, true, attr); +} + +OpenABETreeNode *Driver::le_policy(const std::string &attr, OpenABEUInteger *number) { + *number += 1; + return this->cmp_policy(number, false, attr); +} + +OpenABETreeNode *Driver::ge_policy(const std::string &attr, OpenABEUInteger *number) { + *number -= 1; + return this->cmp_policy(number, true, attr); +} + +OpenABETreeNode *Driver::range_policy(const std::string &c, OpenABEUInteger *min_num, + OpenABEUInteger *max_num) { + if (min_num->getVal() > max_num->getVal()) { + throw OpenABE_ERROR_INVALID_RANGE_NUMBERS; + } else if (min_num->getBits() != max_num->getBits()) { + throw OpenABE_ERROR_INVALID_MISMATCH_BITS; + } + // translate to (LEAF > min_num AND LEAF < max_num) + OpenABETreeNode *rootNode = new OpenABETreeNode(); + OpenABETreeNode *l = this->gt_policy(c, min_num); + OpenABETreeNode *r = this->lt_policy(c, max_num); + rootNode->setNodeType(GATE_TYPE_AND); + rootNode->addSubnode(l); + rootNode->addSubnode(r); + rootNode->setThresholdValue(2); + return rootNode; +} + +OpenABETreeNode *Driver::range_incl_policy(const std::string &c, + OpenABEUInteger *min_num, + OpenABEUInteger *max_num) { + if (min_num->getVal() > max_num->getVal()) { + throw OpenABE_ERROR_INVALID_RANGE_NUMBERS; + } else if (min_num->getBits() != max_num->getBits()) { + throw OpenABE_ERROR_INVALID_MISMATCH_BITS; + } + // translate to (LEAF >= min_num AND LEAF <= max_num) + OpenABETreeNode *rootNode = new OpenABETreeNode(); + OpenABETreeNode *l = this->ge_policy(c, min_num); + OpenABETreeNode *r = this->le_policy(c, max_num); + rootNode->setNodeType(GATE_TYPE_AND); + rootNode->addSubnode(l); + rootNode->addSubnode(r); + rootNode->setThresholdValue(2); + return rootNode; +} + +static bool is_valid_date(int month, int day, int year) { + // gregorian calendar started in 1582 + if (!(1582 <= year)) + return false; + if (!(1 <= month && month <= 12)) + return false; + if (!(1 <= day && day <= 31)) + return false; + if ((day == 31) && + (month == 2 || month == 4 || month == 6 || month == 9 || month == 11)) + return false; + if ((day == 30) && (month == 2)) + return false; + if ((month == 2) && (day == 29) && (year % 4 != 0)) + return false; + if ((month == 2) && (day == 29) && (year % 400 == 0)) + return true; + if ((month == 2) && (day == 29) && (year % 100 == 0)) + return false; + if ((month == 2) && (day == 29) && (year % 4 == 0)) + return true; + + return true; +} + +OpenABEUInteger *get_month(const string &month) { + int m = -1; + if (month == "January" || month == "Jan") + m = 1; + else if (month == "February" || month == "Feb") + m = 2; + else if (month == "March" || month == "Mar") + m = 3; + else if (month == "April" || month == "Apr") + m = 4; + else if (month == "May") + m = 5; + else if (month == "June" || month == "Jun") + m = 6; + else if (month == "July" || month == "Jul") + m = 7; + else if (month == "August" || month == "Aug") + m = 8; + else if (month == "September" || month == "Sep") + m = 9; + else if (month == "October" || month == "Oct") + m = 10; + else if (month == "November" || month == "Nov") + m = 11; + else if (month == "December" || month == "Dec") + m = 12; + else + m = 0; + return new OpenABEUInteger(m, MAX_INT_BITS); +} + +uint32_t validate_date(const std::string &prefix, OpenABEUInteger *m, + OpenABEUInteger *d, OpenABEUInteger *y) { + // check for valid date. Also, make sure no bits specified for year or day. + // If flexints originally, then turn into appropriate expints + // cout << "Prefix: " << prefix << endl; + // cout << "Month: " << m->getVal() << endl; + // cout << "Day: " << d->getVal() << endl; + // cout << "Year: " << y->getVal() << endl; + if (prefix == MONTH_KEYWORD || prefix == DAY_KEYWORD || + prefix == YEAR_KEYWORD) { + throw OpenABE_ERROR_INVALID_PREFIX_SPECIFIED; + } + + if (!(m->isFlexInt() && d->isFlexInt() && y->isFlexInt())) { + throw OpenABE_ERROR_INVALID_ATTRIBUTE_STRUCTURE; + } + + if (!is_valid_date(m->getVal(), d->getVal(), y->getVal())) { + throw OpenABE_ERROR_INVALID_DATE_SPECIFIED; + } + + // reject if before epoch + if (y->getVal() < EPOCH_YEAR) { + throw OpenABE_ERROR_INVALID_DATE_BEFORE_EPOCH; + } + + struct tm t = {0}; + t.tm_year = y->getVal() - 1900; + t.tm_mon = m->getVal() - 1; + t.tm_mday = d->getVal(); + time_t s = mktime(&t); + + uint32_t in_days = (uint32_t)(s / DAY_IN_SECS); + return in_days; +} + +void validate_range_date(const std::string &prefix, OpenABEUInteger *m, + OpenABEUInteger *min_d, OpenABEUInteger *max_d, + OpenABEUInteger *y) { + if (prefix == MONTH_KEYWORD || prefix == DAY_KEYWORD || + prefix == YEAR_KEYWORD) { + throw OpenABE_ERROR_INVALID_PREFIX_SPECIFIED; + } + + if (!(m->isFlexInt() && min_d->isFlexInt() && max_d->isFlexInt() && + y->isFlexInt())) { + throw OpenABE_ERROR_INVALID_ATTRIBUTE_STRUCTURE; + } + + if (!is_valid_date(m->getVal(), min_d->getVal(), y->getVal())) { + throw OpenABE_ERROR_INVALID_DATE_SPECIFIED; + } + + if (!is_valid_date(m->getVal(), max_d->getVal(), y->getVal())) { + throw OpenABE_ERROR_INVALID_DATE_SPECIFIED; + } + + // reject if before epoch + if (y->getVal() < EPOCH_YEAR) { + throw OpenABE_ERROR_INVALID_DATE_BEFORE_EPOCH; + } +} + +OpenABETreeNode *Driver::set_date_in_policy(const std::string &prefix, + OpenABEUInteger *m, OpenABEUInteger *d, + OpenABEUInteger *y) { + // date = {Month} {Day}, {Year} + uint32_t s = validate_date(prefix, m, d, y); + string attr = ""; + if (prefix != TIME_KEYWORD) + attr += prefix + COLON + TIME_KEYWORD; + else + attr += prefix; + + OpenABEUInteger ui(s, 32); + OpenABETreeNode *rootNode = this->eq_policy(attr, &ui); + return rootNode; +} + +OpenABETreeNode *Driver::gt_date_in_policy(const std::string &prefix, + OpenABEUInteger *m, OpenABEUInteger *d, + OpenABEUInteger *y) { + // date > {Month} {Day}, {Year} + uint32_t s = validate_date(prefix, m, d, y); + string attr = ""; + if (prefix != TIME_KEYWORD) + attr += prefix + COLON + TIME_KEYWORD; + else + attr += prefix; + + OpenABEUInteger ui(s, 32); + OpenABETreeNode *rootNode = this->gt_policy(attr, &ui); + return rootNode; +} + +OpenABETreeNode *Driver::ge_date_in_policy(const std::string &prefix, + OpenABEUInteger *m, OpenABEUInteger *d, + OpenABEUInteger *y) { + // date >= {Month} {Day}, {Year} + uint32_t s = validate_date(prefix, m, d, y); + string attr = ""; + if (prefix != TIME_KEYWORD) + attr += prefix + COLON + TIME_KEYWORD; + else + attr += prefix; + + OpenABEUInteger ui(s, 32); + OpenABETreeNode *rootNode = this->ge_policy(attr, &ui); + return rootNode; +} + +OpenABETreeNode *Driver::lt_date_in_policy(const std::string &prefix, + OpenABEUInteger *m, OpenABEUInteger *d, + OpenABEUInteger *y) { + // date < {Month} {Day}, {Year} + uint32_t s = validate_date(prefix, m, d, y); + string attr = ""; + if (prefix != TIME_KEYWORD) + attr += prefix + COLON + TIME_KEYWORD; + else + attr += prefix; + + OpenABEUInteger ui(s, 32); + OpenABETreeNode *rootNode = this->lt_policy(attr, &ui); + return rootNode; +} + +OpenABETreeNode *Driver::le_date_in_policy(const std::string &prefix, + OpenABEUInteger *m, OpenABEUInteger *d, + OpenABEUInteger *y) { + // date < {Month} {Day}, {Year} + uint32_t s = validate_date(prefix, m, d, y); + string attr = ""; + if (prefix != TIME_KEYWORD) + attr += prefix + COLON + TIME_KEYWORD; + else + attr += prefix; + + OpenABEUInteger ui(s, 32); + OpenABETreeNode *rootNode = this->le_policy(attr, &ui); + return rootNode; +} + +OpenABETreeNode *Driver::range_date_in_policy(const std::string &prefix, + OpenABEUInteger *m, OpenABEUInteger *min_d, + OpenABEUInteger *max_d, OpenABEUInteger *y) { + if (min_d->getVal() > max_d->getVal()) { + throw OpenABE_ERROR_INVALID_RANGE_NUMBERS; + } + validate_range_date(prefix, m, min_d, max_d, y); + + struct tm t1 = {0}; + t1.tm_year = y->getVal() - 1900; + t1.tm_mon = m->getVal() - 1; + t1.tm_mday = min_d->getVal(); + time_t s1 = mktime(&t1); + uint32_t s1_days = s1 / DAY_IN_SECS; + + t1.tm_mday = max_d->getVal(); + time_t s2 = mktime(&t1); + uint32_t s2_days = s2 / DAY_IN_SECS; + + string attr = ""; + if (prefix != TIME_KEYWORD) + attr += prefix + COLON + TIME_KEYWORD; + else + attr += prefix; + + OpenABEUInteger ui_min((uint32_t)s1_days, 32), ui_max((uint32_t)s2_days, 32); + OpenABETreeNode *l = this->ge_policy(attr, &ui_min); + OpenABETreeNode *r = this->le_policy(attr, &ui_max); + OpenABETreeNode *rootNode = new OpenABETreeNode(); + rootNode->setNodeType(GATE_TYPE_AND); + rootNode->addSubnode(l); + rootNode->addSubnode(r); + rootNode->setThresholdValue(2); + + return rootNode; +} + +std::ostream &Driver::print(std::ostream &stream) { + stream << this->final_policy->getRootNode()->toString() << "\n"; + return (stream); +} + +////////////////////// Driver for OpenABEPolicy ////////////////////// + +bool assign_stmt(std::vector &attributeList, const std::string &c, + OpenABEUInteger &number) { + // std::cout << "number: " << number << "\n"; + int bits = number.getBits(); + bool flex = bits ? false : true; + int bit_count = bits ? bits : 32; + + if (!flex && !checkValidBit(number.getVal(), bits)) { + return false; + } + + std::bitset<32> num(number.getVal()); + // std::cout << "bit rep: " << num << "\n"; + + int last = flex ? num.size() : bit_count; + if (last < 32) { + last += 2; // bump up to fully capture bits necessary for <=,>= type trees + } + // std::cout << "last = " << last << std::endl; + // std::cout << "num[" << last << "] = " << num[last-1] << std::endl; + attributeList.push_back( + bit_marker(flex, c, last - 1, num[last - 1], bit_count)); + + for (int i = last - 1; i > 0; i--) { + attributeList.push_back(bit_marker(flex, c, i - 1, num[i - 1], bit_count)); + } + return true; +} + +pair check_attribute(const string &c) { + std::string attribute = "", prefix = ""; + size_t found = c.find(COLON); + if (found != std::string::npos) { + // contains a ':' + vector list = split(c, COLON); + size_t len = list.size(); + prefix = list[0]; + if (len == 2) { + // break down into two parts + attribute = list[1]; + } else if (len >= 3) { + // remaining are treated as attribute + for (size_t i = 1; i < len; i++) { + attribute += list[i]; + if (i != (len - 1)) { + attribute += COLON; + } + } + } else { + // throw an error here + throw OpenABE_ERROR_INVALID_ATTRIBUTE_STRUCTURE; + } + } else { + // continue as before and means no prefix was specified + attribute = c; + } + + return make_pair(prefix, attribute); +} + +} diff --git a/src/utils/zerror.cpp b/src/utils/zerror.cpp new file mode 100644 index 00000000..7d48530b --- /dev/null +++ b/src/utils/zerror.cpp @@ -0,0 +1,241 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zerror.cpp +/// +/// \brief Class implementation for error codes to strings. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __ZTOOLKIT_CPP__ + +#include +#include +#include +#include +#include +#include + +using namespace std; + +/*! + * Convert a OpenABE_ERROR result into a string. + * + * @param The error code + * @return The error string + */ +namespace oabe { + +const char *OpenABE_errorToString(OpenABE_ERROR error) { + switch (error) { + case OpenABE_NOERROR: + return "No error"; + break; + case OpenABE_ERROR_INVALID_CONTEXT: + return "Invalid encryption context"; + break; + case OpenABE_ERROR_INVALID_CIPHERTEXT: + return "Invalid ciphertext"; + break; + case OpenABE_ERROR_INVALID_GROUP_PARAMS: + return "Invalid group parameters"; + break; + case OpenABE_ERROR_INVALID_PARAMS: + return "Invalid global parameters"; + break; + case OpenABE_ERROR_INVALID_KEY: + return "Invalid key or parameters"; + break; + case OpenABE_ERROR_OUT_OF_MEMORY: + return "Out of memory"; + break; + case OpenABE_ERROR_INVALID_INPUT: + return "Invalid function input"; + break; + case OpenABE_ERROR_ENCRYPTION_ERROR: + return "Error occurred during encryption"; + break; + case OpenABE_ERROR_UNKNOWN_SCHEME: + return "Unknown scheme"; + break; + case OpenABE_ERROR_LIBRARY_NOT_INITIALIZED: + return "Library not initialized or shut down due to critical error"; + break; + case OpenABE_ERROR_NO_SECRET_PARAMS: + return "Secret parameters are not available"; + break; + case OpenABE_ERROR_NO_PUBLIC_PARAMS: + return "Public parameters (MPK) are not available"; + break; + case OpenABE_ERROR_NOT_IMPLEMENTED: + return "Functionality has not been implemented"; + break; + case OpenABE_ERROR_BUFFER_TOO_SMALL: + return "Buffer is too small for the requested operation"; + break; + case OpenABE_ERROR_INVALID_PARAMS_ID: + return "Invalid group parameters ID"; + break; + case OpenABE_ERROR_WRONG_GROUP: + return "Input value is in the wrong group"; + break; + case OpenABE_ERROR_ELEMENT_NOT_FOUND: + return "Element not found in container"; + break; + case OpenABE_ERROR_SECRET_SHARING_FAILED: + return "Unable to complete secret sharing or recovery"; + break; + case OpenABE_ERROR_INVALID_POLICY: + return "Invalid policy"; + break; + case OpenABE_ERROR_WRONG_USER_PARAM: + return "Provided wrong user parameters"; + break; + case OpenABE_ERROR_INVALID_LENGTH: + return "Specified length is invalid"; + break; + case OpenABE_ERROR_INVALID_TAG_LENGTH: + return "Specified an invalid authentication tag length"; + break; + case OpenABE_ERROR_SERIALIZATION_FAILED: + return "Error occurred during serialization"; + break; + case OpenABE_ERROR_INVALID_LIBVERSION: + return "Input structure does not match library version"; + break; + case OpenABE_ERROR_RAND_INSUFFICIENT: + return "Insufficient randomness returned"; + break; + case OpenABE_ERROR_UNEXPECTED_EXTRA_BYTES: + return "Unexpected extra bytes were added beyond the size of the buffer"; + break; + case OpenABE_ERROR_IN_USE_ALREADY: + return "Specified identifier is currently in use already"; + break; + case OpenABE_ERROR_INVALID_KEY_HEADER: + return "Error occurred while parsing the key header. Perhaps, key type " + "mismatch?"; + break; + case OpenABE_ERROR_INVALID_CIPHERTEXT_HEADER: + return "Error occurred while parsing the ciphertext header"; + break; + case OpenABE_ERROR_DECRYPTION_FAILED: + return "Error occurred during decryption"; + break; + case OpenABE_ERROR_VERIFICATION_FAILED: + return "Could not perform verification due to invalid inputs or " + "verification failed"; + break; + case OpenABE_ERROR_DIVIDE_BY_ZERO: + return "Divide by zero error occurred"; + break; + case OpenABE_ERROR_ORDER_NOT_SPECIFIED: + return "The order of the group was not specified"; + break; + case OpenABE_ERROR_ELEMENT_NOT_INITIALIZED: + return "The group or integer element was not initialized"; + break; + case OpenABE_ERROR_DESERIALIZATION_FAILED: + return "Error occurred during deserialization"; + break; + case OpenABE_ERROR_INVALID_CURVE_ID: + return "Invalid curve identifier"; + break; + case OpenABE_ERROR_INVALID_SCHEME_ID: + return "Invalid scheme identifier"; + break; + case OpenABE_ERROR_INVALID_KEY_BODY: + return "The body of the key structure is malformed"; + break; + case OpenABE_ERROR_INVALID_CIPHERTEXT_BODY: + return "The body of the ciphertext is malformed"; + break; + case OpenABE_ERROR_SYNTAX_ERROR_IN_PARSER: + return "A syntax error occurred during parsing of the input policy"; + break; + case OpenABE_ERROR_CTR_DRB_NOT_INITIALIZED: + return "The CTR DRBG context was not initialized. Failed to call 'setSeed'"; + break; + case OpenABE_ERROR_CLASS_NOT_INITIALIZED: + return "The object was not initialized properly"; + break; + case OpenABE_ERROR_INVALID_PACK_TYPE: + return "The pack type specified is invalid"; + break; + case OpenABE_ERROR_INVALID_ATTRIBUTE_STRUCTURE: + return "Invalid attribute structure specified"; + break; + case OpenABE_ERROR_INDEX_OUT_OF_BOUNDS: + return "Index is out of bounds"; + break; + case OpenABE_ERROR_MISSING_SENDER_PUBLIC_KEY: + return "Missing the sender's public key"; + break; + case OpenABE_ERROR_MISSING_RECEIVER_PRIVATE_KEY: + return "Missing the receiver's private key"; + break; + case OpenABE_ERROR_MISSING_RECEIVER_PUBLIC_KEY: + return "Missing the receiver's public key"; + break; + case OpenABE_ERROR_MISSING_AUTHORITY_ID_IN_ATTR: + return "Missing authority ID in specified attribute"; + break; + case OpenABE_ERROR_INVALID_ATTRIBUTE_LIST: + return "Invalid attribute list specified"; + break; + case OpenABE_ERROR_INVALID_RANGE_NUMBERS: + return "Invalid range numbers specified"; + break; + case OpenABE_ERROR_INVALID_MISMATCH_BITS: + return "Specified a mismatch of integer bits"; + break; + case OpenABE_ERROR_INVALID_PREFIX_SPECIFIED: + return "Specified a reserved/system prefix"; + break; + case OpenABE_ERROR_INVALID_DATE_SPECIFIED: + return "Invalid date specified as attribute"; + break; + case OpenABE_ERROR_INVALID_DATE_BEFORE_EPOCH: + return "Date specified is before unix epoch: January 1, 1970"; + break; + case OpenABE_ERROR_SIGNATURE_FAILED: + return "Error occurred during signing"; + break; + case OpenABE_ERROR_KEYGEN_FAILED: + return "Error occurred during key generation"; + break; + case OpenABE_ERROR_NO_PLAINTEXT_SPECIFIED: + return "Did not specify plaintext to encrypt or sign"; + case OpenABE_ERROR_UNKNOWN: + return "Unknown error"; + break; + default: + return "Unrecognized error code"; + break; + } + } +} diff --git a/src/utils/zfunctioninput.cpp b/src/utils/zfunctioninput.cpp new file mode 100644 index 00000000..07ee0b5a --- /dev/null +++ b/src/utils/zfunctioninput.cpp @@ -0,0 +1,107 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zfunctioninput.cpp +/// +/// \brief Base class for arbitrary function inputs. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __OpenABEFUNCTIONINPUT_CPP__ + +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEFunctionInput class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEFunctionInput class. + * + */ + +OpenABEFunctionInput::OpenABEFunctionInput() : ZObject(), m_Type(FUNC_INVALID_INPUT) {} + +/*! + * Destructor for the OpenABEFunctionInput class. + * + */ + +OpenABEFunctionInput::~OpenABEFunctionInput() {} + +unique_ptr copyFunctionInput(const OpenABEFunctionInput &input) { + unique_ptr funcInput = nullptr; + if (input.getFunctionType() == FUNC_POLICY_INPUT) { + OpenABEPolicy *policy = (OpenABEPolicy *)&input; + funcInput.reset(policy->clone()); + } else if (input.getFunctionType() == FUNC_ATTRLIST_INPUT) { + OpenABEAttributeList *attrs = (OpenABEAttributeList *)&input; + funcInput.reset(attrs->clone()); + } else { + return nullptr; + } + + return funcInput; +} + +unique_ptr getFunctionInput(OpenABECiphertext *ciphertext) { + ASSERT_NOTNULL(ciphertext); + OpenABE_SCHEME scheme_type = ciphertext->getSchemeType(); + OpenABEByteString *policy_str = NULL; + OpenABEAttributeList *attrList = NULL; + + // check the scheme type + switch (scheme_type) { + case OpenABE_SCHEME_CP_WATERS: + case OpenABE_SCHEME_CP_WATERS_CCA: + policy_str = ciphertext->getByteString("policy"); + ASSERT_NOTNULL(policy_str); + return unique_ptr( + createPolicyTree(policy_str->toString())); + break; + case OpenABE_SCHEME_KP_GPSW: + case OpenABE_SCHEME_KP_GPSW_CCA: + attrList = (OpenABEAttributeList *)ciphertext->getComponent("attributes"); + ASSERT_NOTNULL(attrList); + return unique_ptr( + createAttributeList(attrList->toCompactString())); + break; + default: + break; + } + return nullptr; +} + +} diff --git a/src/utils/zkeymgr.cpp b/src/utils/zkeymgr.cpp new file mode 100644 index 00000000..0c3a862e --- /dev/null +++ b/src/utils/zkeymgr.cpp @@ -0,0 +1,387 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zkeymgr.cpp +/// +/// \brief Class implementation for the OpenABE keystore manager (keystore patent). +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace oabe { + +/******************************************************************************** + * Implementation of the OpenABEKeystoreManager class + ********************************************************************************/ + +OpenABEKeystoreManager::OpenABEKeystoreManager(): OpenABEKeystore() { +} + +OpenABEKeystoreManager::~OpenABEKeystoreManager() { + // clear out metadata structure + keyPassphrase_.clear(); +} + +void +OpenABEKeystoreManager::setPassphrase(const std::string& programId, const std::string& userId, const std::string& passphrase) { + keyPassphrase_[userId] = passphrase; + activeUsers_[userId] = programId; +} + +map +OpenABEKeystoreManager::getActiveUsers() { + return activeUsers_; +} + +bool +OpenABEKeystoreManager::storeWithKeyIDCommand(const string& userId, const std::string keyID, + OpenABEByteString& keyBlob, uint64_t keyExpireDate, + bool canCacheKey) { + OpenABEMetadata metadata(new _OpenABEMetadata); + OpenABEByteString origBlob = keyBlob, outputKeyBytes; + // parse the header first + shared_ptr key = nullptr; + assert(userId != ""); + + if (keyMetadata_.count(keyID) != 0) { + keyMetadata_.erase(keyID); + } + + key = this->parseKeyHeader(keyID, keyBlob, outputKeyBytes); + if(key == nullptr) { + THROW_ERROR(OpenABE_ERROR_INVALID_INPUT); + } + + bool foundAnExistingKey = false; + string funcInputStr, funcInputStrNew; + OpenABECurveID curveID = OpenABE_getCurveID(key->getCurveID()); + OpenABE_SCHEME schemeID = OpenABE_getSchemeID(key->getAlgorithmID()); + // create the group object based on curve ID. + std::shared_ptr group; + OpenABE_setGroupObject(group, curveID); + + if(curveID != OpenABE_NONE_ID && schemeID != OpenABE_SCHEME_NONE) { + // parse the body of the key + key->setGroup(group); + key->loadKeyFromBytes(outputKeyBytes); + // check if input + unique_ptr keyInput = getFunctionInput(key.get()); + funcInputStrNew = keyInput->toCompactString(); + // search existing metadata (if available) + for (auto it = keyMetadata_.begin(); it != keyMetadata_.end(); it++) { + funcInputStr = it->second->input->toCompactString(); + if (funcInputStr.compare(funcInputStrNew) == 0 // same func input & type + && keyInput->getFunctionType() == it->second->input->getFunctionType() + && userId.compare(it->second->userId) == 0) { + foundAnExistingKey = true; + break; + } + } + + if (foundAnExistingKey) { + // no need to add key + return false; + } + + // add info to metadata here + metadata->userId = userId; + metadata->keyBlob = origBlob; + metadata->keyExpirationDate = keyExpireDate; + metadata->curveID = curveID; + metadata->schemeID = schemeID; + metadata->inputType = keyInput->getFunctionType(); + metadata->input = move(keyInput); + metadata->isCached = canCacheKey; + keyMetadata_[keyID] = metadata; + return true; + } + return false; +} + +const string +OpenABEKeystoreManager::storeWithKeyPrefixCommand(const string& userId, const string keyPrefix, + OpenABEByteString& keyBlob, uint64_t keyExpireDate, + bool canCacheKey) { + // choose new key ID based on some user-defined prefix + std::lock_guard lock(ks_lock_); + + if(keyCounter_.count(userId) == 0) + keyCounter_[userId] = 0; + const string keyID = keyPrefix + to_string(keyCounter_[userId]); + if (storeWithKeyIDCommand(userId, keyID, keyBlob, keyExpireDate, canCacheKey)) { + // increment the key counter + // currentKeyCounter++; + int key_count = ((keyCounter_[userId] + 1) % MAX_KEYS_PER_USER); + keyCounter_[userId] = key_count; + // return new key ID reference + return keyID; + } + // failed to store key + return ""; +} + +int OpenABEKeystoreManager::getUserKeyCount(const std::string& userId) { + return keyCounter_[userId]; +} + +pair +OpenABEKeystoreManager::getKeyCommand(const string& userId, const string& keyID) { + OpenABEByteString keyBlob; + string funcInput = ""; + std::lock_guard lock(ks_lock_); + + if(keyMetadata_.count(keyID) != 0) { + auto& keyMd = keyMetadata_[keyID]; + if (keyMd->userId.compare(userId) == 0) { + keyBlob = keyMd->keyBlob; + funcInput = keyMd->input->toCompactString(); + } + } + return make_pair(funcInput, keyBlob); +} + +vector +OpenABEKeystoreManager::filterKeys(const string& userId, OpenABEFunctionInputType type) { + vector keyList; + OpenABEFunctionInputType target_type; + OpenABEMetadata tmp; + if (userId == "") { + /* return an empty key list */ + return keyList; + } + + /* filter keys based on opposite of 'type' */ + if(type == FUNC_POLICY_INPUT) + target_type = FUNC_ATTRLIST_INPUT; + else if(type == FUNC_ATTRLIST_INPUT) + target_type = FUNC_POLICY_INPUT; + else + target_type = FUNC_INVALID_INPUT; + + map::iterator it; + for(it = keyMetadata_.begin(); it != keyMetadata_.end(); it++) { + if (it->second->inputType == target_type) { + if (userId.compare(it->second->userId) == 0) { + // if user Id set and matches the Id on the key metadata + // cout << "Filter keys for: " << currentUserId_ << endl; + keyList.push_back(it->first); + } + } + } + + return keyList; +} + +vector +OpenABEKeystoreManager::getKeyIds(const std::string& userId, uint64_t currentTime) { + vector keyList; + OpenABEMetadata tmp; + + map::iterator it; + for(it = keyMetadata_.begin(); it != keyMetadata_.end(); it++) { + if(userId.compare(it->second->userId) == 0) { + if (currentTime == 0) + keyList.push_back(it->first); + else if (currentTime >= it->second->keyExpirationDate) + keyList.push_back(it->first); + } else { + // try to find expired keys (regardless of userId matching) + if (currentTime > 0 && currentTime >= it->second->keyExpirationDate) { + keyList.push_back(it->first); + } + } + } + return keyList; +} + +void +OpenABEKeystoreManager::rankKeyAlgorithm(vector& keyIDs, OpenABEKeyQuery* query) { + /* do nothing for now */ + return; +} + +struct key_ref_compare { + bool operator()(const std::pair &left, const std::pair &right) { + return (left.second < right.second); + } +}; + +pair +OpenABEKeystoreManager::testAKey(OpenABEMetadata& key, OpenABEFunctionInput* funcInput) { + OpenABEPolicy *policy = nullptr; + OpenABEAttributeList *attr_list = nullptr; + ASSERT_NOTNULL(funcInput); + if(key->inputType == FUNC_ATTRLIST_INPUT && + funcInput->getFunctionType() == FUNC_POLICY_INPUT) { + policy = (OpenABEPolicy *) funcInput; + attr_list = (OpenABEAttributeList *) key->input.get(); + } + else if(key->inputType == FUNC_POLICY_INPUT && + funcInput->getFunctionType() == FUNC_ATTRLIST_INPUT) { + policy = (OpenABEPolicy *) key->input.get(); + attr_list = (OpenABEAttributeList *) funcInput; + } + else { + /* throw an error - invalid input on either key or ciphertext (most likely ciphertext) */ + throw OpenABE_ERROR_INVALID_CIPHERTEXT_HEADER; + } + return checkIfSatisfied(policy, attr_list); +} + +const std::string +OpenABEKeystoreManager::searchKeyCommand(OpenABEKeyQuery* query, OpenABEFunctionInput *func_input) { + // call search key on the functional input + std::lock_guard lock(ks_lock_); + return searchKey(query, func_input); +} + +vector +OpenABEKeystoreManager::deleteKeyCommand(OpenABEKeyQuery* query) { + ASSERT_NOTNULL(query); + vector keyList; + + std::lock_guard lock(ks_lock_); + keyList = getKeyIds(query->userId, query->currentTime); + + if (query->currentTime > 0) { + // prune keys based on expiration date and userIds + if (keyList.size() > 0) cout << "Pruning " << keyList.size() << " expired keys ..." << endl; + } else if(query->userId != "") { + // delete user from active user list + this->activeUsers_.erase(query->userId); + } else { + throw runtime_error("OpenABEKeystoreManager::deleteKeyCommand: invalid delete query."); + } + + for (size_t i = 0; i < keyList.size(); i++) { + //cout << "Delete key with Id: " << keyList[i] << " for " << query->userId << endl; + this->deleteKey(keyList[i]); + } + return keyList; +} + +const string +OpenABEKeystoreManager::searchKey(OpenABEKeyQuery* query, OpenABEFunctionInput *funcInput) { + ASSERT_NOTNULL(query); + ASSERT_NOTNULL(funcInput); + vector satKeys; + // initial set of keys that are available that could satisfy the input ciphertext + vector keyRefs = filterKeys(query->userId, funcInput->getFunctionType()); + // rank/sort keys based on the contents of the query + rankKeyAlgorithm(keyRefs, query); + // test and evaluat each key + for(size_t i = 0; i < keyRefs.size(); i++) { + assert(keyMetadata_.count(keyRefs[i]) != 0); + pair result = testAKey(keyMetadata_[keyRefs[i]], funcInput); + bool is_satisfied = result.first; + if (is_satisfied) { + /* returns the key identifier that satisfies the query */ + if(query->isEfficient) { + KeyRef p = make_pair(keyRefs[i], result.second); + satKeys.push_back(p); + } else { + // if efficiency is not a concern, then return + // the first key that would satisfy the func input + return keyRefs[i]; + } + } + } + + // check whether query dictates first satisfied vs. all satisfied + if(satKeys.size() > 0) { + std::sort(satKeys.begin(), satKeys.end(), key_ref_compare()); + return satKeys[0].first; + } + /* error since no key was found -- indicates that a key request needs to be formed */ + return ""; +} + +/******************************************************************************** + * OpenABEKeystoreManager utility methods for ciphertexts and keys + ********************************************************************************/ + +OpenABEFunctionInputType getFunctionInputType(OpenABEKey *key) { + OpenABE_SCHEME scheme_type = OpenABE_getSchemeID(key->getAlgorithmID()); + // check the scheme type + switch(scheme_type) { + case OpenABE_SCHEME_CP_WATERS: + case OpenABE_SCHEME_CP_WATERS_CCA: + return FUNC_ATTRLIST_INPUT; + break; + case OpenABE_SCHEME_KP_GPSW: + case OpenABE_SCHEME_KP_GPSW_CCA: + return FUNC_POLICY_INPUT; + break; + default: + break; + } + return FUNC_INVALID_INPUT; +} + +/* + * NOTE: caller is responsible for deleting memory associated with OpenABEFunctionInput + */ +unique_ptr getFunctionInput(OpenABEKey *key) { + OpenABE_SCHEME scheme_type = OpenABE_getSchemeID(key->getAlgorithmID()); + OpenABEByteString *policy_str = NULL; + OpenABEAttributeList *attrList = NULL; + unique_ptr policy = nullptr; + + // check the scheme type + switch(scheme_type) { + case OpenABE_SCHEME_CP_WATERS: + case OpenABE_SCHEME_CP_WATERS_CCA: + // attributes are on the key for CP-ABE + attrList = (OpenABEAttributeList*)key->getComponent("input"); + ASSERT_NOTNULL(attrList); + return createAttributeList(attrList->toCompactString()); + break; + case OpenABE_SCHEME_KP_GPSW: + case OpenABE_SCHEME_KP_GPSW_CCA: + // policy on the key for KP-ABE + policy_str = key->getByteString("input"); + ASSERT_NOTNULL(policy_str); + return createPolicyTree(policy_str->toString()); + break; + default: + break; + } + + return nullptr; +} + +} diff --git a/src/utils/zpolicy.cpp b/src/utils/zpolicy.cpp new file mode 100644 index 00000000..04617208 --- /dev/null +++ b/src/utils/zpolicy.cpp @@ -0,0 +1,457 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zpolicy.cpp +/// +/// \brief Implementation for OpenABE policy +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __OpenABEPOLICY_CPP__ + +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the OpenABEPolicy class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEPolicy class. + * + */ + +OpenABEPolicy::OpenABEPolicy() : OpenABEFunctionInput(), + m_rootNode(nullptr), m_hasDuplicates(false), m_enabledRevocation(false) { + this->m_Type = FUNC_POLICY_INPUT; +} + +/*! + * Copy constructor for the OpenABEPolicy class. + * + */ + +OpenABEPolicy::OpenABEPolicy(const OpenABEPolicy ©): OpenABEFunctionInput() { + OpenABETreeNode *root = copy.getRootNode(); + + // Copy the tree (routine can handle a NULL root) + if (root != NULL) { + this->m_rootNode = std::unique_ptr(new OpenABETreeNode(root)); + } else { + this->m_rootNode = nullptr; + } + this->m_hasDuplicates = copy.m_hasDuplicates; + this->m_enabledRevocation = copy.m_enabledRevocation; + this->m_attrDuplicateCount = copy.m_attrDuplicateCount; + this->m_attrCompleteSet = copy.m_attrCompleteSet; + this->m_prefixSet = copy.m_prefixSet; + this->m_Type = copy.m_Type; + this->m_originalInputString = copy.m_originalInputString; +} + +/*! + * Destructor for the OpenABEPolicy class. + * + */ + +OpenABEPolicy::~OpenABEPolicy() { + this->m_rootNode.reset(); +} + + +#if 0 +void +OpenABEPolicy::ConstructTestPolicy() { + if (this->m_rootNode == nullptr) { + this->m_rootNode = std::unique_ptr(new OpenABETreeNode()); + } + + OpenABETreeNode *left = new OpenABETreeNode("Alice"); + OpenABETreeNode *right = new OpenABETreeNode("Bob"); + OpenABETreeNode *right2 = new OpenABETreeNode("Charlie"); + + this->m_rootNode->setNodeType(GATE_TYPE_AND); + this->m_rootNode->addSubnode(left); + this->m_rootNode->addSubnode(right); + this->m_rootNode->addSubnode(right2); +} +#endif + +void +OpenABEPolicy::setRootNode(OpenABETreeNode* subtree) { + this->m_rootNode = std::unique_ptr(subtree); +} + +void +OpenABEPolicy::serialize(OpenABEByteString &result) const { } + +std::unique_ptr createPolicyTree(std::string s) { + oabe::Driver driver(false); + if(s.size() == 0) { + return nullptr; + } + /* construct policy now */ + try { + driver.parse_string(POLICY_PREFIX, s); + return driver.getPolicy(); + } catch(OpenABE_ERROR & error) { + cerr << "OpenABE Error: " << OpenABE_errorToString(error) << endl; + return nullptr; + } +} + +unique_ptr +addToRootOfInput(zGateType type, const string attribute, OpenABEPolicy* policy) { + ASSERT_NOTNULL(policy); + if(!policy->getRevocationStatus()) { + // add attribute to policy + string new_pol = "("; + new_pol += policy->toCompactString() + ")"; + new_pol += OpenABETreeNode_ToString(type) + attribute; + return createPolicyTree(new_pol); + } else { + // revocation is enabled so must search for the appropriate + // attribute and extend + throw OpenABE_ERROR_NOT_IMPLEMENTED; + } + return nullptr; +} + + +OpenABEPolicy& +OpenABEPolicy::operator=(OpenABEPolicy const &rhs) { + // Protect against self-assignment + if (this != &rhs) { + // Free the pairing structure associated with the current + // object, and move the new one in + this->m_rootNode.reset(); + // set this rootNode to the rhs and perform copy via OpenABETreeNode class + this->m_rootNode = std::unique_ptr(new OpenABETreeNode(rhs.getRootNode())); + } + + return *this; +} + +void +OpenABEPolicy::setDuplicateInfo(std::map& attr_count, std::set& attr_list) { + if(attr_list.size() > 0) { + this->m_hasDuplicates = true; + // set::iterator it; + for(auto it = attr_list.begin(); it != attr_list.end(); ++it) { + // copy over data for the duplicate attributes only (ignore everything else) + this->m_attrDuplicateCount[ *it ] = attr_count[ *it ]; + // cout << "Duplicate: " << *it << " => " << this->m_attrDuplicateCount[*it] << endl; + } + } + + // record the list of attributes (for easy access) + for (auto& it : attr_count) { + // cout << "ATTR: " << it.first << endl; + this->m_attrCompleteSet.insert(it.first); + } +} + +void +OpenABEPolicy::setPrefixSet(set& prefix_set) { + m_prefixSet = prefix_set; +} + +/******************************************************************************** + * Implementation of the OpenABETreeNode class + ********************************************************************************/ + +/*! + * Constructor. + * + */ + +OpenABETreeNode::OpenABETreeNode() : m_nodeType(GATE_TYPE_NONE), m_thresholdValue(0), + m_numSubnodes(0), m_Mark(false), m_Prefix(""), + m_Label(""), m_Index(0), m_Visited(false) { +} + +/*! + * Constructor for leaf nodes + * + */ + +OpenABETreeNode::OpenABETreeNode(string label, string prefix, int index) : + m_nodeType(GATE_TYPE_LEAF), m_thresholdValue(0), + m_numSubnodes(0), m_Mark(false), m_Prefix(prefix), + m_Label(label), m_Index(index), m_Visited(false) { +} + +/*! + * Get the threshold value, which is computed based on the gate type. + * + * @return - the threshold value of this gate as an int + * @throw - an exception if there is a problem sharing the element + */ + +uint32_t +OpenABETreeNode::getThresholdValue() { + uint32_t result = 0; + + // Handle each case + switch(this->m_nodeType) { + case GATE_TYPE_AND: + result = this->getNumSubnodes(); + break; + case GATE_TYPE_OR: + result = 1; + break; + case GATE_TYPE_THRESHOLD: + result = this->m_thresholdValue; + break; + default: + OpenABE_LOG_AND_THROW("Illegal gate type", OpenABE_ERROR_INVALID_POLICY); + break; + } + + return result; +} + +/*! + * Get the subnode at position "index". + * + * @param - the parameter to return + * @return - the subnode + * @throw - an exception if the subnode doesn't exist + */ + +OpenABETreeNode* +OpenABETreeNode::getSubnode(uint32_t index) { + if (index >= this->getNumSubnodes()) { + OpenABE_LOG_AND_THROW("Invalid policy subnode requested", OpenABE_ERROR_INVALID_INPUT); + } + + return this->m_Subnodes[index]; +} + +/*! + * Copy constructor. Recursively copy the given subtree. + * + * @throw - an exception if there is a problem copying the policy + */ + +OpenABETreeNode::OpenABETreeNode(OpenABETreeNode *copy) { + if (copy == NULL) { + OpenABE_LOG_AND_THROW("Copy with NULL pointer", OpenABE_ERROR_UNKNOWN); + } + + this->m_nodeType = copy->m_nodeType; + if(this->m_nodeType == GATE_TYPE_LEAF) { + this->m_Prefix = copy->m_Prefix; + this->m_Label = copy->m_Label; + return; + } + + this->m_thresholdValue = copy->m_thresholdValue; + this->m_numSubnodes = copy->m_numSubnodes; + // reset state in copied object (we want to copy nodes only) + this->m_Mark = false; + this->m_Visited = false; + this->m_Index = copy->m_Index; + // Now copy the subnodes vector. This is a vector of pointers + // so we need to actually allocate memory and copy. + + // First, copy the vector itself. + this->m_Subnodes = copy->m_Subnodes; + + // Now instantiate a new OpenABETreeNode for each pointer in the vector. + // This will recursively call (this) copy constructor for all + // subnodes. + for (uint32_t i = 0; i < this->m_Subnodes.size(); i++) { + this->m_Subnodes[i] = new OpenABETreeNode(copy->m_Subnodes[i]); + // reset state in copied object (we want to copy nodes only) + this->m_Subnodes[i]->m_Mark = false; + this->m_Subnodes[i]->m_Visited = false; + } +} + + +/*! + * Convert a given subtree to a string. + * + */ +string +OpenABETreeNode::toString() { + string op = ""; + string tree = ""; + stringstream tmp; + /* Initialize threshold to 0 to avoid false positive gcc + variable uninitialized warning */ + int threshold = 0; + bool recurse = false; + if(this->m_nodeType == GATE_TYPE_LEAF) { + if(this->m_Prefix != "") { + const string thePrefix = this->m_Prefix + COLON; + return thePrefix + this->m_Label; + } + return this->m_Label; + } + + switch(this->m_nodeType) { + case GATE_TYPE_AND: + op = " and "; + threshold = this->m_Subnodes.size(); + recurse = true; + break; + case GATE_TYPE_OR: + op = " or "; + threshold = 1; + recurse = true; + break; + case GATE_TYPE_THRESHOLD: + tmp << this->m_thresholdValue << " of "; + op = tmp.str(); + break; + default: + OpenABE_LOG_AND_THROW("Illegal gate type", OpenABE_ERROR_INVALID_POLICY); + break; + } + + if(this->m_Subnodes.size() == 2) { + tree += "("; + if(recurse) { + tree += this->m_Subnodes[0]->toString() + op + this->m_Subnodes[1]->toString(); + } + tree += ")"; + } + else { + if(this->m_nodeType == GATE_TYPE_AND || this->m_nodeType == GATE_TYPE_OR) { + tmp << threshold << " of "; + tree = tmp.str(); + } + tree += "("; + for (uint32_t i = 0; i < this->m_Subnodes.size(); i++) { + tree += this->m_Subnodes[i]->toString() + ", "; + } + tree.erase(tree.size()-2, tree.size()); + tree += ")"; + } + + return tree; +} + +/* + * Iterative pre-order traversal to set each m_Mark and m_Visited flags to false + */ +bool resetFlags(OpenABETreeNode *root) { + std::stack stack; + OpenABETreeNode *top = nullptr; + if(root == nullptr) + return false; + stack.push(root); + + while(!stack.empty()) { + // visit the top element on the stack, then pop it + top = stack.top(); + // reset flags here top and move on + top->setMark(false, 0); + top->m_Visited = false; + // pop element + stack.pop(); + + if(top->getNodeType() != GATE_TYPE_LEAF) { + // visit children of node and push them on the stack + for(size_t i = 0; i < top->getNumSubnodes(); i++) { + stack.push(top->getSubnode(i)); + } + } + } + + return true; +} + +/*! + * Destructor. Dereference any memory used by this structure. + * + * @throw - an exception if there is a problem + */ + +OpenABETreeNode::~OpenABETreeNode() { + // Go through each subnode. + for (uint32_t i = 0; i < this->m_Subnodes.size(); i++) { + if (this->m_Subnodes[i] != NULL) { + uint32_t count = this->m_Subnodes[i]->getRefCount(); + for (uint32_t j = 0; j < count; j++) + this->m_Subnodes[i]->deRef(); + } + } +} + +void +OpenABETreeNode::addSubnode(OpenABETreeNode *subnode) { + this->m_Subnodes.push_back(subnode); + this->m_numSubnodes++; +} + +const char* +OpenABETreeNode_ToString(zGateType type) { + switch(type) { + case GATE_TYPE_OR: + return " or "; + break; + case GATE_TYPE_AND: + return " and "; + break; + case GATE_TYPE_THRESHOLD: + return " of "; + break; + default: + break; + } + + return ""; +} + +std::vector &split(const std::string &s, char delim, std::vector &elems) { + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + if(!item.empty()) { + elems.push_back(item); + } + } + return elems; +} + +std::vector split(const std::string &s, char delim) { + std::vector elems; + split(s, delim, elems); + return elems; +} + +} diff --git a/src/utils/zx509.cpp b/src/utils/zx509.cpp new file mode 100644 index 00000000..5bc03749 --- /dev/null +++ b/src/utils/zx509.cpp @@ -0,0 +1,677 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zx509.cpp +/// +/// \brief X.509 certificate handling functionality +/// +/// \author Alan Dunn +/// + +#include +#include +#undef BN_BITS +#undef BN_BYTES +#include +#include +#include +#include + +using namespace std; +using namespace oabe::crypto; + +namespace oabe { + +DistinguishedName::DistinguishedName() = default; +DistinguishedName::~DistinguishedName() = default; + +class DistinguishedName::Impl { +public: + Impl(const vector>& myRdnPairs) + : rdnPairs(myRdnPairs) {} + + vector> rdnPairs; +}; + +void DistinguishedName::makeDistinguishedName( + DistinguishedName& dn, + const vector>& rdnPairs) { + dn.ptr_.reset(new Impl(rdnPairs)); +} + +bool KeyCertifier::addDnToX509Name(const DistinguishedName& dn, + X509_NAME* name) { + int rc; + + if (!name) { + return false; + } + + for (auto& rdn : dn.ptr_->rdnPairs) { + const char* label = + (char*)rdn.first.c_str(); + const string& value_str = rdn.second; + const unsigned char* value = + (unsigned char*)value_str.c_str(); + rc = X509_NAME_add_entry_by_txt(name, label, MBSTRING_ASC, + value, value_str.size(), -1, 0); + if (rc != 1) { + return false; + } + } + + return true; +} + +void KeyCertifier::fromKeyString(KeyCertifier& certifier, + const string& privateKey) { + stringToPkey(&certifier.privateKey_, privateKey, 1); + if (!certifier.privateKey_) { + throw CryptoException("Key misformatted"); + } +} + +// OpenSSL finds certificates in chains for verifying based upon +// matching subject DN to issuer DN. As a result, we need to add a +// distinguished name to the certificates we issue and the CA cert, +// but it doesn't need to signify anything. +static void getBogusDistinguishedName(DistinguishedName& dn) { + vector> rdns; + rdns.push_back(make_pair("C", "XX")); + + DistinguishedName::makeDistinguishedName(dn, rdns); +} + +static bool setCertificateSerialNumber(X509 *cert) +{ + ASN1_INTEGER *sno = ASN1_INTEGER_new(); + BIGNUM *bn = nullptr; + bool result = false; + + if (!sno) { + printf("Unable to allocate memory for " + "an ASN1 object"); + goto out; + } + + bn = BN_new(); + if (!bn) { + ASN1_INTEGER_free(sno); + printf("Unable to allocate memory " + "for an BIGNUM object"); + goto out; + } + + // random for now, but will switch to SHA256(subject, notBefore, notAfter, PK?) + if (BN_pseudo_rand(bn, SERIAL_BITS, 0, 0) == 1 && + (sno = BN_to_ASN1_INTEGER(bn,sno)) != NULL && + X509_set_serialNumber(cert, sno) == 1) + result = true; + else + printf("Unable to create or set the serial number"); + if (bn) + BN_free(bn); + ASN1_INTEGER_free(sno); +out: + return result; +} + +// OpenSSL checks the validity of certificates based on their period +// of validity. Thus we need to adjust the period of validity for +// certificates to use them. +static bool setDaysValid(X509* cert, + int daysValid) { + bool result = false; + const long seconds_in_day = 60*60*24; + + // Backdate the certificate by a day (some period likely long + // enough to escape synchronization issues) since otherwise lack + // of timing synchronization between remote server and local + // server can cause certificate verification to fail (certificate + // server presents will seem not yet valid). + if (!X509_gmtime_adj(X509_get_notBefore(cert), + (long)-seconds_in_day)) { + goto out; + } + if (!X509_gmtime_adj(X509_get_notAfter(cert), + (long)seconds_in_day*daysValid)) { + goto out; + } + + result = true; + + out: + return result; +} + +void KeyCertifier::generateCertificate(string& cert, + const string& publicKey, + const string& commonName, + int daysValid) { + vector> subjectRdns; + subjectRdns.push_back(make_pair("CN", commonName)); + DistinguishedName subjectDn; + DistinguishedName::makeDistinguishedName(subjectDn, subjectRdns); + DistinguishedName issuerDn; + getBogusDistinguishedName(issuerDn); + + generateCertificate(cert, + publicKey, + issuerDn, + subjectDn, + daysValid); +} + +void KeyCertifier::generateCertificate(string& cert, + const string& publicKey, + const DistinguishedName& issuerDn, + const DistinguishedName& subjectDn, + int daysValid) { + X509* x509_cert = nullptr; + X509_NAME* issuer_name, *subject_name; + EVP_PKEY* pkey = nullptr; + string error_msg(""); + bool rc; + + stringToPkey(&pkey, publicKey, 0); + if (!pkey) { + error_msg = "Key misformatted"; + goto out; + } + + x509_cert = X509_new(); + if (!x509_cert) { + error_msg = "X509_new"; + goto out; + } + + // Set the valid period in the certificate + if (!setDaysValid(x509_cert, daysValid)) { + error_msg = "setDaysValid"; + goto out; + } + + // Add distinguished names to certificate + issuer_name = X509_get_issuer_name(x509_cert); + rc = addDnToX509Name(issuerDn, issuer_name); + if (!rc) { + error_msg = "addDnToX509Name(issuer)"; + goto out; + } + + subject_name = X509_get_subject_name(x509_cert); + rc = addDnToX509Name(subjectDn, subject_name); + if (!rc) { + error_msg = "addDnToX509Name(subject)"; + } + + // Add public key for the corresponding certificate to the X509 + // certificate + if (!X509_set_pubkey(x509_cert, pkey)) { + error_msg = "X509_set_pubkey"; + goto out; + } + + // Add serial number to certificate + if (!setCertificateSerialNumber(x509_cert)) { + error_msg = "setCertificateSerialNumber"; + goto out; + } + + // Finalize the certificate + if (!X509_sign(x509_cert, privateKey_, EVP_sha256())) { + error_msg = "X509_sign"; + goto out; + } + + if (!x509ToPemString(cert, x509_cert)) { + error_msg = "x509ToPemString"; + goto out; + } + + out: + if (pkey) { + EVP_PKEY_free(pkey); + } + if (x509_cert) { + X509_free(x509_cert); + } + + if (error_msg != "") { + throw CryptoException(error_msg); + } +} + +KeyCertifier::~KeyCertifier() { + if (privateKey_) { + EVP_PKEY_free(privateKey_); + } +} + +void certifyKeyAsCA(std::string& cert, + const std::string& privateKey, + int daysValid) { + KeyCertifier kc; + KeyCertifier::fromKeyString(kc, privateKey); + + string publicKey; + demotePrivateKey(publicKey, + privateKey); + + DistinguishedName bogusDn; + getBogusDistinguishedName(bogusDn); + kc.generateCertificate(cert, + publicKey, + bogusDn, + bogusDn); +} + +int getFirstSubjectCommonName(std::string &out, X509* cert) { + X509_NAME* name = X509_get_subject_name(cert); + int idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1); + if (idx == -1) { + return 0; + } + int rc = -1; + X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx); + ASN1_STRING* commonName = X509_NAME_ENTRY_get_data(entry); + + unsigned char* utf8 = nullptr; + int size = ASN1_STRING_to_UTF8(&utf8, commonName); + if (size < 0) { + goto out; + } + + out.assign((char *)utf8, size); + rc = 1; + + out: + if (utf8) { + OPENSSL_free(utf8); + } + return rc; +} + +static inline void BN_to_ByteString(const BIGNUM *bn, OpenABEByteString& serial) { + serial.clear(); + int to_len = BN_num_bytes(bn); + uint8_t to[to_len]; + BN_bn2bin(bn, to); + + // return the serial number + serial.appendArray((uint8_t*)to, to_len); + return; +} + +int getSerialNumber(OpenABEByteString& serial, X509* cert) { + assert(cert != nullptr); + string error_msg = ""; + int rv = -1; + BIGNUM *bn_serial = nullptr; + + ASN1_INTEGER *_serial = X509_get_serialNumber(cert); + if (!_serial) { + cerr << "get serial number failed" << endl; + return rv; + } + + bn_serial = ASN1_INTEGER_to_BN(_serial, NULL); + if (!bn_serial) { + cerr << "asn1 to integer failed" << endl; + return rv; + } + + BN_to_ByteString(bn_serial, serial); + rv = 1; + + if (bn_serial) + BN_free(bn_serial); + + return rv; +} + + +CertRevList::CertRevList(const string& crl_path) { + crl_path_ = crl_path; + crl_ = nullptr; + crlNumber_ = -1; + revListSet_ = false; +} + +CertRevList::~CertRevList() { + if (crl_) { + X509_CRL_free(crl_); + } +} + +void CertRevList::createNewCrl(const std::string& ca_cert, const string& ca_privKey) { + assert(crl_ == nullptr); + string error_msg = ""; + EVP_PKEY *pkey = nullptr; + X509 *cert = nullptr; +// X509_CRL_INFO *ci = nullptr; + long version; + ASN1_TIME *lastUpdate = ASN1_UTCTIME_new(); + ASN1_TIME *nextUpdate = ASN1_UTCTIME_new(); + + stringToPkey(&pkey, ca_privKey, true); + if (!pkey) { + error_msg = "Could not load CA private key!"; + goto out; + } + + pemStringToX509(&cert, ca_cert); + if (!cert) { + error_msg = "Could not load CA certificate!"; + goto out; + } + + // X509_check_private_key + + crl_ = X509_CRL_new(); + if(!crl_) { + error_msg = "Could not allocate X509 CRL structure!"; + goto out; + } + + if (!X509_CRL_set_issuer_name(crl_, X509_get_subject_name(cert))) { + error_msg = "Could not set issuer name in CRL."; + goto out; + } + + lastUpdate = X509_gmtime_adj(lastUpdate, 0); + X509_CRL_set_lastUpdate(crl_, lastUpdate); + + nextUpdate = X509_gmtime_adj(nextUpdate, CRL_UPDATE_SCHED); + X509_CRL_set_nextUpdate(crl_, nextUpdate); + + version = X509_get_version(cert); + X509_CRL_set_version(crl_, ++version); + +// ci = crl_->crl; +// ci->issuer = X509_NAME_dup(cert->cert_info->subject); +// assert(ci->issuer != nullptr); +// +// X509_gmtime_adj(ci->lastUpdate, 0); +// if (ci->nextUpdate == nullptr) { +// ci->nextUpdate = ASN1_UTCTIME_new(); +// } +// X509_gmtime_adj(ci->nextUpdate, CRL_UPDATE_SCHED); +// if (!ci->revoked) { +// ci->revoked = sk_X509_REVOKED_new_null(); +// } +//// if (crlNumber_ >= 0) { +//// if (crl_->crl_number == nullptr) +//// crl_->crl_number = ASN1_INTEGER_new(); +//// ASN1_INTEGER_set(crl_->crl_number, crlNumber_); +//// } +// +// if (ci->version == nullptr) { +// ci->version = ASN1_INTEGER_new(); +// } +// +// version = ASN1_INTEGER_get(cert->cert_info->version); +// ASN1_INTEGER_set(ci->version, ++version); + + if (!X509_CRL_sign(crl_, pkey, EVP_sha256())) { + error_msg = "Could not sign the CRL list"; + goto out; + } + + writeCrlFile(); +out: + if (lastUpdate) + ASN1_UTCTIME_free(lastUpdate); + + if (nextUpdate) + ASN1_UTCTIME_free(nextUpdate); + + if (pkey) + EVP_PKEY_free(pkey); + + if (cert) + X509_free(cert); + + if (error_msg != "") { + throw CryptoException(error_msg); + } +} + +// load CRL from an existing file +bool CertRevList::loadCrlFile() { + bool result = true; + if (crl_ != nullptr) return result; // already loaded + + BIO* io = BIO_new_file((const char *)crl_path_.c_str(), "r"); + assert(io != nullptr); + crl_ = PEM_read_bio_X509_CRL(io, NULL, NULL, NULL); + + if (crl_ == nullptr) { + cerr << "Could not load the CRL list" << endl; + result = false; + } + + BIO_free(io); + return result; +} + +bool CertRevList::revokeCertificate(const string& client_cert) { + bool result = false; + string error_msg = ""; + X509_REVOKED* xr = nullptr; + X509 *cert = nullptr; + OpenABEByteString serial; + //BIGNUM *bn_serial = nullptr; + ASN1_INTEGER *_serial = nullptr; + ASN1_TIME *revDate = ASN1_TIME_new(); + + if (!crl_) { + error_msg = "Need to load or create a CRL list"; + goto out; + } + + pemStringToX509(&cert, client_cert); + if (!cert) { + error_msg = "Could not load client certificate!"; + goto out; + } + + time_t tm; + time(&tm); + + xr = X509_REVOKED_new(); + assert(xr != nullptr); + ASN1_TIME_set(revDate, tm); + X509_REVOKED_set_revocationDate(xr, revDate); + + // for debug purposes! + getSerialNumber(serial, cert); + cout << "Serial Number: " << serial.toLowerHex() << endl; + // get the serial number + _serial = X509_get_serialNumber(cert); + if (!_serial) { + cerr << "get serial number failed" << endl; + goto out; + } + + // set the serial number in REVOKED struct + X509_REVOKED_set_serialNumber(xr, _serial); + // convert ASN1 to BIGNUM + //bn_serial = ASN1_INTEGER_to_BN(_serial, NULL); + // BIGNUM to asn1 integer + //BN_to_ASN1_INTEGER(bn_serial, xr->serialNumber); + // now can push revoke + X509_CRL_add0_revoked(crl_, xr); + + writeCrlFile(); + + result = true; +out: + if (revDate) + ASN1_TIME_free(revDate); + + //if (bn_serial) + // BN_free(bn_serial); + + if (cert) + X509_free(cert); + + return result; +} + +void CertRevList::writeCrlFile() { + BIO *io = BIO_new_file((const char *)crl_path_.c_str(), "w"); + assert(io != nullptr); + PEM_write_bio_X509_CRL(io, crl_); + if (io) + BIO_free(io); + return; +} + +bool CertRevList::isRevoked(const std::string& client_cert) { + X509 *cert = nullptr; + bool result = false; + string error_msg = ""; + + pemStringToX509(&cert, client_cert); + if (!cert) { + error_msg = "Could not load client certificate!"; + goto out; + } + + result = isRevoked(cert); +out: + if (cert) + X509_free(cert); + + if (error_msg != "") { + throw CryptoException(error_msg); + } + + return result; +} + +bool CertRevList::isRevoked(X509 *cert) { + assert(cert != nullptr); + string byte_str, error_msg = ""; + bool revoked_status = false; + STACK_OF(X509_REVOKED) *rev = nullptr; + X509_REVOKED *r = nullptr; + ASN1_INTEGER *serial = nullptr; + OpenABEByteString byte; + BIGNUM *bn = nullptr; + //BIO *out = nullptr; + + if (!crl_) { + error_msg = "Need to load or create a CRL list"; + goto out; + } + + serial = X509_get_serialNumber(cert); + if (revListSet_) { + // we've optimized CRL loading into memory + // check whether serial is in the revList_ + bn = ASN1_INTEGER_to_BN(serial, NULL); + BN_to_ByteString(bn, byte); + byte_str = byte.toString(); + // loop through each serial number + for(size_t i = 0; i < revList_.size(); i++) { + if (revList_[i].compare(byte_str) == 0) { + revoked_status = true; + break; + } + } + goto out; + } + + // otherwise, let's check the loaded CRL + rev = X509_CRL_get_REVOKED(crl_); + + // out = BIO_new_fp(stdout, BIO_NOCLOSE); + if(sk_X509_REVOKED_num(rev) == 0) { + goto out; + } + BIO_printf(out, "Revoked Certificates:\n"); + + for(int i = 0; i < sk_X509_REVOKED_num(rev); i++) { + r = sk_X509_REVOKED_value(rev, i); + const ASN1_INTEGER *serialNumber = X509_REVOKED_get0_serialNumber(r); + BIO_printf(out," Serial Number: "); + i2a_ASN1_INTEGER(out, serialNumber); + if (ASN1_INTEGER_cmp(serialNumber, serial) == 0) { + // BIO_printf(out, "\n Found the revoked certificate!"); + revoked_status = true; + break; + } + } + +out: + if (bn != nullptr) + BN_free(bn); + + if (error_msg != "") { + throw CryptoException(error_msg); + } + + return revoked_status; +} + +bool CertRevList::loadRevokedList() { + STACK_OF(X509_REVOKED) *rev = nullptr; + X509_REVOKED *r = nullptr; + bool status = false; + OpenABEByteString serial; + BIGNUM *bn_serial = nullptr; + + if (!crl_) { + cerr << "Need to load or create a CRL list" << endl; + goto out; + } + + rev = X509_CRL_get_REVOKED(crl_); + if (sk_X509_REVOKED_num(rev) == 0) { + status = true; + goto out; + } + + revList_.clear(); + for(int i = 0; i < sk_X509_REVOKED_num(rev); i++) { + // get the X509_REVOKED structure + r = sk_X509_REVOKED_value(rev, i); + // get serial number from this structure + const ASN1_INTEGER *serialNumber = X509_REVOKED_get0_serialNumber(r); + bn_serial = ASN1_INTEGER_to_BN(serialNumber, NULL); + BN_to_ByteString(bn_serial, serial); + revList_.push_back(serial.toString()); + BN_free(bn_serial); + } + status = true; +out: + revListSet_ = status; + return status; +} + +} diff --git a/src/zcontext.cpp b/src/zcontext.cpp new file mode 100644 index 00000000..f1ef394a --- /dev/null +++ b/src/zcontext.cpp @@ -0,0 +1,70 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcontext.cpp +/// +/// \brief Base implementation of OpenABE context class +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include + +using namespace std; + +#include + +/******************************************************************************** + * Implementation of the OpenABEContext class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the OpenABEContext base class. + * + */ + +OpenABEContext::OpenABEContext() : ZObject(), m_SecurityLevel(0) { + // initialize the keystore for this context + this->m_RNG_ = nullptr; + this->m_Pairing_ = nullptr; + this->m_EllipticCurve_ = nullptr; + this->m_Keystore_.reset(new OpenABEKeystore); + this->algID = OpenABE_SCHEME_NONE; +} + +/*! + * Destructor for the OpenABEContext base class. + * + */ + +OpenABEContext::~OpenABEContext() {} + +} diff --git a/src/zcrypto_box.cpp b/src/zcrypto_box.cpp new file mode 100644 index 00000000..067cf750 --- /dev/null +++ b/src/zcrypto_box.cpp @@ -0,0 +1,599 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zcrypto_box.cpp +/// +/// \brief Thin wrappers for PKE and ABE scheme contexts. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include + +#include +#include + +using namespace std; + +namespace oabe { + +static const char MASTER_PUBLIC_PARAMS[] = "mpk"; +static const char MASTER_SECRET_PARAMS[] = "msk"; + +static const char PUBLIC_ID[] = "public_"; +static const char PRIVATE_ID[] = "private_"; + +#define OpenABE_PK_PREFIX(a) PUBLIC_ID + a +#define OpenABE_SK_PREFIX(a) PRIVATE_ID + a + +OpenABECryptoContext::OpenABECryptoContext(const std::string scheme_id, bool base64encode) { + scheme_type_ = OpenABE_convertStringToSchemeID(scheme_id); + if (scheme_type_ == OpenABE_SCHEME_NONE) { + throw ZCryptoBoxException("Invalid input: unrecognized scheme ID"); + } + + schemeContextCCA_ = OpenABE_createContextABESchemeCCA(scheme_type_); + if (!schemeContextCCA_) { + throw ZCryptoBoxException("Unable to create ABE scheme context"); + } + + if (scheme_type_ == OpenABE_SCHEME_CP_WATERS) { + keyInputType_ = FUNC_ATTRLIST_INPUT; + encInputType_ = FUNC_POLICY_INPUT; + } else { + // OpenABE_SCHEME_KP_GPSW + keyInputType_ = FUNC_POLICY_INPUT; + encInputType_ = FUNC_ATTRLIST_INPUT; + } + // whether to base-64 encode + base64Encode_ = base64encode; + keyManager_.reset(new OpenABEKeystoreManager); + useKeyManager_ = false; + debug_ = false; +} + +void OpenABECryptoContext::generateParams() { + schemeContextCCA_->generateParams(DEFAULT_BP_PARAM, MASTER_PUBLIC_PARAMS, + MASTER_SECRET_PARAMS); +} + +void OpenABECryptoContext::enableKeyManager(const std::string userId) { + userId_ = userId; + useKeyManager_ = true; +} + +void OpenABECryptoContext::enableVerbose() { + debug_ = true; +} + +void OpenABECryptoContext::keygen(const std::string &keyInput, const std::string &keyID, + const std::string &authID, const std::string &GID) { + unique_ptr keyFuncInput = nullptr; + if (keyInputType_ == FUNC_POLICY_INPUT) { + keyFuncInput = createPolicyTree(keyInput); + } else { + keyFuncInput = createAttributeList(keyInput); + } + + string mpkID = MASTER_PUBLIC_PARAMS, mskID = MASTER_SECRET_PARAMS, gpkID = ""; + if (keyFuncInput != nullptr) { + OpenABE_ERROR result = schemeContextCCA_->keygen(keyFuncInput.get(), keyID, + mpkID, mskID, gpkID, GID); + if (result != OpenABE_NOERROR) { + throw ZCryptoBoxException(OpenABE_errorToString(result)); + } + } else { + throw ZCryptoBoxException("Invalid functional input for ABE key"); + } +} + +void OpenABECryptoContext::exportPublicParams(string &mpk) { + return exportUserKey(MASTER_PUBLIC_PARAMS, mpk); +} + +void OpenABECryptoContext::exportSecretParams(string &msk) { + return exportUserKey(MASTER_SECRET_PARAMS, msk); +} + +void OpenABECryptoContext::exportUserKey(const string &keyID, string &keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString key; + if ((result = this->schemeContextCCA_->exportKey(keyID, key)) != + OpenABE_NOERROR) { + throw ZCryptoBoxException(OpenABE_errorToString(result)); + } + + keyBlob = key.toString(); + if (base64Encode_) + keyBlob = Base64Encode((const uint8_t *)keyBlob.c_str(), keyBlob.size()); +} + +void OpenABECryptoContext::importPublicParams(const std::string &keyBlob) { + importPublicParams(MASTER_PUBLIC_PARAMS, keyBlob); +} + +void OpenABECryptoContext::importPublicParams(const std::string &authID, + const std::string &keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString key; + if (base64Encode_) + key += Base64Decode(keyBlob); + else + key += keyBlob; + + string keyID = authID; + result = schemeContextCCA_->loadMasterPublicParams(keyID, key); + if (result != OpenABE_NOERROR) { + throw ZCryptoBoxException(OpenABE_errorToString(result)); + } +} + +void OpenABECryptoContext::importSecretParams(const std::string &keyBlob) { + this->importSecretParams(MASTER_SECRET_PARAMS, keyBlob); +} + +void OpenABECryptoContext::importSecretParams(const std::string &authID, + const std::string &keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString key; + if (base64Encode_) + key += Base64Decode(keyBlob); + else + key += keyBlob; + + string keyID = ""; + keyID = authID; + + result = schemeContextCCA_->loadMasterSecretParams(keyID, key); + if (result != OpenABE_NOERROR) { + throw ZCryptoBoxException(OpenABE_errorToString(result)); + } +} + +void OpenABECryptoContext::importUserKey(const std::string& keyID, const std::string& keyBlob) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEByteString key; + if (base64Encode_) + key += Base64Decode(keyBlob); + else + key += keyBlob; + + if (!useKeyManager_) + result = schemeContextCCA_->loadUserSecretParams(keyID, key); + else + keyManager_->storeWithKeyIDCommand(userId_, keyID, key, 0); + + if (result != OpenABE_NOERROR) { + throw ZCryptoBoxException(OpenABE_errorToString(result)); + } +} + +bool OpenABECryptoContext::deleteKey(const std::string &keyID) { + return (this->schemeContextCCA_->deleteKey(keyID) == OpenABE_NOERROR); +} + +void OpenABECryptoContext::encrypt(const std::string encInput, + const std::string &plaintext, + std::string &ciphertext) { + OpenABE_ERROR result = OpenABE_NOERROR; + unique_ptr ciphertext1 = nullptr, ciphertext2 = nullptr; + unique_ptr funcInput = nullptr; + + try { + OpenABEByteString ct1, ct2, combined; + + if (encInputType_ == FUNC_POLICY_INPUT) { + funcInput = createPolicyTree(encInput); + } else { + funcInput = createAttributeList(encInput); + } + + if (!funcInput) { + throw ZCryptoBoxException(OpenABE_errorToString(OpenABE_ERROR_INVALID_INPUT)); + } + + ciphertext1.reset(new OpenABECiphertext); + ciphertext2.reset(new OpenABECiphertext); + + string mpkID = MASTER_PUBLIC_PARAMS; + // now we can encrypt + if ((result = schemeContextCCA_->encrypt( + mpkID, funcInput.get(), plaintext, ciphertext1.get(), + ciphertext2.get())) != OpenABE_NOERROR) { + throw ZCryptoBoxException(OpenABE_errorToString(result)); + } + + // serialize the results + ciphertext1->exportToBytes(ct1); + ciphertext2->exportToBytes(ct2); + + // write back to user + combined.pack(ct1); + combined.pack(ct2); + if (base64Encode_) { + const string ct = combined.toString(); + ciphertext = Base64Encode((const uint8_t *)ct.data(), ct.size()); + } else { + ciphertext = combined.toString(); + } + } catch (OpenABE_ERROR &error) { + if (debug_) + cerr << "OpenABECryptoContext::encrypt: " << OpenABE_errorToString(error) << endl; + throw ZCryptoBoxException(OpenABE_errorToString(error)); + } +} + +bool OpenABECryptoContext::decrypt(const std::string &keyID, + const std::string &ciphertext, + std::string &plaintext) { + OpenABE_ERROR result = OpenABE_NOERROR; + unique_ptr ciphertext1 = nullptr, ciphertext2 = nullptr; + + try { + string pt; + OpenABEByteString ct, ct1, ct2; + if (base64Encode_) { + // base64 decode ... + string ct_bin = Base64Decode(ciphertext); + ct += ct_bin; + } else { + ct += ciphertext; + } + size_t index = 0; + ct.unpack(&index, ct1); + ct.unpack(&index, ct2); + + ciphertext1.reset(new OpenABECiphertext); + ciphertext2.reset(new OpenABECiphertext); + + ciphertext1->loadFromBytes(ct1); + ciphertext2->loadFromBytes(ct2); + + string mpkID = MASTER_PUBLIC_PARAMS; + // can now decrypt + if ((result = schemeContextCCA_->decrypt( + mpkID, keyID, plaintext, ciphertext1.get(), ciphertext2.get())) != + OpenABE_NOERROR) { + throw result; + } + return true; + } catch (OpenABE_ERROR &error) { + if (debug_) + cerr << "OpenABECryptoContext::decrypt: " << OpenABE_errorToString(error) << endl; + } + return false; +} + +bool OpenABECryptoContext::decrypt(const std::string &ciphertext, + std::string &plaintext) { + OpenABE_ERROR result = OpenABE_NOERROR; + OpenABEKeyQuery query; + unique_ptr ciphertext1 = nullptr, ciphertext2 = nullptr; + if (!useKeyManager_) { + throw ZCryptoBoxException("Key Manager not enabled!"); + } + + try { + string pt; + OpenABEByteString ct, ct1, ct2; + if (base64Encode_) { + // base64 decode ... + string ct_bin = Base64Decode(ciphertext); + ct += ct_bin; + } else { + ct += ciphertext; + } + size_t index = 0; + ct.unpack(&index, ct1); + ct.unpack(&index, ct2); + + ciphertext1.reset(new OpenABECiphertext); + ciphertext2.reset(new OpenABECiphertext); + + ciphertext1->loadFromBytes(ct1); + ciphertext2->loadFromBytes(ct2); + + string mpkID = MASTER_PUBLIC_PARAMS; + + query.userId = userId_; + query.isEfficient = true; + + unique_ptr funcInput = getFunctionInput(ciphertext1.get()); + const string decKeyId = keyManager_->searchKeyCommand(&query, funcInput.get()); + if (decKeyId == "") { + throw ZCryptoBoxException("Key Manager could not find an appropriate key to decrypt!"); + } + + // load key in the scheme context + pair sk = keyManager_->getKeyCommand(userId_, decKeyId); + if (debug_) { cout << "Found Key: '" << decKeyId << "' => '" << sk.first << "'" << endl; } + if ((result = schemeContextCCA_->loadUserSecretParams(decKeyId, sk.second)) != OpenABE_NOERROR) { + throw result; + } + + // can now decrypt + if ((result = schemeContextCCA_->decrypt( + mpkID, decKeyId, plaintext, ciphertext1.get(), ciphertext2.get())) != + OpenABE_NOERROR) { + throw result; + } + return true; + } catch (OpenABE_ERROR &error) { + if (debug_) + cerr << "OpenABECryptoContext::decrypt: " << OpenABE_errorToString(error) << endl; + } + return false; +} + +/////////////////// OpenABECryptoContext //////////////////////// + +OpenPKEContext::OpenPKEContext(const string ec_id, bool base64encode) { + schemeContext_ = OpenABE_createContextPKESchemeCCA(OpenABE_SCHEME_PK_OPDH); + if (!schemeContext_) { + throw runtime_error("Unable to create PKE scheme context"); + } + ec_id_ = ec_id; + base64Encode_ = base64encode; +} + +void OpenPKEContext::keygen(const string key_id) { + OpenABE_ERROR result; + const string pk_id = OpenABE_PK_PREFIX(key_id); + const string sk_id = OpenABE_SK_PREFIX(key_id); + if (schemeContext_->generateParams(ec_id_) != OpenABE_NOERROR) { + throw runtime_error("Unable to set parameters"); + } + + if ((result = schemeContext_->keygen(key_id, pk_id, sk_id)) != OpenABE_NOERROR) { + throw ZCryptoBoxException(OpenABE_errorToString(result)); + } +} + +void OpenPKEContext::exportPublicKey(const std::string key_id, + std::string &keyBlob) { + OpenABE_ERROR result; + OpenABEByteString public_key; + const string pk_id = OpenABE_PK_PREFIX(key_id); + if ((result = schemeContext_->exportKey(pk_id, public_key)) != OpenABE_NOERROR) { + throw ZCryptoBoxException("exportPublicKey: " + string(OpenABE_errorToString(result))); + } + + if (base64Encode_) { + const string str = public_key.toString(); + keyBlob = Base64Encode((const uint8_t *)str.c_str(), str.size()); + } else + keyBlob = public_key.toString(); +} + +void OpenPKEContext::exportPrivateKey(const std::string key_id, + std::string &keyBlob) { + OpenABE_ERROR result; + OpenABEByteString private_key; + const string sk_id = OpenABE_SK_PREFIX(key_id); + if ((result = schemeContext_->exportKey(sk_id, private_key)) != OpenABE_NOERROR) { + throw ZCryptoBoxException("exportPrivateKey: " + string(OpenABE_errorToString(result))); + } + + if (base64Encode_) { + const string str = private_key.toString(); + keyBlob = Base64Encode((const uint8_t *)str.c_str(), str.size()); + } else + keyBlob = private_key.toString(); +} + +void OpenPKEContext::importPublicKey(const string key_id, const string &keyBlob) { + OpenABE_ERROR result; + OpenABEByteString key_buf; + const string pk_id = OpenABE_PK_PREFIX(key_id); + if (base64Encode_) + key_buf += Base64Decode(keyBlob); + else + key_buf = keyBlob; + + if ((result = schemeContext_->loadPublicKey(pk_id, key_buf)) != OpenABE_NOERROR) { + throw ZCryptoBoxException("importPublicKey: " + string(OpenABE_errorToString(result))); + } +} + +void OpenPKEContext::importPrivateKey(const string key_id, const string &keyBlob) { + OpenABE_ERROR result; + OpenABEByteString key_buf; + const string sk_id = OpenABE_SK_PREFIX(key_id); + if (base64Encode_) + key_buf += Base64Decode(keyBlob); + else + key_buf = keyBlob; + + if ((result = schemeContext_->loadPrivateKey(sk_id, key_buf)) != + OpenABE_NOERROR) { + throw ZCryptoBoxException("importPrivateKey: " + string(OpenABE_errorToString(result))); + } +} + +bool OpenPKEContext::encrypt(const string receiver_id, const string &plaintext, + string &ciphertext) { + OpenABE_ERROR result; + OpenABECiphertext ct; + OpenABEByteString ct_buf; + + if ((result = schemeContext_->encrypt(nullptr, OpenABE_PK_PREFIX(receiver_id), + OpenABE_PK_PREFIX(receiver_id), plaintext, + &ct)) != OpenABE_NOERROR) { + throw ZCryptoBoxException("encrypt: " + string(OpenABE_errorToString(result))); + } + ct.exportToBytes(ct_buf); + if (base64Encode_) { + const string str = ct_buf.toString(); + ciphertext = Base64Encode((const uint8_t *)str.c_str(), str.size()); + } else + ciphertext = ct_buf.toString(); + + return true; +} + +bool OpenPKEContext::decrypt(const string receiver_id, const string &ciphertext, + string &plaintext) { + OpenABE_ERROR result; + OpenABEByteString ct_buf; + OpenABECiphertext ct; + if (base64Encode_) { + ct_buf += Base64Decode(ciphertext); + } else + ct_buf += ciphertext; + // now we can convert into a OpenABECiphertext structure + ct.loadFromBytes(ct_buf); + + if ((result = schemeContext_->decrypt(OpenABE_PK_PREFIX(receiver_id), + OpenABE_SK_PREFIX(receiver_id), plaintext, + &ct)) != OpenABE_NOERROR) { + return false; + } + return true; +} + +OpenPKSIGContext::OpenPKSIGContext(const string ec_id, bool base64encode) { + schemeContext_ = OpenABE_createContextPKSIGScheme(); + if (!schemeContext_) { + throw runtime_error("Unable to create PKSIG scheme context"); + } + ec_id_ = ec_id; + base64Encode_ = base64encode; +} + +void OpenPKSIGContext::keygen(const string key_id) { + OpenABE_ERROR result; + const string pk_id = OpenABE_PK_PREFIX(key_id); + const string sk_id = OpenABE_SK_PREFIX(key_id); + if (schemeContext_->generateParams(ec_id_) != OpenABE_NOERROR) { + throw runtime_error("Unable to set parameters"); + } + + if ((result = schemeContext_->keygen(pk_id, sk_id)) != OpenABE_NOERROR) { + throw ZCryptoBoxException(OpenABE_errorToString(result)); + } +} + +void OpenPKSIGContext::exportPublicKey(const std::string key_id, + std::string &keyBlob) { + OpenABE_ERROR result; + OpenABEByteString public_key; + const string pk_id = OpenABE_PK_PREFIX(key_id); + if ((result = schemeContext_->exportKey(pk_id, public_key)) != OpenABE_NOERROR) { + throw ZCryptoBoxException("exportPublicKey: " + string(OpenABE_errorToString(result))); + } + + if (base64Encode_) { + const string str = public_key.toString(); + keyBlob = Base64Encode((const uint8_t *)str.c_str(), str.size()); + } else + keyBlob = public_key.toString(); +} + +void OpenPKSIGContext::exportPrivateKey(const std::string key_id, + std::string &keyBlob) { + OpenABE_ERROR result; + OpenABEByteString private_key; + const string sk_id = OpenABE_SK_PREFIX(key_id); + if ((result = schemeContext_->exportKey(sk_id, private_key)) != OpenABE_NOERROR) { + throw ZCryptoBoxException("exportPrivateKey: " + string(OpenABE_errorToString(result))); + } + + if (base64Encode_) { + const string str = private_key.toString(); + keyBlob = Base64Encode((const uint8_t *)str.c_str(), str.size()); + } else + keyBlob = private_key.toString(); +} + +void OpenPKSIGContext::importPublicKey(const string key_id, const string &keyBlob) { + OpenABE_ERROR result; + OpenABEByteString key_buf; + const string pk_id = OpenABE_PK_PREFIX(key_id); + if (base64Encode_) + key_buf += Base64Decode(keyBlob); + else + key_buf = keyBlob; + + if ((result = schemeContext_->loadPublicKey(pk_id, key_buf)) != OpenABE_NOERROR) { + throw ZCryptoBoxException("importPublicKey: " + string(OpenABE_errorToString(result))); + } +} + +void OpenPKSIGContext::importPrivateKey(const string key_id, + const string &keyBlob) { + OpenABE_ERROR result; + OpenABEByteString key_buf; + const string sk_id = OpenABE_SK_PREFIX(key_id); + if (base64Encode_) + key_buf += Base64Decode(keyBlob); + else + key_buf = keyBlob; + + if ((result = schemeContext_->loadPrivateKey(sk_id, key_buf)) != + OpenABE_NOERROR) { + throw ZCryptoBoxException("importPrivateKey: " + string(OpenABE_errorToString(result))); + } +} + +void OpenPKSIGContext::sign(const std::string key_id, const std::string &message, + std::string &signature) { + OpenABE_ERROR result; + OpenABEByteString msg, sig; + const string sk_id = OpenABE_SK_PREFIX(key_id); + msg = message; + if ((result = schemeContext_->sign(sk_id, &msg, &sig)) != OpenABE_NOERROR) { + throw ZCryptoBoxException("sign: " + string(OpenABE_errorToString(result))); + } + + if (base64Encode_) { + const string str = sig.toString(); + signature = Base64Encode((const uint8_t *)str.c_str(), str.size()); + } else + signature = sig.toString(); +} + +bool OpenPKSIGContext::verify(const std::string key_id, const std::string &message, + const std::string &signature) { + OpenABE_ERROR result; + OpenABEByteString msg, sig; + if (base64Encode_) + sig += Base64Decode(signature); + else + sig += signature; + + const string pk_id = OpenABE_PK_PREFIX(key_id); + msg = message; + if ((result = schemeContext_->verify(pk_id, &msg, &sig)) != OpenABE_NOERROR) { + cerr << "Failed to verify: " << string(OpenABE_errorToString(result)) << endl; + return false; + } + return true; +} + +} diff --git a/src/zml/zelement.c b/src/zml/zelement.c new file mode 100644 index 00000000..f5732ffa --- /dev/null +++ b/src/zml/zelement.c @@ -0,0 +1,912 @@ +/// +/// \file zelement.c +/// +/// \brief Class implementation for generic ZP_t and G_t elements. +/// Works either with OpenSSL or RELIC. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(BP_WITH_OPENSSL) +#define EC_WITH_OPENSSL +#define BN_WITH_OPENSSL +#endif + +/******************************************************************************** + * ZML abstract C operations for bignum operations + ********************************************************************************/ +void zml_init() { +#if !defined(BP_WITH_OPENSSL) + core_init(); + ec_core_init(); +#endif +} + +void zml_clean() { +#if !defined(BP_WITH_OPENSSL) + core_clean(); + ec_core_clean(); +#endif +} + +#if !defined(BP_WITH_OPENSSL) +int zml_check_error() { + ctx_t *ctx = core_get(); + if (ctx != NULL) { + if (ctx->code == STS_OK) + return TRUE; + else + return FALSE; /* means there was an error */ + } + return -1; +} +#endif + +void zml_bignum_init(bignum_t *b) { +#if defined(BN_WITH_OPENSSL) + *b = BN_new(); +#else + bn_null(*b); + bn_new(*b); +#endif +} + +void zml_bignum_copy(bignum_t to, const bignum_t from) { +#if defined(BN_WITH_OPENSSL) + BN_copy(to, from); +#else + bn_copy_const(to, from); +#endif + return; +} + +int zml_bignum_sign(const bignum_t a) { +#if defined(BN_WITH_OPENSSL) + return BN_is_negative(a); +#else + return bn_sign(a); +#endif +} + +int zml_bignum_cmp(const bignum_t a, const bignum_t b) { +#if defined(BN_WITH_OPENSSL) + return BN_cmp(a, b); +#else + return bn_cmp(a, b); +#endif +} + +void zml_bignum_setzero(bignum_t a) { +#if defined(BN_WITH_OPENSSL) + BN_zero(a); +#else + bn_zero(a); +#endif +} + +int zml_bignum_countbytes(const bignum_t a) { +#if defined(BN_WITH_OPENSSL) + return BN_num_bytes(a); +#else + return bn_size_bin(a); +#endif +} + +#if !defined(BN_WITH_OPENSSL) +void zml_bignum_rand(bignum_t a, bignum_t o) { + bn_rand(a, BN_POS, bn_bits(o)); +} +#endif + +void zml_bignum_mod(bignum_t x, const bignum_t o) { +#if defined(BN_WITH_OPENSSL) + BN_CTX *ctx = BN_CTX_new(); + BN_mod(x, x, o, ctx); + BN_CTX_free(ctx); +#else + bn_mod(x, x, o); +#endif +} + +void zml_bignum_add(bignum_t r, const bignum_t x, const bignum_t y, + const bignum_t o) { +#if defined(BN_WITH_OPENSSL) + /* computes r = (x+y) mod o */ + BN_CTX *ctx = BN_CTX_new(); + BN_mod_add(r, x, y, o, ctx); + BN_CTX_free(ctx); +#else + bn_add(r, x, y); + bn_mod(r, r, o); +#endif + return; +} + +void zml_bignum_sub(bignum_t r, const bignum_t x, const bignum_t y) { +#if defined(BN_WITH_OPENSSL) + /* computes r = (x-y) */ + BN_sub(r, x, y); +#else + bn_sub(r, x, y); +#endif +} + +void zml_bignum_sub_order(bignum_t r, const bignum_t x, const bignum_t y, + const bignum_t o) { +#if defined(BN_WITH_OPENSSL) + /* computes r = (x-y) mod o */ + BN_CTX *ctx = BN_CTX_new(); + BN_mod_sub(r, x, y, o, ctx); + BN_CTX_free(ctx); +#else + bn_sub(r, x, y); + if (bn_sign(r) == BN_NEG) { + bn_add(r, r, o); + } else { + bn_mod(r, r, o); + } +#endif +} + +void zml_bignum_mul(bignum_t r, const bignum_t x, const bignum_t y, + const bignum_t o) { +#if defined(BN_WITH_OPENSSL) + /* computes r = (x*y) mod o */ + BN_CTX *ctx = BN_CTX_new(); + BN_mod_mul(r, x, y, o, ctx); + BN_CTX_free(ctx); +#else + bn_mul(r, x, y); + if (bn_sign(r) == BN_NEG) { + bn_add(r, r, o); + } else { + bn_mod(r, r, o); + } +#endif +} + +#if !defined(BN_WITH_OPENSSL) +int bn_is_one(const bn_t a) { + if (a->used == 0) + return 0; // false + else if ((a->used == 1) && (a->dp[0] == 1)) + return 1; // true + else + return 0; // false +} +#endif + +void zml_bignum_div(bignum_t r, const bignum_t x, const bignum_t y, + const bignum_t o) { + // r = (1 / y) mod o + zml_bignum_mod_inv(r, y, o); + if (zml_bignum_is_one(x)) + return; // return r + // r = (r * x) mod o + zml_bignum_mul(r, r, x, o); +} + +void zml_bignum_exp(bignum_t r, const bignum_t x, const bignum_t y, + const bignum_t o) { + // r = (x^y) mod o +#if defined(BN_WITH_OPENSSL) + BN_CTX *ctx = BN_CTX_new(); + BN_mod_exp(r, x, y, o, ctx); + BN_CTX_free(ctx); +#else + bn_mxp(r, x, y, o); +#endif +} + +void zml_bignum_lshift(bignum_t r, const bignum_t a, int n) { +#if defined(BN_WITH_OPENSSL) + BN_lshift(r, a, n); +#else + bn_lsh(r, a, n); +#endif +} + +void zml_bignum_rshift(bignum_t r, const bignum_t a, int n) { +#if defined(BN_WITH_OPENSSL) + BN_rshift(r, a, n); +#else + bn_rsh(r, a, n); +#endif +} + +char *zml_bignum_toHex(const bignum_t b, int *length) { + char *hex = NULL; +#if defined(BN_WITH_OPENSSL) + hex = BN_bn2hex(b); + *length = strlen((const char *)hex); +#else + *length = bn_size_str(b, 16); + hex = (char *)malloc(*length+1); + MALLOC_CHECK_OUT_OF_MEMORY(hex); + bn_write_str(hex, *length, b, 16); +#endif + return hex; +} + +char *zml_bignum_toDec(const bignum_t b, int *length) { + char *dec = NULL; +#if defined(BN_WITH_OPENSSL) + dec = BN_bn2dec(b); + *length = strlen(dec); +#else + *length = bn_size_str(b, 10); + dec = (char *)malloc(*length+1); + MALLOC_CHECK_OUT_OF_MEMORY(dec); + bn_write_str(dec, *length, b, 10); +#endif + return dec; +} + +void zml_bignum_negate(bignum_t b, const bignum_t o) { +#if defined(BN_WITH_OPENSSL) + // 0 for +, != 0 for - + BN_set_negative(b, -1); + if (BN_is_negative(b)) { + BN_add(b, b, o); + } +#else + bn_neg(b, b); + if (bn_sign(b) == BN_NEG) { + bn_add(b, b, o); + } +#endif +} + +int zml_bignum_mod_inv(bignum_t a, const bignum_t b, const bignum_t o) { +#if defined(BN_WITH_OPENSSL) + BN_CTX *ctx = BN_CTX_new(); + BN_mod_inverse(a, b, o, ctx); + BN_CTX_free(ctx); + return 1; +#else + bn_t s; + bn_inits(s); + // computes (1 / b) mod o + bn_gcd_ext(s, a, NULL, b, o); + // check if negative + if (bn_sign(a) == BN_NEG) { + bn_add(a, a, o); + } + bn_free(s); + return 1; +#endif +} + +/******************************************************************************** + * ZML abstract C operations for EC operations + ********************************************************************************/ + +int ec_group_init(ec_group_t *group, uint8_t id) { + switch (id) { +#if defined(EC_WITH_OPENSSL) + case OpenABE_NIST_P256_ID: + *group = EC_GROUP_new_by_curve_name(OBJ_sn2nid("prime256v1")); + break; + case OpenABE_NIST_P384_ID: + *group = EC_GROUP_new_by_curve_name(OBJ_sn2nid("secp384r1")); + break; + case OpenABE_NIST_P521_ID: + *group = EC_GROUP_new_by_curve_name(OBJ_sn2nid("secp521r1")); + break; +#else /* RELIC -- group is always NULL b/c parameters are statically defined \ + */ + case OpenABE_NIST_P256_ID: + ec_ep_param_set(NIST_P256); + break; + case OpenABE_NIST_P384_ID: + ec_ep_param_set(NIST_P384); + break; + case OpenABE_NIST_P521_ID: + ec_ep_param_set(NIST_P521); + break; +#endif + default: + return -1; + } + return 0; +} + +void ec_get_order(ec_group_t group, bignum_t order) { +#if defined(EC_WITH_OPENSSL) + EC_GROUP_get_order(group, order, NULL); +#else + // EC group structure is defined as static vars in RELIC + ec_ep_curve_get_ord(order); +#endif +} + +void ec_point_init(ec_group_t group, ec_point_t *e) { +#if defined(EC_WITH_OPENSSL) + *e = EC_POINT_new(group); +#else + ep_null(*e); + ep_new(*e); +#endif +} + +void ec_point_copy(ec_point_t to, const ec_point_t from) { +#if defined(EC_WITH_OPENSSL) + EC_POINT_copy(to, from); +#else + ep_copy_const(to, from); +#endif +} + +void ec_point_set_inf(ec_group_t group, ec_point_t p) { +#if defined(EC_WITH_OPENSSL) + EC_POINT_set_to_infinity(group, p); +#else + ec_ep_set_infty(p); +#endif +} + +int ec_point_is_inf(ec_group_t group, ec_point_t p) { +#if defined(EC_WITH_OPENSSL) + return (EC_POINT_is_at_infinity(group, p) == 1); +#else + // 1 if the point is at infinity, 0 otherise. + return ec_ep_is_infty(p); +#endif +} + +int ec_point_is_on_curve(ec_group_t group, ec_point_t p) { +#if defined(EC_WITH_OPENSSL) + int ret = EC_POINT_is_on_curve(group, p, NULL); + return ret; +#else + if (ec_ep_is_valid(p)) + return 1; +#endif + return 0; +} + +void ec_point_add(ec_group_t g, ec_point_t r, const ec_point_t x, + const ec_point_t y) { +#if defined(EC_WITH_OPENSSL) + EC_POINT_add(g, r, x, y, NULL); +#else + ep_add(r, x, y); + ec_ep_norm(r, r); +#endif +} + +void ec_point_mul(ec_group_t g, ec_point_t r, const ec_point_t x, + const bignum_t y) { +#if defined(EC_WITH_OPENSSL) + EC_POINT_mul(g, r, NULL, x, y, NULL); +#else + //ep_mul(r, x, y); + ec_ep_mul_lwnaf(r, x, y); +#endif +} + +int ec_point_cmp(ec_group_t group, const ec_point_t a, const ec_point_t b) { +#if defined(EC_WITH_OPENSSL) + return EC_POINT_cmp(group, a, b, NULL); +#else + return ec_ep_cmp(a, b); +#endif +} + +void ec_get_coordinates(ec_group_t group, bignum_t x, bignum_t y, + const ec_point_t p) { +#if defined(EC_WITH_OPENSSL) + EC_POINT_get_affine_coordinates_GFp(group, p, x, y, NULL); +#else + ec_fp_prime_back(x, p->x); + ec_fp_prime_back(y, p->y); +#endif + return; +} + +void ec_get_generator(ec_group_t group, ec_point_t p) { +#if defined(EC_WITH_OPENSSL) + EC_POINT_copy(p, EC_GROUP_get0_generator(group)); +#else + ec_ep_curve_get_gen(p); +#endif +} + +#if !defined(EC_WITH_OPENSSL) +size_t ec_point_elem_len(const ec_point_t g) { + return ec_ep_size_bin(g, COMPRESS); +} + +void ec_point_elem_in(ec_point_t g, uint8_t *in, size_t len) { + ec_ep_read_bin(g, in, (int)len); + ec_fp_zero(g->z); + ec_fp_set_dig(g->z, 1); +} + +void ec_point_elem_out(const ec_point_t g, uint8_t *out, size_t len) { + ec_ep_write_bin(out, len, g, COMPRESS); +} +#endif + +int ec_convert_to_point(ec_group_t group, ec_point_t p, uint8_t *xstr, + int len) { +#if defined(EC_WITH_OPENSSL) + EC_POINT_oct2point(group, p, xstr, len, NULL); + if (!EC_POINT_is_on_curve(group, p, NULL)) { + return FALSE; + } + return TRUE; +#else + ec_point_elem_in(p, xstr, len); + return TRUE; +#endif +} + + +int bp_group_init(bp_group_t *group, uint8_t id) { +#if !defined(BP_WITH_OPENSSL) + /* RELIC definitions */ + int twist = EP_DTYPE; // , degree = 2; +#endif + switch (id) { +#if defined(BP_WITH_OPENSSL) + case OpenABE_BN_P254_ID: + *group = BP_GROUP_new_by_curve_name(NID_fp254bnb); + break; + case OpenABE_BN_P256_ID: + *group = NULL; + return -1; + break; +// *group = BP_GROUP_new_by_curve_name(NID_fp256bnb); +// break; +#else /* RELIC -- group is always NULL b/c parameters are statically defined \ + */ + case OpenABE_BN_P254_ID: + ep_param_set(BN_P254); + ep2_curve_set_twist(twist); + break; + case OpenABE_BN_P256_ID: + ep_param_set(BN_P256); + ep2_curve_set_twist(twist); + break; + case OpenABE_BN_P382_ID: + ep_param_set(BN_P382); + ep2_curve_set_twist(twist); + break; +#endif + default: + return -1; + } + return 0; +} + +void bp_get_order(bp_group_t group, bignum_t order) { +#if defined(BP_WITH_OPENSSL) + BP_GROUP_get_order(group, order, NULL); +#else + // EC group structure is defined as static vars in RELIC + // assumes we've called bp_group_init on 'group' + // g1_get_ord + ep_curve_get_ord(order); +#endif +} + +/******************************************************************************** + * ZML abstract C operations for G1 init/arithmetic + ********************************************************************************/ + +void g1_init(bp_group_t group, g1_ptr *e) { +#if defined(BP_WITH_OPENSSL) + *e = G1_ELEM_new(group); +#else + g1_inits(*e); +#endif +} + +void g1_set_to_infinity(bp_group_t group, g1_ptr *e) { +#if defined(BP_WITH_OPENSSL) + *e = G1_ELEM_new(group); + G1_ELEM_set_to_infinity(group, *e); +#else + g1_inits(*e); + g1_set_infty(*e); +#endif +} + +void g1_add_op(bp_group_t group, g1_ptr z, const g1_ptr x, const g1_ptr y) { +#if defined(BP_WITH_OPENSSL) + G1_ELEM_add(group, z, x, y, NULL); +#else + ep_add_projc(z, x, y); + ep_norm(z, z); +#endif +} + +void g1_sub_op(bp_group_t group, g1_ptr z, const g1_ptr x) { +#if defined(BP_WITH_OPENSSL) + int rc = G1_ELEM_invert(group, z, NULL); + if (rc == 1) { + G1_ELEM_add(group, z, x, z, NULL); + } +#else + ep_sub_projc(z, x, z); + ep_norm(z, z); +#endif + +} + +void g1_mul_op(bp_group_t group, g1_ptr z, const g1_ptr x, const bignum_t r) { +#if defined(BP_WITH_OPENSSL) + G1_ELEM_mul(group, z, NULL, x, r, NULL); +#else + g1_mul(z, x, r); +#endif +} + +#if !defined(BP_WITH_OPENSSL) +void g1_rand_op(g1_ptr g) { + ep_rand(g); +} +#endif + +#if defined(BP_WITH_OPENSSL) +static int g1_map_OpenSSL(const bp_group_t group, uint8_t *h, int hlen, + g1_ptr p) { + int result = FALSE; + bignum_t px; + + px = BN_new(); + BN_bin2bn(h, hlen, px); + while (TRUE) { + if (G1_ELEM_set_compressed_coordinates(group, p, px, 0, NULL) == 1) { + // Found a y-coordinate. Now verify that x/y is on the curve + if (G1_ELEM_is_on_curve(group, p, NULL) == 1) { + result = TRUE; + break; + } + } + BN_add(px, px, BN_value_one()); + } + + BN_free(px); + return result; +} +#endif + +void g1_map_op(const bp_group_t group, g1_ptr g, uint8_t *msg, int msg_len) { +#if defined(BP_WITH_OPENSSL) + // now convert digest into a G1 point + g1_map_OpenSSL(group, msg, msg_len, g); +#else + g1_map(g, msg, msg_len); +#endif +} + +#if !defined(BP_WITH_OPENSSL) +size_t g1_elem_len(const g1_ptr g) { + return ep_size_bin(g, COMPRESS); +} + +void g1_elem_in(g1_ptr g, uint8_t *in, size_t len) { + ep_read_bin(g, in, (int)len); +} + +void g1_elem_out(const g1_ptr g, uint8_t *out, size_t len) { + ep_write_bin(out, len, g, COMPRESS); +} + +size_t g2_elem_len(g2_ptr g) { + return ep2_size_bin(g, COMPRESS); +} + +void g2_elem_in(g2_ptr g, uint8_t *in, size_t len) { + ep2_read_bin(g, in, (int)len); +} + +void g2_elem_out(g2_ptr g, uint8_t *out, size_t len) { + ep2_write_bin(out, len, g, COMPRESS); +} + +size_t gt_elem_len(gt_ptr g, int should_compress) { + return fp12_size_bin(g, should_compress); +} + +void gt_elem_in(gt_ptr g, uint8_t *in, size_t len) { + fp12_read_bin(g, in, (int)len); +} + +void gt_elem_out(gt_ptr g, uint8_t *out, size_t len, int should_compress) { + fp12_write_bin(out, len, g, should_compress); +} + +#endif + +/******************************************************************************** + * ZML abstract C operations for G2 init/arithmetic + ********************************************************************************/ + +void g2_init(bp_group_t group, g2_ptr *e) { +#if defined(BP_WITH_OPENSSL) + *e = G2_ELEM_new(group); +#else + ep2_inits(*e); +#endif +} + +void g2_set_to_infinity(bp_group_t group, g2_ptr *e) { +#if defined(BP_WITH_OPENSSL) + *e = G2_ELEM_new(group); + G2_ELEM_set_to_infinity(group, *e); +#else + ep2_inits(*e); + // g2_set_infty + ep2_set_infty(*e); +#endif +} + +void g2_mul_op(bp_group_t group, g2_ptr z, g2_ptr x, bignum_t r) { +#if defined(BP_WITH_OPENSSL) + G2_ELEM_mul(group, z, NULL, x, r, NULL); +#else + // g2_mul(z, x, r); + ep2_mul_lwnaf(z, x, r); +#endif +} + +int g2_cmp_op(bp_group_t group, g2_ptr x, g2_ptr y) { +#if defined(BP_WITH_OPENSSL) + return G2_ELEM_cmp(group, x, y, NULL); +#else + return ep2_cmp(x, y); +#endif +} + +/******************************************************************************** + * abstract C operations for GT init/arithmetic + ********************************************************************************/ + +void gt_init(const bp_group_t group, gt_ptr *e) { +#if defined(BP_WITH_OPENSSL) + *e = GT_ELEM_new(group); +#else + fp12_inits(*e); +#endif +} + +void gt_set_to_infinity(bp_group_t group, gt_ptr *e) { +#if defined(BP_WITH_OPENSSL) + *e = GT_ELEM_new(group); + GT_ELEM_set_to_unity(group, *e); +#else + fp12_inits(*e); + // gt_set_unity + fp12_set_dig(*e, 1); +#endif +} + +void gt_mul_op(const bp_group_t group, gt_ptr z, gt_ptr x, gt_ptr y) { +#if defined(BP_WITH_OPENSSL) + GT_ELEM_mul(group, z, x, y, NULL); +#else + fp12_mul_lazyr(z, x, y); +#endif +} + +void gt_div_op(const bp_group_t group, gt_ptr z, gt_ptr x, gt_ptr y) { +#if defined(BP_WITH_OPENSSL) + GT_ELEM_inv(group, z, y, NULL); + GT_ELEM_mul(group, z, x, z, NULL); +#else + // gt_inv + fp12_inv(z, y); + // gt_mul + fp12_mul_lazyr(z, x, z); +#endif +} + +void gt_exp_op(const bp_group_t group, gt_ptr y, gt_ptr x, bignum_t r) { +#if defined(BP_WITH_OPENSSL) + GT_ELEM_exp(group, y, x, r, NULL); +#else + fp12_exp(y, x, r); +#endif +} + +int gt_is_unity_check(const bp_group_t group, gt_ptr r) { +#if defined(BP_WITH_OPENSSL) + return (GT_ELEM_is_unity(group, r) == 1); +#else + // gt_is_unity + return (fp12_cmp_dig(r, 1)) == 0; +#endif +} + +void bp_map_op(const bp_group_t group, gt_ptr gt, g1_ptr g1, g2_ptr g2) { +#if defined(BP_WITH_OPENSSL) + GT_ELEM_pairing(group, gt, g1, g2, NULL); +#else + pp_map_oatep_k12(gt, g1, g2); +#endif +} + +#if !defined(BP_WITH_OPENSSL) +/**************************************************************** + * RELIC helper functions + * These may end up as part of RELIC, not the OpenABE. + * Once testing is complete they could be moved into the RELIC + * source code and released per LGPL terms. It's not really clear + * what to do with them. + ****************************************************************/ + +void bn_copy_const(bn_t c, const bn_t a) { + int i; + + if (c->dp == a->dp) + return; + + bn_grow(c, a->used); + + for (i = 0; i < a->used; i++) { + c->dp[i] = a->dp[i]; + } + + c->used = a->used; + c->sign = a->sign; +} + +void ep_copy_const(ep_t r, const ep_t p) { + fp_copy_const(r->x, p->x); + fp_copy_const(r->y, p->y); + fp_copy_const(r->z, p->z); + r->norm = p->norm; +} + +void fp_copy_const(fp_t c, const fp_t a) { + int i; + for (i = 0; i < FP_DIGS; i++) { + c[i] = a[i]; + } +} + +void ep2_copy_const(ep2_t r, const ep2_t p) { + fp2_copy_const(r->x, p->x); + fp2_copy_const(r->y, p->y); + fp2_copy_const(r->z, p->z); + r->norm = p->norm; +} + +void fp2_copy_const(fp2_t c, const fp2_t a) { + fp_copy_const(c[0], a[0]); + fp_copy_const(c[1], a[1]); +} + +void fp12_copy_const(fp12_t c, const fp12_t a) { + fp6_copy_const(c[0], a[0]); + fp6_copy_const(c[1], a[1]); +} + +void fp6_copy_const(fp6_t c, const fp6_t a) { + fp2_copy_const(c[0], a[0]); + fp2_copy_const(c[1], a[1]); + fp2_copy_const(c[2], a[2]); +} + +int bn_cmp_const(bn_t a, const bn_t b) { + if (a->sign == BN_POS && b->sign == BN_NEG) { + return CMP_GT; + } + if (a->sign == BN_NEG && b->sign == BN_POS) { + return CMP_LT; + } + + if (a->sign == BN_NEG) { + return bn_cmp_abs_const(b, a); + } + + return bn_cmp_abs_const(a, b); +} + +int bn_cmp_abs_const(const bn_t a, const bn_t b) { + if (a->used > b->used) { + return CMP_GT; + } + + if (a->used < b->used) { + return CMP_LT; + } + + return bn_cmpn_low_const(a->dp, b->dp, a->used); +} + +int bn_cmpn_low_const(const dig_t *a, const dig_t *b, const int size) { + int i, r; + + a += (size - 1); + b += (size - 1); + + r = CMP_EQ; + for (i = 0; i < size; i++, --a, --b) { + if (*a != *b && r == CMP_EQ) { + r = (*a > *b ? CMP_GT : CMP_LT); + } + } + return r; +} + + +int ep_cmp_const(ep_t p, const ep_t q) { + if (fp_cmp_const(p->x, q->x) != CMP_EQ) { + return CMP_NE; + } + + if (fp_cmp_const(p->y, q->y) != CMP_EQ) { + return CMP_NE; + } + + if (fp_cmp_const(p->z, q->z) != CMP_EQ) { + return CMP_NE; + } + + return CMP_EQ; +} + +int ep2_cmp_const(ep2_t p, const ep2_t q) { + if (fp2_cmp_const(p->x, q->x) != CMP_EQ) { + return CMP_NE; + } + + if (fp2_cmp_const(p->y, q->y) != CMP_EQ) { + return CMP_NE; + } + + if (fp2_cmp_const(p->z, q->z) != CMP_EQ) { + return CMP_NE; + } + + return CMP_EQ; +} + +int fp12_cmp_const(fp12_t a, const fp12_t b) { + return ((fp6_cmp_const(a[0], b[0]) == CMP_EQ) && + (fp6_cmp_const(a[1], b[1]) == CMP_EQ) ? CMP_EQ : CMP_NE); +} + +int fp6_cmp_const(fp6_t a, const fp6_t b) { + return ((fp2_cmp_const(a[0], b[0]) == CMP_EQ) && (fp2_cmp_const(a[1], b[1]) == CMP_EQ) + && (fp2_cmp_const(a[2], b[2]) == CMP_EQ) ? CMP_EQ : CMP_NE); +} + +int fp2_cmp_const(fp2_t a, const fp2_t b) { + return (fp_cmp_const(a[0], b[0]) == CMP_EQ) && + (fp_cmp_const(a[1], b[1]) == CMP_EQ) ? CMP_EQ : CMP_NE; +} + +int fp_cmp_const(fp_t a, const fp_t b) { + return fp_cmpn_low_const(a, b); +} + +int fp_cmpn_low_const(dig_t *a, const dig_t *b) { + int i, r; + + a += (FP_DIGS - 1); + b += (FP_DIGS - 1); + + r = CMP_EQ; + for (i = 0; i < FP_DIGS; i++, --a, --b) { + if (*a != *b && r == CMP_EQ) { + r = (*a > *b ? CMP_GT : CMP_LT); + } + } + return r; +} + +#endif diff --git a/src/zml/zelement_bp.cpp b/src/zml/zelement_bp.cpp new file mode 100644 index 00000000..24e320ff --- /dev/null +++ b/src/zml/zelement_bp.cpp @@ -0,0 +1,1320 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zelement_bp.cpp +/// +/// \brief Class implementation for OpenABE group elements. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +using namespace std; + +const string print_point(char *x, int x_len, char *y, int y_len) { + string s; + s = "[" + string(x, x_len); + s += ","; + s += string(y, y_len) + "]"; + return s; +} + +const string g1_point_to_string(bp_group_t group, const g1_ptr p) { + bignum_t x, y; + zml_bignum_init(&x); + zml_bignum_init(&y); +#if defined(BP_WITH_OPENSSL) + G1_ELEM_get_affine_coordinates(group, p, x, y, NULL); +#endif + int x_size, y_size; + char *xstr = zml_bignum_toDec(x, &x_size); + char *ystr = zml_bignum_toDec(y, &y_size); + string s = print_point(xstr, x_size, ystr, y_size); + // s = "[" + string(xstr, x_size); + // s += ","; + // s += string(ystr, y_size) + "]"; + + zml_bignum_safe_free(xstr); + zml_bignum_safe_free(ystr); + zml_bignum_free(x); + zml_bignum_free(y); + return s; +} + +void g1_convert_to_bytestring(bp_group_t group, oabe::OpenABEByteString &s, + const g1_ptr p) { +#if defined(BP_WITH_OPENSSL) + uint8_t buf[MAX_BUFFER_SIZE]; + memset(buf, 0, MAX_BUFFER_SIZE); + size_t len = G1_ELEM_point2oct(group, p, POINT_CONVERSION_COMPRESSED, buf, + MAX_BUFFER_SIZE, NULL); + s.appendArray(buf, len); +#else + size_t len = g1_elem_len(p); + s.fillBuffer(0, len); + g1_elem_out(p, s.getInternalPtr(), len); +#endif +} + +void g1_convert_to_point(bp_group_t group, oabe::OpenABEByteString &s, g1_ptr p) { + uint8_t *xstr = s.getInternalPtr(); + size_t xstr_len = s.size(); +#if defined(BP_WITH_OPENSSL) + G1_ELEM_oct2point(group, p, xstr, xstr_len, NULL); +#else + g1_elem_in(p, xstr, xstr_len); + ASSERT(oabe::checkRelicError(), oabe::OpenABE_ERROR_SERIALIZATION_FAILED); +#endif +} + +const string g2_point_to_string(bp_group_t group, const g2_ptr p) { + bignum_t x[2], y[2]; + zml_bignum_init(&x[0]); + zml_bignum_init(&y[0]); + zml_bignum_init(&x[1]); + zml_bignum_init(&y[1]); +#if defined(BP_WITH_OPENSSL) + G2_ELEM_get_affine_coordinates(group, p, x, y, NULL); +#endif + int x1_size, y1_size, x2_size, y2_size; + char *x1str = zml_bignum_toDec(x[0], &x1_size); + char *y1str = zml_bignum_toDec(y[0], &y1_size); + char *x2str = zml_bignum_toDec(x[1], &x2_size); + char *y2str = zml_bignum_toDec(y[1], &y2_size); + + std::string s = ""; + s += print_point(x1str, x1_size, y1str, y1_size) + ","; + s += print_point(x2str, x1_size, y2str, y2_size); + + // std::string s1, s2; + // s1 = "[" + string(x1str, x1_size); + // s1 += ","; + // s1 += string(y1str, y1_size) + "]"; + // s2 = ", [" + string(x2str, x2_size); + // s2 += ","; + // s2 += string(y2str, y2_size) + "]"; + + zml_bignum_safe_free(x1str); + zml_bignum_safe_free(y1str); + zml_bignum_safe_free(x2str); + zml_bignum_safe_free(y2str); + + zml_bignum_free(x[0]); + zml_bignum_free(y[0]); + zml_bignum_free(x[1]); + zml_bignum_free(y[1]); + + return s; +} + +void g2_convert_to_bytestring(bp_group_t group, oabe::OpenABEByteString &s, + g2_ptr p) { +#if defined(BP_WITH_OPENSSL) + uint8_t buf[MAX_BUFFER_SIZE]; + memset(buf, 0, MAX_BUFFER_SIZE); // ideal => POINT_CONVERSION_COMPRESSED + size_t len = G2_ELEM_point2oct(group, p, POINT_CONVERSION_UNCOMPRESSED, buf, + MAX_BUFFER_SIZE, NULL); + s.appendArray(buf, len); +#else + size_t len = g2_elem_len(p); + s.fillBuffer(0, len); + g2_elem_out(p, s.getInternalPtr(), len); + +// size_t len = g2_size_bin(p, COMPRESS); +// // cout << "G1::serialize => " << len << endl; +// s.fillBuffer(0, len); +// g2_write_bin(s.getInternalPtr(), len, p, COMPRESS); +#endif +} + +void g2_convert_to_point(bp_group_t group, oabe::OpenABEByteString &s, g2_ptr p) { + uint8_t *xstr = s.getInternalPtr(); + size_t xstr_len = s.size(); +#if defined(BP_WITH_OPENSSL) + G2_ELEM_oct2point(group, p, xstr, xstr_len, NULL); +#else + g2_elem_in(p, xstr, xstr_len); + ASSERT(oabe::checkRelicError(), oabe::OpenABE_ERROR_SERIALIZATION_FAILED); +#endif +} + +void gt_convert_to_bytestring(bp_group_t group, oabe::OpenABEByteString &s, gt_ptr p, + int should_compress) { +#if defined(BP_WITH_OPENSSL) + uint8_t buf[MAX_BUFFER_SIZE]; + memset(buf, 0, MAX_BUFFER_SIZE); + size_t len = GT_ELEM_elem2oct(group, p, buf, MAX_BUFFER_SIZE, NULL); + s.appendArray(buf, len); +#else + size_t len = gt_elem_len(p, should_compress); + s.fillBuffer(0, len); + gt_elem_out(p, s.getInternalPtr(), len, should_compress); +// size_t len = gt_size_bin(p, should_compress); +// // cout << "G1::serialize => " << len << endl; +// s.fillBuffer(0, len); +// gt_write_bin(s.getInternalPtr(), len, p, should_compress); +#endif +} + +void gt_convert_to_point(bp_group_t group, oabe::OpenABEByteString &s, gt_ptr p) { + uint8_t *xstr = s.getInternalPtr(); + size_t xstr_len = s.size(); +#if defined(BP_WITH_OPENSSL) + GT_ELEM_oct2elem(group, p, xstr, xstr_len, NULL); +#else + gt_elem_in(p, xstr, xstr_len); + ASSERT(oabe::checkRelicError(), oabe::OpenABE_ERROR_SERIALIZATION_FAILED); +#endif +} + + +void multi_bp_map_op(const bp_group_t group, oabe::GT >, + std::vector &g1, std::vector &g2) { + if (g1.size() != g2.size()) { + throw oabe::OpenABE_ERROR_INVALID_LENGTH; + } + const size_t n = g1.size(); +#if defined(BP_WITH_OPENSSL) + const G1_ELEM *ps[n]; + const G2_ELEM *qs[n]; + for (size_t i = 0; i < n; i++) { + ps[i] = g1.at(i).m_G1; + qs[i] = g2.at(i).m_G2; + } + GT_ELEMs_pairing(group, gt.m_GT, n, ps, qs, NULL); +#else + g1_t g_1[n]; + g2_t g_2[n]; + for (size_t i = 0; i < n; i++) { + g1_inits(g_1[i]); + g1_copy_const(g_1[i], g1.at(i).m_G1); + ep2_inits(g_2[i]); + g2_copy_const(g_2[i], g2.at(i).m_G2); + } + pp_map_sim_oatep_k12(gt.m_GT, g_1, g_2, n); + for (size_t i = 0; i < n; i++) { + g1_free(g_1[i]); + g2_free(g_2[i]); + } +#endif +} + + +/******************************************************************************** + * RNG trampoline from RELIC + ********************************************************************************/ + +void ro_error(void) { + cout << "Writing to read only object." << endl; + exit(0); +} + +namespace oabe { + +#if !defined(BP_WITH_OPENSSL) +static void rng_trampoline(uint8_t *buf, int len, void *this_ptr) { + // cout << "calling our RNG!!!!" << endl; + OpenABERNG *rng = static_cast(this_ptr); + rng->getRandomBytes(buf, len); +} + +bool checkRelicError() { + return (zml_check_error() == TRUE); +} +#endif + +/******************************************************************************** + * Implementation of the Group class + ********************************************************************************/ + +BPGroup::BPGroup(OpenABECurveID id) : ZGroup(id) { + bp_group_init(&group, id); + group_param = OpenABE_convertCurveIDToString(id); + zml_bignum_init(&order); + bp_get_order(group, order); +} + +BPGroup::~BPGroup() { + bp_group_free(group); + zml_bignum_free(order); +} + +void BPGroup::getGroupOrder(bignum_t o) { + zml_bignum_copy(o, order); +} + +/******************************************************************************** + * Implementation of the ZP class + ********************************************************************************/ + +// Begin ZP-specific classes + +ZP::ZP() { + zml_bignum_init(&this->m_ZP); + zml_bignum_init(&this->order); + isOrderSet = false; + isInit = true; +} + +ZP::ZP(uint32_t x) { + zml_bignum_init(&this->m_ZP); + zml_bignum_init(&this->order); + zml_bignum_setuint(this->m_ZP, x); + isOrderSet = false; + isInit = true; +} + +ZP::ZP(char *hex_str, bignum_t o) { + zml_bignum_init(&m_ZP); + zml_bignum_init(&order); + zml_bignum_copy(order, o); + zml_bignum_fromHex(m_ZP, (const char *)hex_str, strlen(hex_str)); + isOrderSet = true; + isInit = true; +} + +ZP::ZP(uint8_t *bstr, uint32_t bstr_len, bignum_t o) { + zml_bignum_init(&m_ZP); + zml_bignum_init(&order); + zml_bignum_copy(order, o); + zml_bignum_fromBin(m_ZP, bstr, bstr_len); + zml_bignum_mod(m_ZP, order); + isOrderSet = true; + isInit = true; +} + +ZP::ZP(bignum_t y) { + zml_bignum_init(&m_ZP); + zml_bignum_copy(m_ZP, y); + zml_bignum_init(&order); + // g1_get_ord(this->order); + isOrderSet = false; + isInit = true; +} + +ZP::ZP(const ZP& w) +{ + zml_bignum_init(&this->m_ZP); + zml_bignum_copy(this->m_ZP, w.m_ZP); + zml_bignum_init(&this->order); + zml_bignum_copy(this->order, w.order); + isInit = w.isInit; + isOrderSet = w.isOrderSet; +} + +ZP::~ZP() { + zml_bignum_free(m_ZP); + zml_bignum_free(order); +} + +ZP &ZP::operator+=(const ZP &x) { + ZP r(*this); + *this = r + x; + return *this; +} + +ZP &ZP::operator*=(const ZP &x) { + ZP r(*this); + *this = r * x; + return *this; +} + +ZP &ZP::operator=(const ZP &w) { + if (isInit) { + zml_bignum_copy(m_ZP, w.m_ZP); + zml_bignum_copy(order, w.order); + isOrderSet = w.isOrderSet; + } else + ro_error(); + return *this; +} + +ZP operator+(const ZP &x, const ZP &y) { + ASSERT(x.isOrderSet || y.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + ZP zr; + if (x.isOrderSet) + zr.setOrder(x.order); + else + zr.setOrder(y.order); + + zml_bignum_add(zr.m_ZP, x.m_ZP, y.m_ZP, zr.order); + return zr; +} + +ZP operator-(const ZP &x, const ZP &y) { + ASSERT(x.isOrderSet || y.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + ZP zr; + if (x.isOrderSet) + zr.setOrder(x.order); + else + zr.setOrder(y.order); + + zml_bignum_sub_order(zr.m_ZP, x.m_ZP, y.m_ZP, zr.order); + return zr; +} + +ZP operator-(const ZP &x) { + ASSERT(x.isInit && x.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + ZP zr = x; + zml_bignum_negate(zr.m_ZP, zr.order); + return zr; +} + +ZP operator*(const ZP &x, const ZP &y) { + ASSERT(x.isOrderSet || y.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + ZP zr; + if (x.isOrderSet) + zr.setOrder(x.order); + else + zr.setOrder(y.order); + + zml_bignum_mul(zr.m_ZP, x.m_ZP, y.m_ZP, zr.order); + return zr; +} + +void ZP::multInverse() { + // compute c = (1 / zr) mod o + if (this->isInit && this->isOrderSet) { + zml_bignum_mod_inv(this->m_ZP, this->m_ZP, this->order); + } +} + +ZP operator/(const ZP &x, const ZP &y) { + ZP c; + if (zml_bignum_is_zero(y.m_ZP)) { + cout << "Divide by zero error!" << endl; + throw OpenABE_ERROR_DIVIDE_BY_ZERO; + } + + ASSERT(x.isOrderSet || y.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + ZP r; + if (x.isOrderSet) + r.setOrder(x.order); + else + r.setOrder(y.order); + + zml_bignum_div(r.m_ZP, x.m_ZP, y.m_ZP, r.order); + return r; +} + +ZP power(const ZP &x, unsigned int r) { + ZP zr; + ASSERT(x.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + zr.setOrder(x.order); + + bignum_t p; + zml_bignum_init(&p); + zml_bignum_setuint(p, r); + zml_bignum_exp(zr.m_ZP, x.m_ZP, p, zr.order); + zml_bignum_free(p); + return zr; +} + +ZP power(const ZP &x, const ZP &r) { + ZP zr; + ASSERT(x.isOrderSet || r.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + if (x.isOrderSet) + zr.setOrder(x.order); + else + zr.setOrder(r.order); + + zml_bignum_exp(zr.m_ZP, x.m_ZP, r.m_ZP, zr.order); + return zr; +} + +bool ZP::ismember(void) { + ASSERT(isInit && isOrderSet, OpenABE_ERROR_ELEMENT_NOT_INITIALIZED); + bool result; + // CMP_LT if a < b, CMP_EQ if a == b and CMP_GT if a > b. + result = (zml_bignum_cmp(m_ZP, order) == BN_CMP_LT && + zml_bignum_sign(m_ZP) == BN_POSITIVE); + return result; +} + +void ZP::setOrder(const bignum_t o) { + ASSERT(isInit, OpenABE_ERROR_ELEMENT_NOT_INITIALIZED); + if (!isOrderSet) { + zml_bignum_copy(order, o); + isOrderSet = true; + } +} + +void ZP::setRandom(OpenABERNG *rng, bignum_t o) { + ASSERT(isInit, OpenABE_ERROR_ELEMENT_NOT_INITIALIZED); + // 1. get some number of bytes + if (!this->isOrderSet) { + this->isOrderSet = true; + zml_bignum_copy(this->order, o); + } + int length = zml_bignum_countbytes(this->order); + // 2. call bignum_fromBin on the bytes obtained + uint8_t buf[length]; + memset(buf, 0, length); +#if defined(BP_WITH_OPENSSL) + rng->getRandomBytes(buf, length); + zml_bignum_fromBin(this->m_ZP, buf, length); +#else + rand_seed(&rng_trampoline, (void *)rng); + zml_bignum_rand(this->m_ZP, this->order); +#endif + zml_bignum_mod(this->m_ZP, this->order); +} + +void ZP::setFrom(ZP &z, uint32_t index) { + // hash z + index? + ASSERT(isInit, OpenABE_ERROR_ELEMENT_NOT_INITIALIZED); + zml_bignum_copy(this->m_ZP, z.m_ZP); + *this = *this + index; +} + +ostream &operator<<(ostream &os, const ZP &zr) { + int len = 0; + char *str = zml_bignum_toDec(zr.m_ZP, &len); + string s0 = string(str, len-1); + zml_bignum_safe_free(str); + os << s0 << " (orderSet: " << (zr.isOrderSet ? "true)" : "false)"); + return os; +} + +bool operator<(const ZP &x, const ZP &y) { + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) == BN_CMP_LT); +} + +bool operator<=(const ZP &x, const ZP &y) { + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) <= BN_CMP_EQ); +} + +bool operator>(const ZP &x, const ZP &y) { + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) == BN_CMP_GT); +} + +bool operator>=(const ZP &x, const ZP &y) { + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) >= BN_CMP_EQ); +} + +bool operator==(const ZP &x, const ZP &y) { + ASSERT(x.isOrderSet || y.isOrderSet, OpenABE_ERROR_ELEMENT_NOT_INITIALIZED); + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) == BN_CMP_EQ); +} + +bool operator!=(const ZP &x, const ZP &y) { + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) != BN_CMP_EQ); +} + +ZP operator<<(const ZP &a, int b) { + // left shift + ZP zr = a; + zml_bignum_lshift(zr.m_ZP, zr.m_ZP, b); + return zr; +} + +ZP operator>>(const ZP &a, int b) { + // right shift + ZP zr = a; + zml_bignum_rshift(zr.m_ZP, zr.m_ZP, b); + return zr; +} + +void ZP::serialize(OpenABEByteString &result) const { + ASSERT(isInit, OpenABE_ERROR_ELEMENT_NOT_INITIALIZED); + result.clear(); + result.insertFirstByte(OpenABE_ELEMENT_ZP); + this->getLengthAndByteString(result); +} + +void ZP::deserialize(OpenABEByteString &input) { + size_t inputSize = input.size(), hdrLen = 3; + ASSERT(isInit, OpenABE_ERROR_ELEMENT_NOT_INITIALIZED); + + // first byte is the group type + if (input.at(0) == OpenABE_ELEMENT_ZP && inputSize > hdrLen) { + uint16_t len = 0; + // read 2 bytes from right to left + len |= input.at(2); // Moves to 0x00FF + len |= (input.at(1) << 8); // Moves to 0xFF00 + ASSERT(input.size() == (len + hdrLen), OpenABE_ERROR_SERIALIZATION_FAILED); + + uint8_t *bstr = (input.getInternalPtr() + hdrLen); + zml_bignum_fromBin(this->m_ZP, bstr, len); + if (isOrderSet && zml_bignum_cmp(this->m_ZP, this->order) == BN_CMP_GT) { + zml_bignum_mod(this->m_ZP, this->order); + } + } +} + +bool ZP::isEqual(ZObject *z) const { + ZP *z1 = dynamic_cast(z); + if (z1 != NULL) { + return *z1 == *this; + } + return false; +} + +OpenABEByteString ZP::getByteString() const { + size_t length = zml_bignum_countbytes(this->m_ZP); + + uint8_t data[length+1]; + memset(data, 0, length); + zml_bignum_toBin(this->m_ZP, data, length); + + OpenABEByteString z; + z.appendArray(data, length); + return z; +} + +string ZP::getBytesAsString() { + OpenABEByteString z; + z = this->getByteString(); + return z.toHex(); +} + + +void ZP::getLengthAndByteString(OpenABEByteString &z) const { + size_t length = zml_bignum_countbytes(this->m_ZP); + + uint8_t data[length]; + memset(data, 0, length); + zml_bignum_toBin(this->m_ZP, data, length); + + z.pack16bits((uint16_t)length); + z.appendArray(data, length); +} + + +/******************************************************************************** + * Implementation of the G1 class + ********************************************************************************/ + +G1::G1(std::shared_ptr bgroup) { + this->isInit = true; + this->bgroup = bgroup; + // does init and sets the point to infinity + g1_set_to_infinity(GET_BP_GROUP(this->bgroup), &this->m_G1); +} + +G1::G1(const G1 &w) { + if (w.bgroup != nullptr) { + this->bgroup = w.bgroup; + } else { + throw OpenABE_ERROR_INVALID_GROUP_PARAMS; + } + g1_init(GET_BP_GROUP(this->bgroup), &this->m_G1); + g1_copy_const(this->m_G1, w.m_G1); + this->isInit = true; +} + +G1 &G1::operator=(const G1 &w) { + if (this->isInit) { + if (w.bgroup != nullptr) { + this->bgroup = w.bgroup; + } + if (is_elem_null(this->m_G1)) { + if (this->bgroup) + g1_init(GET_BP_GROUP(this->bgroup), &this->m_G1); + else + ro_error(); + } + g1_copy_const(this->m_G1, w.m_G1); + } else + ro_error(); + + return *this; +} + +G1::~G1() { + if (this->isInit) { + g1_element_free(this->m_G1); + this->isInit = false; + } +} + +/*! + * Field addition (rep. as multiplication operator) on elements of G1. + * + * @param[in] - G1 element on lhs + * @param[in] - G1 element on rhs + */ +G1 operator*(const G1 &x, const G1 &y) { + G1 z = x; + g1_add_op(GET_GROUP(z.bgroup), z.m_G1, z.m_G1, y.m_G1); +//#if defined(BP_WITH_OPENSSL) +// G1_ELEM_add(GET_BP_GROUP(z.bgroup), z.m_G1, z.m_G1, y.m_G1, NULL); +//#else +// g1_add(z.m_G1, z.m_G1, y.m_G1); +// g1_norm(z.m_G1, z.m_G1); +//#endif + return z; +} + +G1 &G1::operator*=(const G1 &x) { + G1 r(*this); + *this = r * x; + return *this; +} + +/*! + * Field subtraction (represented as division operator) on elements of G1. + * + * @param[in] - G1 element on lhs + * @param[in] - G1 element on rhs + */ +G1 operator/(const G1 &x, const G1 &y) { + // z = (x / y) => Point z = y; z = x - z; + G1 z = y; + g1_sub_op(GET_BP_GROUP(z.bgroup), z.m_G1, x.m_G1); +//#if defined(BP_WITH_OPENSSL) +// int rc = G1_ELEM_invert(GET_BP_GROUP(z.bgroup), z.m_G1, NULL); +// ASSERT(rc == 1, OpenABE_ERROR_INVALID_INPUT); +// G1_ELEM_add(GET_BP_GROUP(z.bgroup), z.m_G1, x.m_G1, z.m_G1, NULL); +//#else +// g1_sub(z.m_G1, x.m_G1, z.m_G1); +// g1_norm(z.m_G1, z.m_G1); +//#endif + return z; +} + +/*! + * Negation operator on elements of G1. + * + * @param[in] - G1 element to negate on rhs. + */ +G1 operator-(const G1 &x) { + G1 z = x; +#if defined(BP_WITH_OPENSSL) + G1_ELEM_invert(GET_BP_GROUP(z.bgroup), z.m_G1, NULL); +#else + g1_neg(z.m_G1, z.m_G1); +#endif + return z; +} + +/*! + * Field multiplication (or exponentiation operator) on elements of G1. + * + * @param[in] - ZP to multiply with this element. + */ +G1 G1::exp(ZP z) { + G1 g1(this->bgroup); + g1_mul_op(GET_BP_GROUP(g1.bgroup), g1.m_G1, this->m_G1, z.m_ZP); + return g1; +} + +/*! + * Check whether G1 element is a member of a subgroup of the elliptic curve. + * + * @param[in] - order of elliptic curve points in G1. + */ +bool G1::ismember(bignum_t order) { + bool result; +#if defined(BP_WITH_OPENSSL) + // 1 indicates that the element is on the curve + result = + (G1_ELEM_is_on_curve(GET_BP_GROUP(this->bgroup), this->m_G1, NULL) == 1); +#else + g1_t r; + g1_inits(r); + + g1_mul(r, this->m_G1, order); + if (g1_is_infty(r) == 1) + result = true; + else + result = false; + g1_free(r); +#endif + return result; +} + +/*! + * Select random group element in G1. + * + * @param[in] - an OpenABERNG object. + */ +void G1::setRandom(OpenABERNG *rng) { + if (this->isInit) { +// cout << "G1: "; +#if defined(BP_WITH_OPENSSL) + int rc = BP_GROUP_get_generator_G1(GET_BP_GROUP(this->bgroup), this->m_G1); + ASSERT(rc == 1, OpenABE_ERROR_INVALID_INPUT); +#else + rand_seed(&rng_trampoline, (void *)rng); + // g1_rand(this->m_G1); + g1_rand_op(this->m_G1); +#endif + } +} + +ostream &operator<<(ostream &os, const G1 &g1) { +#if defined(BP_WITH_OPENSSL) + os << g1_point_to_string(GET_BP_GROUP(g1.bgroup), g1.m_G1); +#else + ep_write_ostream(os, const_cast(g1).m_G1, DEC); +#endif + return os; +} + +bool operator==(const G1 &x, const G1 &y) { + bool result; +#if defined(BP_WITH_OPENSSL) + result = + (G1_ELEM_cmp(GET_BP_GROUP(x.bgroup), x.m_G1, y.m_G1, NULL) == G_CMP_EQ); +#else + result = (g1_cmp(x.m_G1, y.m_G1) == CMP_EQ); +#endif + return result; +} + +bool operator!=(const G1 &x, const G1 &y) { + bool result; +#if defined(BP_WITH_OPENSSL) + result = + (G1_ELEM_cmp(GET_BP_GROUP(x.bgroup), x.m_G1, y.m_G1, NULL) != G_CMP_EQ); +#else + result = (g1_cmp(x.m_G1, y.m_G1) != CMP_EQ); +#endif + return result; +} + +void G1::serialize(OpenABEByteString &result) const { + OpenABEByteString tmp; + + if (this->isInit) { + g1_convert_to_bytestring(GET_BP_GROUP(this->bgroup), tmp, this->m_G1); + result.clear(); + result.insertFirstByte(OpenABE_ELEMENT_G1); + result.smartPack(tmp); + } +} + +void G1::deserialize(OpenABEByteString &input) { + OpenABEByteString g1_bytes; + size_t index = 0; + + if (this->isInit && this->bgroup != nullptr) { + // first byte is the group type + uint8_t element_type = input.at(index); + if (element_type == OpenABE_ELEMENT_G1) { + index++; + g1_bytes = input.smartUnpack(&index); + // read the binary buffer into a G1 element, then check for error + // condition + if (is_elem_null(this->m_G1)) { + g1_init(GET_BP_GROUP(this->bgroup), &this->m_G1); + } + g1_convert_to_point(GET_BP_GROUP(this->bgroup), g1_bytes, this->m_G1); + return; + } + } + ASSERT(false, OpenABE_ERROR_SERIALIZATION_FAILED); +} + +bool G1::isEqual(ZObject *z) const { + G1 *z1 = dynamic_cast(z); + if (z1 != NULL) { + return *z1 == *this; + } + return false; +} + +/******************************************************************************** + * Implementation of the G2 class + ********************************************************************************/ + +G2::G2(std::shared_ptr bgroup) +{ + this->isInit = true; + this->bgroup = bgroup; + // does init and sets the point to infinity + g2_set_to_infinity(GET_BP_GROUP(this->bgroup), &this->m_G2); +} + +G2::G2(const G2& w) +{ + if (w.bgroup != nullptr) { + this->bgroup = w.bgroup; + } else { + throw OpenABE_ERROR_INVALID_GROUP_PARAMS; + } + g2_init(GET_BP_GROUP(this->bgroup), &this->m_G2); + g2_copy_const(this->m_G2, w.m_G2); + this->isInit = true; +} + +G2& +G2::operator=(const G2& w) +{ + if (this->isInit) { + if(w.bgroup != nullptr) { + this->bgroup = w.bgroup; + } + if (is_elem_null(this->m_G2)) { + if (this->bgroup) + g2_init(GET_BP_GROUP(this->bgroup), &this->m_G2); + else + ro_error(); + } + g2_copy_const(this->m_G2, w.m_G2); + } + else ro_error(); + + return *this; +} + +G2::~G2() +{ + if (this->isInit) { + g2_element_free(this->m_G2); + this->isInit = false; + } +} + +/* multiplicative notation for point addition*/ +G2 operator*(const G2& x,const G2& y) +{ + G2 z = x; +#if defined(BP_WITH_OPENSSL) + G2_ELEM_add(GET_BP_GROUP(z.bgroup), z.m_G2, z.m_G2, y.m_G2, NULL); +#else + g2_add(z.m_G2, z.m_G2, const_cast(y).m_G2); + g2_norm(z.m_G2, z.m_G2); +#endif + return z; +} + +G2& +G2::operator*=(const G2& x) +{ + G2 r(*this); + *this = r * x; + return *this; +} + +/* multiplicative notation for point subtraction*/ +G2 operator/(const G2& x,const G2& y) +{ + G2 z = y; +#if defined(BP_WITH_OPENSSL) + int rc = G2_ELEM_invert(GET_BP_GROUP(z.bgroup), z.m_G2, NULL); + ASSERT(rc == 1, OpenABE_ERROR_INVALID_INPUT); + G2_ELEM_add(GET_BP_GROUP(z.bgroup), z.m_G2, x.m_G2, z.m_G2, NULL); +#else + g2_sub(z.m_G2, const_cast(x).m_G2, z.m_G2); + g2_norm(z.m_G2, z.m_G2); +#endif + return z; +} + +G2 operator-(const G2& x) +{ + G2 z = x; +#if defined(BP_WITH_OPENSSL) + G2_ELEM_invert(GET_BP_GROUP(z.bgroup), z.m_G2, NULL); +#else + g2_neg(z.m_G2, z.m_G2); +#endif + return z; +} + +G2 G2::exp(ZP z) +{ + G2 g2(this->bgroup); + g2_mul_op(GET_BP_GROUP(g2.bgroup), g2.m_G2, this->m_G2, z.m_ZP); + return g2; +} + +bool G2::ismember(bignum_t order) +{ + bool result; +#if defined(BP_WITH_OPENSSL) + // 1 indicates that the element is on the curve + result = (G2_ELEM_is_on_curve(GET_BP_GROUP(this->bgroup), this->m_G2, NULL) == 1); +#else + g2_t r; + fp12_inits(r); + + g2_mul(r, this->m_G2, order); + if(g2_is_infty(r) == 1) + result = true; + else + result = false; + g2_free(r); +#endif + return result; +} + +void G2::setRandom(OpenABERNG *rng) +{ + if(this->isInit) { + // cout << "G2: "; +#if defined(BP_WITH_OPENSSL) + int rc = BP_GROUP_get_generator_G2(GET_BP_GROUP(this->bgroup), this->m_G2); + ASSERT(rc == 1, OpenABE_ERROR_INVALID_INPUT); +#else + rand_seed(&rng_trampoline, (void *) rng); + g2_rand(this->m_G2); +#endif + } +} + +ostream& operator<<(ostream& os, const G2& g2) +{ +#if defined(BP_WITH_OPENSSL) + os << g2_point_to_string(GET_BP_GROUP(g2.bgroup), g2.m_G2); +#else + g2_write_ostream(os, const_cast(g2).m_G2, DEC); +#endif + return os; +} + +bool operator==(const G2& x,const G2& y) +{ + return (g2_cmp_op(GET_BP_GROUP(x.bgroup), const_cast(x).m_G2, const_cast(y).m_G2) == G_CMP_EQ); +} + +bool operator!=(const G2& x,const G2& y) +{ + return (g2_cmp_op(GET_BP_GROUP(x.bgroup), const_cast(x).m_G2, const_cast(y).m_G2) != G_CMP_EQ); +} + +void +G2::serialize(OpenABEByteString &result) const +{ + OpenABEByteString tmp; + + if(this->isInit) { + g2_convert_to_bytestring(GET_BP_GROUP(this->bgroup), tmp, const_cast(this)->m_G2); + result.clear(); + result.insertFirstByte(OpenABE_ELEMENT_G2); + result.smartPack(tmp); + } +} + +void +G2::deserialize(OpenABEByteString &input) +{ + OpenABEByteString g2_bytes; + size_t index = 0; + + if(this->isInit && this->bgroup != nullptr) { + // first byte is the group type + uint8_t element_type = input.at(index); + if(element_type == OpenABE_ELEMENT_G2) { + index++; + g2_bytes = input.smartUnpack(&index); + if (is_elem_null(this->m_G2)) { + g2_init(GET_BP_GROUP(this->bgroup), &this->m_G2); + } + g2_convert_to_point(GET_BP_GROUP(this->bgroup), g2_bytes, this->m_G2); + return; + } + } + ASSERT(false, OpenABE_ERROR_ELEMENT_NOT_INITIALIZED); +} + +bool +G2::isEqual(ZObject *z) const +{ + G2 *z1 = dynamic_cast(z); + if(z1 != NULL) { + return *z1 == *this; + } + return false; +} + +/******************************************************************************** + * Implementation of the GT class + ********************************************************************************/ + +GT::GT(std::shared_ptr bgroup) +{ + this->isInit = true; + this->bgroup = bgroup; + // does init and sets the point to infinity + gt_set_to_infinity(GET_BP_GROUP(this->bgroup), &this->m_GT); + shouldCompress_ = true; +} + +GT::GT(const GT& w) +{ + if (w.bgroup != nullptr) { + this->bgroup = w.bgroup; + } else { + throw OpenABE_ERROR_INVALID_GROUP_PARAMS; + } + gt_init(GET_BP_GROUP(this->bgroup), &this->m_GT); + gt_copy_const(this->m_GT, w.m_GT); + this->isInit = true; + this->shouldCompress_ = w.shouldCompress_; +} + +GT& +GT::operator=(const GT& w) +{ + if (this->isInit) { + if(w.bgroup != nullptr) { + this->bgroup = w.bgroup; + } + if (is_elem_null(this->m_GT)) { + if (this->bgroup) + gt_init(GET_BP_GROUP(this->bgroup), &this->m_GT); + else + ro_error(); + } + gt_copy_const(this->m_GT, w.m_GT); + this->shouldCompress_ = w.shouldCompress_; + } + else ro_error(); + return *this; +} + +GT::~GT() +{ + if (this->isInit) { + gt_element_free(this->m_GT); + this->isInit = false; + } +} + + +GT operator*(const GT& x,const GT& y) +{ + GT z = x; // , y1 = y; + gt_mul_op(GET_BP_GROUP(z.bgroup), z.m_GT, z.m_GT, const_cast(y).m_GT); + return z; +} + +GT& +GT::operator*=(const GT& x) +{ + GT r(*this); + *this = r * x; + return *this; +} + +GT operator/(const GT& x,const GT& y) +{ + GT z = x; + // z = x * y^-1 + gt_div_op(GET_BP_GROUP(z.bgroup), z.m_GT, const_cast(x).m_GT, const_cast(y).m_GT); + return z; +} + +GT GT::exp(ZP z) +{ + GT gt(*this); +#if defined(BP_WITH_OPENSSL) + GT_ELEM_exp(GET_BP_GROUP(gt.bgroup), gt.m_GT, gt.m_GT, z.m_ZP, NULL); + //ASSERT(rc == 1, OpenABE_ERROR_INVALID_INPUT); +#else + gt_exp(gt.m_GT, gt.m_GT, z.m_ZP); +#endif + return gt; +} + +GT operator-(const GT& g) +{ + GT gt(g); +#if defined(BP_WITH_OPENSSL) + GT_ELEM_inv(GET_BP_GROUP(gt.bgroup), gt.m_GT, gt.m_GT, NULL); +#else + gt_inv(gt.m_GT, gt.m_GT); +#endif + return gt; +} + +void GT::setIdentity() +{ +#if defined(BP_WITH_OPENSSL) + GT_ELEM_set_to_unity(GET_BP_GROUP(this->bgroup), this->m_GT); + //ASSERT(rc == 1, oabe::OpenABE_ERROR_INVALID_INPUT); +#else + gt_set_unity(this->m_GT); +#endif +} + +bool GT::isInfinity() +{ + return gt_is_unity_check(GET_BP_GROUP(this->bgroup), this->m_GT); +} + +bool GT::ismember(bignum_t order) +{ + bool result; + gt_ptr r; + gt_init(GET_BP_GROUP(this->bgroup), &r); + gt_exp_op(GET_BP_GROUP(this->bgroup), r, this->m_GT, order); + result = gt_is_unity_check(GET_BP_GROUP(this->bgroup), r); + gt_element_free(r); + return result; +} + +ostream& operator<<(ostream& os, const GT& gt) +{ +#if defined(BP_WITH_OPENSSL) + OpenABEByteString s; + gt_convert_to_bytestring(GET_BP_GROUP(gt.bgroup), s, gt.m_GT, NO_COMPRESS); + os << "(" << s.toHex() << ")"; +#else + gt_write_ostream(os, const_cast(gt).m_GT, DEC); +#endif + return os; +} + +bool operator==(const GT& x,const GT& y) +{ + bool result; +#if defined(BP_WITH_OPENSSL) + result = (GT_ELEM_cmp(x.m_GT, y.m_GT) == G_CMP_EQ); +#else + result = (gt_cmp(const_cast(x).m_GT, const_cast(y).m_GT) == G_CMP_EQ); +#endif + return result; +} + +bool operator!=(const GT& x, const GT& y) +{ + bool result; +#if defined(BP_WITH_OPENSSL) + result = (GT_ELEM_cmp(x.m_GT, y.m_GT) != G_CMP_EQ); +#else + result = (gt_cmp(const_cast(x).m_GT, const_cast(y).m_GT) != G_CMP_EQ); +#endif + return result; +} + + +void +GT::serialize(OpenABEByteString &result) const +{ + OpenABEByteString tmp; + int compress = shouldCompress_ ? COMPRESS : NO_COMPRESS; + + if(this->isInit) { + gt_convert_to_bytestring(GET_BP_GROUP(this->bgroup), tmp, const_cast(*this).m_GT, compress); + // pack the resulting ciphertext in result + result.clear(); + result.insertFirstByte(OpenABE_ELEMENT_GT); + result.smartPack(tmp); + } +} + +void +GT::deserialize(OpenABEByteString &input) +{ + OpenABEByteString gt_bytes; + size_t index = 0; + + if(this->isInit && this->bgroup != nullptr) { + // first byte is the group type + uint8_t element_type = input.at(index); + if(element_type == OpenABE_ELEMENT_GT) { + index++; + gt_bytes = input.smartUnpack(&index); + if (is_elem_null(this->m_GT)) { + gt_init(GET_BP_GROUP(this->bgroup), &this->m_GT); + } + gt_convert_to_point(GET_BP_GROUP(this->bgroup), gt_bytes, this->m_GT); + return; + } + } + ASSERT(false, OpenABE_ERROR_ELEMENT_NOT_INITIALIZED); +} + +bool +GT::isEqual(ZObject *z) const +{ + GT *z1 = dynamic_cast(z); + if(z1 != NULL) { + return *z1 == *this; + } + return false; +} + +#if !defined(BP_WITH_OPENSSL) +void fp12_write_ostream(ostream& os, fp12_t a, int radix) { + os << "[("; + fp6_write_ostream(os, a[0], radix); + os << "),("; + fp6_write_ostream(os, a[1], radix); + os << "]"; +} + +void fp6_write_ostream(ostream &os, fp6_t a, int radix) { + os << "{"; + fp2_write_ostream(os, a[0], radix); + os << ","; + fp2_write_ostream(os, a[1], radix); + os << ","; + fp2_write_ostream(os, a[2], radix); + os << "}"; +} + +void fp2_write_ostream(ostream& os, fp2_t a, int radix) { + os << "<"; + fp_write_ostream(os, a[0], radix); + os << ","; + fp_write_ostream(os, a[1], radix); + os << ">"; +} + +void fp_write_ostream(ostream& os, fp_t a, int radix) { + char strBuf[MAX_BYTES]; + fp_write_str(strBuf, MAX_BYTES, a, radix); + os << strBuf; +} + +void ep2_write_ostream(ostream &os, ep2_t p, int radix) { + os << "["; + fp2_write_ostream(os, p->x, radix); + os << ","; + fp2_write_ostream(os, p->y, radix); +// os << ","; +// fp2_write_ostream(os, p->z, radix); + os << "]"; +} + +void ep_write_ostream(ostream &os, ep_t p, int radix) { + // base field + os << "["; + fp_write_ostream(os, p->x, radix); + os << ","; + fp_write_ostream(os, p->y, radix); + os << "]"; +} +#endif + +} diff --git a/src/zml/zelement_ec.cpp b/src/zml/zelement_ec.cpp new file mode 100644 index 00000000..a19edf04 --- /dev/null +++ b/src/zml/zelement_ec.cpp @@ -0,0 +1,536 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zelement_ec.cpp +/// +/// \brief Class implementation for generic ZP_t and G_t elements. +/// Works either with OpenSSL or RELIC. +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +using namespace std; +using namespace oabe; + +string ec_point_to_string(ec_group_t group, const ec_point_t p) { + bignum_t x, y; + zml_bignum_init(&x); + zml_bignum_init(&y); + ec_get_coordinates(group, x, y, p); + int x_size, y_size; + char *xstr = zml_bignum_toDec(x, &x_size); + char *ystr = zml_bignum_toDec(y, &y_size); + string s; + s = "[" + string(xstr, x_size); + s += ","; + s += string(ystr, y_size) + "]"; + + zml_bignum_safe_free(xstr); + zml_bignum_safe_free(ystr); + zml_bignum_free(x); + zml_bignum_free(y); + return s; +} + +int ec_convert_to_bytestring(const ec_group_t group, oabe::OpenABEByteString &s, + const ec_point_t p) { +#if defined(EC_WITH_OPENSSL) + BN_CTX *ctx = BN_CTX_new(); + uint8_t buf[MAX_BUFFER_SIZE]; + memset(buf, 0, MAX_BUFFER_SIZE); + size_t len = EC_POINT_point2oct(group, p, POINT_CONVERSION_COMPRESSED, buf, + MAX_BUFFER_SIZE, ctx); + s.appendArray(buf, len); + BN_CTX_free(ctx); + return (int)len; +#else + size_t len = ec_point_elem_len(p); + uint8_t buf[len + 1]; + ec_point_elem_out(p, buf, len); + s.appendArray(buf, len); + return (int)len; +#endif +} + +/******************************************************************************** + * Implementation of the ZP class + ********************************************************************************/ +namespace oabe { + +void generateECCurveParameters(EC_GROUP **group, string paramid) { + if (*group == NULL) { + // obtain the nid from the paramid + int nid = OpenABE_convertStringToNID(paramid); + if (nid == 0) { + throw OpenABE_ERROR_INVALID_INPUT; + } + // construct the group by nid + *group = EC_GROUP_new_by_curve_name(nid); + + ASSERT_NOTNULL(*group); + } +} + +ZP_t::ZP_t() : ZObject() { + zml_bignum_init(&this->m_ZP); + zml_bignum_init(&this->order); + this->isInit = true; + this->isOrderSet = false; +} + +ZP_t::ZP_t(bignum_t order) { + zml_bignum_init(&this->m_ZP); + zml_bignum_init(&this->order); + zml_bignum_copy(this->order, order); + this->isInit = true; + this->isOrderSet = true; +} + +ZP_t::ZP_t(const ZP_t &w) { + zml_bignum_init(&this->m_ZP); + zml_bignum_init(&this->order); + + this->isInit = true; + zml_bignum_copy(this->m_ZP, w.m_ZP); + if (w.isOrderSet) { + zml_bignum_copy(this->order, w.order); + } + this->isOrderSet = w.isOrderSet; +} + +ZP_t::~ZP_t() { + zml_bignum_free(this->m_ZP); + zml_bignum_free(this->order); +} + +ZP_t::ZP_t(char *str) { + zml_bignum_init(&this->m_ZP); + isInit = true; + zml_bignum_fromHex(this->m_ZP, (const char *)str, strlen(str)); + this->isOrderSet = false; +} + +ZP_t::ZP_t(uint8_t *bstr, uint32_t bstr_len) { + zml_bignum_init(&this->m_ZP); + isInit = true; + zml_bignum_fromBin(this->m_ZP, bstr, bstr_len); + this->isOrderSet = false; +} + +ZP_t &ZP_t::operator+=(const ZP_t &x) { + *this = *this + x; + return *this; +} + +ZP_t &ZP_t::operator-=(const ZP_t &x) { + *this = *this - x; + return *this; +} + +ZP_t &ZP_t::operator-=(int x) { + // subtract x from whatever is in m_ZP (no modulo op though) + if (this->isInit) { + // ZP_t X(x); + bignum_t X; + zml_bignum_init(&X); + zml_bignum_setuint(X, x); + zml_bignum_sub(this->m_ZP, this->m_ZP, X); + zml_bignum_free(X); + } + return *this; +} + +ZP_t &ZP_t::operator*=(const ZP_t &x) { + *this = *this * x; + return *this; +} + +ZP_t operator+(const ZP_t &x, const ZP_t &y) { + ASSERT(x.isOrderSet || y.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + ZP_t zr; + if (x.isOrderSet) + zr.setOrder(x.order); + else + zr.setOrder(y.order); + + zml_bignum_add(zr.m_ZP, x.m_ZP, y.m_ZP, zr.order); + return zr; +} + +ZP_t operator-(const ZP_t &x, const ZP_t &y) { + ASSERT(x.isOrderSet || y.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + ZP_t zr; + if (x.isOrderSet) + zr.setOrder(x.order); + else + zr.setOrder(y.order); + + zml_bignum_sub_order(zr.m_ZP, x.m_ZP, y.m_ZP, zr.order); + return zr; +} + +ZP_t operator-(const ZP_t &x) { + ASSERT(x.isInit && x.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + ZP_t zr = x; + zml_bignum_negate(zr.m_ZP, zr.order); + return zr; +} + +ZP_t operator*(const ZP_t &x, const ZP_t &y) { + ASSERT(x.isOrderSet || y.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + ZP_t zr; + if (x.isOrderSet) + zr.setOrder(x.order); + else + zr.setOrder(y.order); + + zml_bignum_mul(zr.m_ZP, x.m_ZP, y.m_ZP, zr.order); + return zr; +} + +void ZP_t::multInverse() { + // compute c = (1 / zr) mod o + if (this->isInit && this->isOrderSet) { + ASSERT(zml_bignum_mod_inv(this->m_ZP, this->m_ZP, this->order), + OpenABE_ERROR_INVALID_INPUT); + } +} + +ZP_t operator/(const ZP_t &x, const ZP_t &y) { + if (zml_bignum_is_zero(y.m_ZP)) { + cout << "Divide by zero error!" << endl; + throw OpenABE_ERROR_DIVIDE_BY_ZERO; + } + ASSERT(x.isOrderSet || y.isOrderSet, OpenABE_ERROR_INVALID_INPUT); + ZP_t r; + if (x.isOrderSet) + r.setOrder(x.order); + else + r.setOrder(y.order); + + zml_bignum_div(r.m_ZP, x.m_ZP, y.m_ZP, r.order); + return r; +} + +void ZP_t::set(bignum_t i) { + if (this->isInit) { + zml_bignum_copy(this->m_ZP, i); + } +} + +void ZP_t::setZero() { + if (this->isInit) { + zml_bignum_setzero(this->m_ZP); + } +} + +void ZP_t::setOrder(const bignum_t order) { + if (!this->isOrderSet) { + zml_bignum_copy(this->order, order); + if (this->isInit) { + zml_bignum_mod(this->m_ZP, this->order); + } + } + return; +} + +void ZP_t::setRandom(OpenABERNG *rng) { + if (this->isInit && this->isOrderSet) { + // 1. get some number of bytes + int length = zml_bignum_countbytes(this->order); + // 2. call bignum_fromBin on the bytes obtained + uint8_t buf[length]; + memset(buf, 0, length); + rng->getRandomBytes(buf, length); + zml_bignum_fromBin(this->m_ZP, buf, length); + zml_bignum_mod(this->m_ZP, this->order); + } else { + throw OpenABE_ERROR_ELEMENT_NOT_INITIALIZED; + } +} + +bool operator<(const ZP_t &x, const ZP_t &y) { + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) == BN_CMP_LT); +} + +bool operator<=(const ZP_t &x, const ZP_t &y) { + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) <= BN_CMP_EQ); +} + +bool operator>(const ZP_t &x, const ZP_t &y) { + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) == BN_CMP_GT); +} + +bool operator>=(const ZP_t &x, const ZP_t &y) { + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) >= BN_CMP_EQ); +} + +bool operator==(const ZP_t &x, const ZP_t &y) { + ASSERT(x.isOrderSet || y.isOrderSet, OpenABE_ERROR_ELEMENT_NOT_INITIALIZED); + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) == BN_CMP_EQ); +} + +bool operator!=(const ZP_t &x, const ZP_t &y) { + return (zml_bignum_cmp(x.m_ZP, y.m_ZP) != BN_CMP_EQ); +} + +ostream &operator<<(ostream &s, const ZP_t &zr) { + if (zr.isInit) { + int len = 0; + char *str = zml_bignum_toDec(zr.m_ZP, &len); + string s0 = string(str, len); + zml_bignum_safe_free(str); + s << s0; + } + + return s; +} + +void ZP_t::serialize(OpenABEByteString &result) const { + if (this->isInit) { + result.clear(); + result.insertFirstByte(OpenABE_ELEMENT_ZP_t); + this->getByteString(result); + } +} + +void ZP_t::deserialize(OpenABEByteString &input) { + size_t inputSize = input.size(), hdrLen = 3; + + if (this->isInit) { + // first byte is the group type + if (input.at(0) == OpenABE_ELEMENT_ZP_t && inputSize > hdrLen) { + uint16_t len = 0; + // read 2 bytes from right to left + len |= input.at(2); // Moves to 0x00FF + len |= (input.at(1) << 8); // Moves to 0xFF00 + // cout << "len: " << len << ", input size: " << input.size() << endl; + ASSERT(input.size() == (len + hdrLen), OpenABE_ERROR_SERIALIZATION_FAILED); + + uint8_t *bstr = (input.getInternalPtr() + hdrLen); + zml_bignum_fromBin(this->m_ZP, bstr, len); + } + } +} + +bool ZP_t::isEqual(ZObject *z) const { + ZP_t *z1 = dynamic_cast(z); + if (z1 != NULL) { + return *z1 == *this; + } + return false; +} + +string ZP_t::getBytesAsString() { + int len = 0; + if (this->isInit) { + char *str = zml_bignum_toHex(this->m_ZP, &len); + string s0 = string(str, len); + zml_bignum_safe_free(str); + return s0; + } else { + throw OpenABE_ERROR_ELEMENT_NOT_INITIALIZED; + } +} + +OpenABEByteString ZP_t::getByteString() { + int length = zml_bignum_countbytes(this->m_ZP); + + uint8_t data[length]; + memset(data, 0, length); + zml_bignum_toBin(this->m_ZP, data, length); + + OpenABEByteString z; + z.appendArray(data, length); + return z; +} + +// used specifically for serialization +void ZP_t::getByteString(OpenABEByteString &z) const { + int length = zml_bignum_countbytes(this->m_ZP); + + uint8_t data[length]; + memset(data, 0, length); + zml_bignum_toBin(this->m_ZP, data, length); + + z.pack16bits((uint16_t)length); + z.appendArray(data, length); +} + +/******************************************************************************** + * Implementation of the ECGroup class + ********************************************************************************/ + +ECGroup::ECGroup(OpenABECurveID id) : ZGroup(id) { + ec_group_init(&group, id); + this->group_param = OpenABE_convertCurveIDToString(id); + zml_bignum_init(&order); + ec_get_order(group, order); +} + +ECGroup::~ECGroup() { + ec_group_free(group); + zml_bignum_free(order); +} + +void ECGroup::getGenerator(ec_point_t g) { ec_get_generator(group, g); } + +void ECGroup::getGroupOrder(bignum_t o) { zml_bignum_copy(o, order); } + +/******************************************************************************** + * Implementation of the G_t class + ********************************************************************************/ + +G_t::G_t() { + this->isInit = true; + this->ecgroup = nullptr; + ec_point_set_null(this->m_G); +} + +G_t::G_t(std::shared_ptr ecgroup) { + this->isInit = true; + this->ecgroup = ecgroup; + ec_point_init(GET_GROUP(this->ecgroup), &this->m_G); + ec_point_set_inf(GET_GROUP(this->ecgroup), this->m_G); +} + +G_t::G_t(const G_t &w) { + this->isInit = true; + if (w.ecgroup != nullptr) { + this->ecgroup = w.ecgroup; + } else { + throw OpenABE_ERROR_INVALID_GROUP_PARAMS; + } + ec_point_init(GET_GROUP(this->ecgroup), &this->m_G); + ec_point_copy(this->m_G, w.m_G); +} + +G_t &G_t::operator=(const G_t &w) { + if (isInit == true) { + ec_point_copy(this->m_G, w.m_G); + if (w.ecgroup != nullptr) { + this->ecgroup = w.ecgroup; + } + } else + ro_error(); + return *this; +} + +G_t::~G_t() { + if (this->isInit) { + ec_point_free(this->m_G); + this->isInit = false; + } +} + +G_t operator*(const G_t &x, const G_t &y) { + G_t z(x.ecgroup); + ec_point_add(GET_GROUP(z.ecgroup), z.m_G, x.m_G, y.m_G); + return z; +} + +G_t G_t::exp(ZP_t &z) { + G_t g(this->ecgroup); + ec_point_mul(GET_GROUP(g.ecgroup), g.m_G, this->m_G, z.m_ZP); + return g; +} + +void G_t::get(ZP_t &X, ZP_t &Y) { + if (this->isInit) { + ec_get_coordinates(GET_GROUP(this->ecgroup), X.m_ZP, Y.m_ZP, this->m_G); + } +} + +ostream &operator<<(ostream &os, const G_t &g) { + os << ec_point_to_string(GET_GROUP(g.ecgroup), g.m_G); + return os; +} + +void G_t::serialize(OpenABEByteString &result) const { + OpenABEByteString ss; + string str; + size_t total_len; + + if (this->isInit) { + result.clear(); + result.insertFirstByte(OpenABE_ELEMENT_G_t); + total_len = + ec_convert_to_bytestring(GET_GROUP(this->ecgroup), ss, this->m_G); + // cout << "len: " << ss.size() << ", total_len: " << total_len << endl; + ASSERT(ss.size() == total_len, OpenABE_ERROR_SERIALIZATION_FAILED); + result.pack16bits((uint16_t)total_len); + result += ss; + ss.clear(); + } else { + /* throw an error */ + throw OpenABE_ERROR_ELEMENT_NOT_INITIALIZED; + } +} + +void G_t::deserialize(OpenABEByteString &input) { + size_t inputSize = input.size(), hdrLen = 3; + + if (this->isInit && this->ecgroup != nullptr) { + // first byte is the group type + if (input.at(0) == OpenABE_ELEMENT_G_t && inputSize > hdrLen) { + uint16_t len = 0; + // read 2 bytes from right to left + len |= input.at(2); // Moves to 0x00FF + len |= (input.at(1) << 8); // Moves to 0xFF00 + ASSERT(input.size() == (len + hdrLen), OpenABE_ERROR_SERIALIZATION_FAILED); + + uint8_t *pointstr = (input.getInternalPtr() + hdrLen); + if (is_ec_point_null(this->m_G)) { + ec_point_init(GET_GROUP(this->ecgroup), &this->m_G); + } + ec_convert_to_point(GET_GROUP(this->ecgroup), this->m_G, pointstr, len); + } + } else { + throw OpenABE_ERROR_ELEMENT_NOT_INITIALIZED; + } +} + +bool G_t::isEqual(ZObject *z) const { + G_t *z1 = dynamic_cast(z); + if (z1 != NULL) { + return *z1 == *this; + } + return false; +} + +} diff --git a/src/zml/zelliptic.cpp b/src/zml/zelliptic.cpp new file mode 100644 index 00000000..14d91ff1 --- /dev/null +++ b/src/zml/zelliptic.cpp @@ -0,0 +1,284 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zelliptic.cpp +/// +/// \brief Class implementation for ordinary elliptic curves (NIST). +/// +/// \author J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Utilities for the OpenABEEllipticCurve + ********************************************************************************/ +namespace oabe { + +/*! + * Factory for creating new OpenABEEllipticCurve objects + * + * @return The pairing object or NULL + */ + +OpenABEEllipticCurve *OpenABE_createNewEllipticCurve(const string &ecParams) { + return new OpenABEEllipticCurve(ecParams); +} + +string OpenABE_ECParamsForSecurityLevel(OpenABESecurityLevel securityLevel) { + if (securityLevel == 128) + return "NIST_P256"; + else if (securityLevel == 256) + return "NIST_P384"; + else if (securityLevel == 512) + return "NIST_P521"; + return ""; +} + +OpenABECurveID OpenABE_convertIntToCurveID(uint8_t curveID) { + OpenABECurveID id; + if (curveID == OpenABE_NIST_P256_ID) { + id = OpenABE_NIST_P256_ID; + } else if (curveID == OpenABE_NIST_P384_ID) { + id = OpenABE_NIST_P384_ID; + } else if (curveID == OpenABE_NIST_P521_ID) { + id = OpenABE_NIST_P521_ID; + } else { + throw OpenABE_ERROR_INVALID_PARAMS_ID; + } + + return id; +} + +int OpenABE_convertStringToNID(string paramsID) { + int NID = 0; + if (paramsID == "NIST_P256") { + NID = OBJ_sn2nid("prime256v1"); + } else if (paramsID == "NIST_P384") { + NID = OBJ_sn2nid("secp384r1"); + } else if (paramsID == "NIST_P521") { + NID = OBJ_sn2nid("secp521r1"); + } else if (paramsID == "BN_P254") { +#if defined(BP_WITH_OPENSSL) + NID = NID_fp254bnb; +#else + throw OpenABE_ERROR_INVALID_PARAMS_ID; +#endif + } else { + // Unrecognized parameter type + throw OpenABE_ERROR_INVALID_PARAMS_ID; + } + + return NID; +} + +int OpenABE_convertCurveIDToNID(OpenABECurveID id) { + int NID = 0; + if (id == OpenABE_NIST_P256_ID) { + NID = OBJ_sn2nid("prime256v1"); + } else if (id == OpenABE_NIST_P384_ID) { + NID = OBJ_sn2nid("secp384r1"); + } else if (id == OpenABE_NIST_P521_ID) { + NID = OBJ_sn2nid("secp521r1"); + } else if (id == OpenABE_BN_P254_ID) { +#if defined(BP_WITH_OPENSSL) + NID = NID_fp254bnb; +#else + throw OpenABE_ERROR_INVALID_PARAMS_ID; +#endif + } else { + /* NOTE: add other curves as they are added to openssl for BP */ + // Unrecognized parameter type + throw OpenABE_ERROR_INVALID_PARAMS_ID; + } + + return NID; +} + + +/******************************************************************************** + * Implementation of the OpenABEEllipticCurve class + ********************************************************************************/ + +/*! + * Constructor for the OpenABEEllipticCurve base class. + * + */ +OpenABEEllipticCurve::OpenABEEllipticCurve(const string &ecParams) : ZObject() { + AssertLibInit(); + // Look up the EC parameters (throws an error if not valid) + OpenABECurveID id = OpenABE_convertStringToCurveID(ecParams); + this->ecParams = ecParams; + this->curveID = id; + this->ecgroup = make_shared(id); +} + +/*! + * Constructor for the OpenABEEllipticCurve class. + * + */ + +OpenABEEllipticCurve::OpenABEEllipticCurve(const OpenABEEllipticCurve ©From) + : ZObject() { + AssertLibInit(); + this->ecParams = copyFrom.getECParams(); + + // Look up the EC parameters (throws an error if not valid) + OpenABECurveID id = OpenABE_convertStringToCurveID(this->ecParams); + this->curveID = id; + this->ecgroup = make_shared(id); +} + +/*! + * Destructor for the OpenABEContextABE base class. + * + */ +OpenABEEllipticCurve::~OpenABEEllipticCurve() {} + +/*! + * Return the elliptic curve parameter string. + * + * @return Curve parameter string + */ + +string OpenABEEllipticCurve::getECParams() const { return this->ecParams; } + +/*! + * Return the elliptic curve parameter ID. + * + * @return Curve parameter ID + */ + +OpenABECurveID OpenABEEllipticCurve::getCurveID() const { return this->curveID; } + +ZP_t +OpenABEEllipticCurve::initZP() +{ + ZP_t z; + this->getGroupOrder(z.order); + z.isOrderSet = true; + return z; +} + +/*! + * Generate and return a random group element in ZP. + * + * @return group element in ZP + */ +ZP_t OpenABEEllipticCurve::randomZP(OpenABERNG *rng) { + ZP_t result; + this->getGroupOrder(result.order); + result.isOrderSet = true; + result.setRandom(rng); + return result; +} + +G_t +OpenABEEllipticCurve::initG() +{ + G_t g(this->ecgroup); + return g; +} + +/*! + * Return a generator G of the selected elliptic curve. + * + * @return group element in G + */ +G_t OpenABEEllipticCurve::getGenerator() { + G_t result(this->ecgroup); + this->ecgroup->getGenerator(result.m_G); + return result; +} + +/*! + * Return the order of the selected elliptic curve. + * + * @return order of the group in ZP. + */ +ZP_t OpenABEEllipticCurve::getGroupOrder() { + ZP_t result; + this->ecgroup->getGroupOrder(result.m_ZP); + return result; +} + +void OpenABEEllipticCurve::getGroupOrder(bignum_t o) { + ASSERT_NOTNULL(o); + this->ecgroup->getGroupOrder(o); +} + +/*! + * Test whether a point is at infinity on the elliptic curve. + * + * @return Success or failure. + */ +bool OpenABEEllipticCurve::isAtInfinity(G_t &point) { + if (ec_point_is_inf(GET_GROUP(this->ecgroup), point.m_G) == 1) { + return true; + } + return false; +} + +/*! + * Test whether a point is on the elliptic curve. + * + * @return Success or failure. + */ +bool OpenABEEllipticCurve::isOnCurve(G_t &point) { + if (ec_point_is_on_curve(GET_GROUP(this->ecgroup), point.m_G)) { + return true; + } + + return false; +} + +/*! + * Convert a uint8_t into an elliptic curve identifier. + * + * @return a string of the elliptic curve ID. + */ +string OpenABE_convertECCurveIDToString(uint8_t curveID) { + if (curveID == OpenABE_NIST_P256_ID) { + return "NIST_P256"; + } else if (curveID == OpenABE_NIST_P384_ID) { + return "NIST_P384"; + } else if (curveID == OpenABE_NIST_P521_ID) { + return "NIST_P521"; + } else { + return ""; + } +} + +} diff --git a/src/zml/zgroup.cpp b/src/zml/zgroup.cpp new file mode 100644 index 00000000..e7205894 --- /dev/null +++ b/src/zml/zgroup.cpp @@ -0,0 +1,67 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zgroup.cpp +/// +/// \brief Base class definition for OpenABE groups (EC/pairings) +/// +/// \author J. Ayo Akinyele +/// + +#define __ZGROUP_CPP__ + +#include + +/******************************************************************************** + * Implementation of the ZGroup class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the ZGroup class. + * + */ + +ZGroup::ZGroup(OpenABECurveID id) { + this->id = id; + this->group_param = ""; +} + +/*! + * Destructor for the ZGroup class. + * + */ + +ZGroup::~ZGroup() {} + +OpenABECurveID ZGroup::getCurveID() { return id; } + +std::ostream &operator<<(std::ostream &os, const ZGroup &z) { + os << z.group_param << " : " << z.id; + return os; +} +} + diff --git a/src/zml/zpairing.cpp b/src/zml/zpairing.cpp new file mode 100644 index 00000000..06160067 --- /dev/null +++ b/src/zml/zpairing.cpp @@ -0,0 +1,370 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zpairing.cpp +/// +/// \brief Implementation for bilinear maps (or pairings). +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#define __ZPAIRING_CPP__ + +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +} +using namespace std; + +namespace oabe { + +// Utility functions + +/*! + * Global pairing library initialization + * + * @return OpenABE_NOERROR or an error code + */ + +OpenABE_ERROR +zMathInitLibrary() +{ + // Initialize ZML + zml_init(); + return OpenABE_NOERROR; +} + +/*! + * Global pairing library shutdown + * + * @return OpenABE_NOERROR or an error code + */ + +OpenABE_ERROR +zMathShutdownLibrary() +{ + // Cleanup ZML + zml_clean(); + return OpenABE_NOERROR; +} + +/*! + * Factory for creating new OpenABEPairing objects + * + * @return The pairing object or NULL + */ + +OpenABEPairing* +OpenABE_createNewPairing(const string &pairingParams) +{ + return new OpenABEPairing(pairingParams); +} + +/*! + * Convert a symmetric-equivalent security level into an ID string + * for a set of pairing parameters. + * + * @return The corresponding ID string or NULL + */ + +string +OpenABE_pairingParamsForSecurityLevel(OpenABESecurityLevel securityLevel) +{ + if(securityLevel == 128) + return "BN_P256"; + return ""; +} + + +/******************************************************************************** + * Implementation of the OpenABEPairing class + ********************************************************************************/ + +/*! + * Constructor for the OpenABEPairing class. + * + */ + +OpenABEPairing::OpenABEPairing(const string &pairingParams) : ZObject() +{ + AssertLibInit(); + // Look up the pairing parameters and set them + this->curveID = getPairingCurveID(pairingParams); + + this->bpgroup = make_shared(this->curveID); + zml_bignum_init(&this->order); + this->bpgroup->getGroupOrder(this->order); +} + +/*! + * Constructor for the OpenABEPairing class. + * + */ +OpenABEPairing::OpenABEPairing(const OpenABEPairing ©From) : ZObject() +{ + AssertLibInit(); + // copy the pairing params first + string pairingParams = copyFrom.getPairingParams(); + + // Look up the pairing parameters and set them in RELIC + this->curveID = getPairingCurveID(pairingParams); + + this->bpgroup = make_shared(this->curveID); + zml_bignum_init(&this->order); + this->bpgroup->getGroupOrder(this->order); +} + +/*! + * Destructor for the OpenABEPairing class. + * + */ +OpenABEPairing::~OpenABEPairing() +{ + zml_bignum_free(order); + this->bpgroup.reset(); +} + +void +OpenABEPairing::initZP(ZP& result, uint32_t v) +{ + result = v; + result.setOrder(order); +} + +ZP +OpenABEPairing::initZP() +{ + ZP z = (uint32_t) 0; + z.setOrder(order); + return z; +} + +G1 +OpenABEPairing::initG1() +{ + G1 g(this->bpgroup); + return g; +} + +G2 +OpenABEPairing::initG2() +{ + G2 g(this->bpgroup); + return g; +} + +GT +OpenABEPairing::initGT() +{ + GT g(this->bpgroup); + return g; +} + +/*! + * Generate and return a random group element in ZP. + * + * @return group element in ZP + */ +ZP +OpenABEPairing::randomZP(OpenABERNG *rng) +{ + ASSERT_NOTNULL(rng); + ZP result; + result.setRandom(rng, order); + return result; +} + +/*! + * Generate and return a random group element in G1. + * + * @return group element in G1 + */ +G1 +OpenABEPairing::randomG1(OpenABERNG *rng) +{ + ASSERT_NOTNULL(rng); + G1 result(this->bpgroup); + result.setRandom(rng); + return result; +} + +/*! + * Generate and return a random group element in G2. + * + * @return group element in G2 + */ +G2 +OpenABEPairing::randomG2(OpenABERNG *rng) +{ + ASSERT_NOTNULL(rng); + G2 result(this->bpgroup); + result.setRandom(rng); + return result; +} + +G1 +OpenABEPairing::hashToG1(OpenABEByteString& keyPrefix, string msg) +{ + ASSERT_PAIRING(this); + OpenABEByteString tmp; + // set the key prefix + tmp = keyPrefix; + // append the message + tmp += msg; + // hash the message to G1 + // (note that g1_map first hashes to ZP, then to G1) + G1 g1(this->bpgroup); + std::string digest, str = tmp.toString(); + oabe::sha256(digest, str); + uint8_t *xstr = (uint8_t *)digest.c_str(); + size_t xstr_len = digest.size(); + g1_map_op(GET_BP_GROUP(this->bpgroup), g1.m_G1, xstr, xstr_len); + return g1; +} + +GT +OpenABEPairing::pairing(G1& g1, G2& g2) +{ + GT result(this->bpgroup); + bp_map_op(GET_BP_GROUP(this->bpgroup), result.m_GT, g1.m_G1, g2.m_G2); + if(result.isInfinity()) { + result.setIdentity(); + } + return result; +} + +void +OpenABEPairing::multi_pairing(GT& gt, std::vector& g1, std::vector& g2) { + multi_bp_map_op(GET_BP_GROUP(this->bpgroup), gt, g1, g2); + if(gt.isInfinity()) { + gt.setIdentity(); + } +} + +/*! + * Return the pairing parameters string. + * + * @return Pairing parameters string + */ + +string +OpenABEPairing::getPairingParams() const +{ + return this->pairingParams; +} + +/*! + * Return the pairing parameters ID. + * + * @return Pairing parameters ID + */ + +OpenABECurveID +OpenABEPairing::getCurveID() const +{ + return this->curveID; +} + +/* + * Convert a pairing parameters identifier string into a RELIC + * identifier for the parameters. + * + * @return An int representing the parameters, or -1 if not found. + */ + +OpenABECurveID +getPairingCurveID(const string ¶msID) +{ + OpenABECurveID curveID = OpenABE_NONE_ID; + + if (paramsID == "BN_P254") { + curveID = OpenABE_BN_P254_ID; + } else if (paramsID == "BN_P256") { + curveID = OpenABE_BN_P256_ID; + } else if (paramsID == "BN_P382") { + curveID = OpenABE_BN_P382_ID; + } else { + // Unrecognized parameter type + throw OpenABE_ERROR_INVALID_PARAMS; + } + + return curveID; +} + +OpenABEByteString +OpenABEPairing::hashToBytes(uint8_t *buf, uint32_t buf_len) +{ + uint8_t hash[SHA256_LEN]; + sha256(hash, buf, buf_len); + + OpenABEByteString b; + b.appendArray(hash, SHA256_LEN); + return b; +} + +// implements a variable-sized hash function +// block_len = len / md_len ... rounding up +// H(00 || hash_byte || m) || H(01 || hash_byte || m) || ... || H(n || hash_byte || m) +// ... where 'n' is block_len and 'm' is message +OpenABEByteString +OpenABEPairing::hashFromBytes(OpenABEByteString &buf, uint32_t target_len, uint8_t hash_prefix) +{ + // compute number of hash blocks needed + int block_len = ceil(((double)target_len) / SHA256_LEN); + // set the hash_len + int hash_len = block_len * SHA256_LEN; + uint8_t hash[hash_len+1]; + memset(hash, 0, hash_len+1); + + OpenABEByteString buf2 = buf; + uint8_t count = 0; + + buf2.insertFirstByte(hash_prefix); + buf2.insertFirstByte(count); + uint8_t *ptr = buf2.getInternalPtr(); + uint8_t *hash_ptr = hash; + + for(int i = 0; i < block_len; i++) { + // H(count || hash_prefix || buf) + sha256(hash_ptr, buf2.getInternalPtr(), buf2.size()); + count++; + ptr[0] = count; // change block number + hash_ptr += SHA256_LEN; // move ptr by SHA256_LEN size + } + + OpenABEByteString b; + b.appendArray(hash, target_len); + return b; +} + +} diff --git a/src/zobject.cpp b/src/zobject.cpp new file mode 100644 index 00000000..943ccbf4 --- /dev/null +++ b/src/zobject.cpp @@ -0,0 +1,216 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zobject.cpp +/// +/// \brief Implementation for the abstract OpenABE object. +/// +/// \author Matthew Green and J. Ayo Akinyele +/// + +#include +#include +#include +#include +#include +#include + +using namespace std; + +/******************************************************************************** + * Implementation of the ZObject class + ********************************************************************************/ +namespace oabe { + +/*! + * Constructor for the ZObject class. + * + */ + +ZObject::ZObject() +{ + this->refCount = 1; +} + +/*! + * Destructor for the ZObject class. + * + */ + +ZObject::~ZObject() +{ +} + +/*! + * Increment the reference count. + * + */ + +void +ZObject::addRef() +{ + this->refCount++; +} + +/*! + * Decrement the reference count. + * + */ + +void +ZObject::deRef() +{ + if (this->refCount-- <= 0) { + delete this; + } +} + +void +OpenABEZeroize(void *b, size_t b_len) { + ASSERT_NOTNULL(b); + volatile uint8_t *p = (uint8_t *)b; + if (b_len > 0) { + while( b_len-- ) { + *p++ = 0; + } + } +} + +/* helper methods to assist with serializing and base-64 encoding group elements */ +static const string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +/* Note that the following was borrowed from Copyright (C) 2004-2008 Ren� Nyffenegger (*/ + +bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +string Base64Encode(unsigned char const* bytes_to_encode, unsigned int in_len) { + string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + +} + +string Base64Decode(string const& encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + size_t in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + // The only case where we have a valid input and the following + // if happens is terminating '=' characters + if (in_ < encoded_string.size()) { + // Look for terminating '='s, maximum 2 + if (encoded_string.size() - in_ > 2) { + throw OpenABE_ERROR_INVALID_INPUT; + } + size_t tmp = in_; + for (; tmp < encoded_string.size(); tmp++) { + if (encoded_string[tmp] != '=') { + break; + } + } + if (tmp != encoded_string.size()) { + throw OpenABE_ERROR_INVALID_INPUT; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +} + +} diff --git a/src/zparser.yy b/src/zparser.yy new file mode 100644 index 00000000..0cce6bb0 --- /dev/null +++ b/src/zparser.yy @@ -0,0 +1,198 @@ +/** \file zparser.yy Contains the OpenABEPolicy and OpenABEAttributeList Bison parser source */ + +%{ /*** C/C++ Declarations ***/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +%} + +/*** yacc/bison Declarations ***/ + +/* Require bison 3.0 or later */ +%require "3.0" + +/* add debug output code to generated parser. disable this for release + * versions. */ +%debug + +/* start symbol is named "start" */ +%start start + +/* write out a header file containing the token defines */ +%defines + +/* use newer C++ skeleton file */ +%skeleton "lalr1.cc" + +/* namespace to enclose parser in */ +%name-prefix "oabe" + +/* set the parser's class identifier */ +%define "parser_class_name" {Parser} + +/* keep track of the current position within the input */ +%locations +%initial-action +{ + // initialize the initial location object + @$.begin.filename = @$.end.filename = &driver.streamname; +}; + +/* The driver is passed by reference to the parser and to the scanner. This + * provides a simple but effective pure interface, not relying on global + * variables. */ +%parse-param { class Driver& driver } + +/* verbose error messages */ +%error-verbose + + /*** BEGIN EXAMPLE - Change the example grammar's tokens below ***/ + +%union { + std::string* stringVal; + class OpenABETreeNode* treeNode; + std::vector* oabeAttrList; + uint32_t uintVal; + class OpenABEUInteger* uInteger; +} + +%token END 0 "end of file" +%token EOL "end of line" +%token LEAF "string" +%token UINT "an integer" +%type number "OpenABEUInteger" +%type policy "OpenABE tree node" +%type attrlist "OpenABE attribute list" + +%left OR +%left AND +%token OF "of" +%token EQ "==" +%token ASSIGN "=" +%token LEQ "<=" +%token GEQ ">=" +%token ERROR "error" +%token START_POLICY "[0]:" +%token START_ATTRLIST "[1]:" +%token IN "in" +%destructor { delete $$; } LEAF +%destructor { delete $$; } policy +%destructor { delete $$; } attrlist +%destructor { delete $$; } number + + /*** END EXAMPLE - Change the example grammar's tokens above ***/ + +%{ + +#include +#include + +/* this "connects" the bison parser in the driver to the flex scanner class + * object. it defines the yylex() function call to pull the next token from the + * current lexer object of the driver context. */ +#undef yylex +#define yylex driver.lexer->lex + +%} + +%% /*** Grammar Rules ***/ + + /*** BEGIN EXAMPLE - Change the example grammar rules below ***/ + +start: + START_POLICY policy { driver.set_policy($2); } | + START_ATTRLIST attrlist { driver.set_attrlist($2); }; + +number: UINT '#' UINT { + if (!oabe::checkValidBit($1, $3)) { + YYERROR; + } else { + $$ = create_expint($1, $3); + } + } + | UINT { $$ = create_flexint($1); } + +policy: LEAF { $$ = driver.leaf_node(*$1); delete $1; } + | policy OR policy { $$ = driver.kof2_tree(1, $1, $3); } + | policy AND policy { $$ = driver.kof2_tree(2, $1, $3); } + | LEAF '<' number { $$ = driver.lt_policy(*$1, $3); delete $1; delete $3; } + | LEAF '>' number { $$ = driver.gt_policy(*$1, $3); delete $1; delete $3; } + | LEAF LEQ number { $$ = driver.le_policy(*$1, $3); delete $1; delete $3; } + | LEAF GEQ number { $$ = driver.ge_policy(*$1, $3); delete $1; delete $3; } + | LEAF EQ number { $$ = driver.eq_policy(*$1, $3); delete $1; delete $3; } + | '(' policy ')' { $$ = $2; } + /* for range-types */ + | LEAF IN '(' number '-' number ')' + { $$ = driver.range_policy(*$1, $4, $6); + delete $1; delete $4; delete $6; + } + | LEAF IN '{' number '-' number '}' + { $$ = driver.range_incl_policy(*$1, $4, $6); + delete $1; delete $4; delete $6; + } + /* for date-types */ + | LEAF '=' LEAF number ',' number + { std::unique_ptr month(oabe::get_month(*$3)); + $$ = driver.set_date_in_policy(*$1, month.get(), $4, $6); + delete $1; delete $3; delete $4; delete $6; + } + | LEAF '=' LEAF number '-' number ',' number + { std::unique_ptr month(oabe::get_month(*$3)); + $$ = driver.range_date_in_policy(*$1, month.get(), $4, $6, $8); + delete $1; delete $3; delete $4; delete $6; delete $8; + } + | LEAF '>' LEAF number ',' number + { std::unique_ptr month(oabe::get_month(*$3)); + $$ = driver.gt_date_in_policy(*$1, month.get(), $4, $6); + delete $1; delete $3; delete $4; delete $6; + } + | LEAF '<' LEAF number ',' number + { std::unique_ptr month(oabe::get_month(*$3)); + $$ = driver.lt_date_in_policy(*$1, month.get(), $4, $6); + delete $1; delete $3; delete $4; delete $6; + } + | LEAF GEQ LEAF number ',' number + { std::unique_ptr month(oabe::get_month(*$3)); + $$ = driver.ge_date_in_policy(*$1, month.get(), $4, $6); + delete $1; delete $3; delete $4; delete $6; + } + | LEAF LEQ LEAF number ',' number + { std::unique_ptr month(oabe::get_month(*$3)); + $$ = driver.le_date_in_policy(*$1, month.get(), $4, $6); + delete $1; delete $3; delete $4; delete $6; + } + +attrlist: LEAF { $$ = driver.leaf_attr(*$1); delete $1; } + | '|' attrlist { $$ = driver.concat_attr($2, nullptr); } + | attrlist '|' { $$ = driver.concat_attr($1, nullptr); } + | attrlist '|' attrlist { $$ = driver.concat_attr($1, $3); delete $3; } + | LEAF '=' number { $$ = driver.attr_num(*$1, $3); delete $1; delete $3; } + | LEAF '=' LEAF number ',' number + { std::unique_ptr month(oabe::get_month(*$3)); + $$ = driver.set_date_in_attrlist(*$1, *$3, month.get(), $4, $6); + delete $1; delete $3; delete $4; delete $6; + } +; + + + + /*** END EXAMPLE - Change the example grammar rules above ***/ + +%% /*** Additional Code ***/ + +void oabe::Parser::error(const Parser::location_type& l, + const std::string& m) +{ + driver.error(l, m); +} diff --git a/src/zscanner.ll b/src/zscanner.ll new file mode 100644 index 00000000..b3645667 --- /dev/null +++ b/src/zscanner.ll @@ -0,0 +1,179 @@ +/** \file zscanner.ll Define the OpenABE policy Flex lexical scanner */ + +%{ /*** C/C++ Declarations ***/ + +#include +#include +#include + +/* import the parser's token type into a local typedef */ +typedef oabe::Parser::token token; +typedef oabe::Parser::token_type token_type; + +/* By default yylex returns int, we use token_type. Unfortunately yyterminate + * by default returns 0, which is not of token_type. */ +#define yyterminate() return token::END + +/* This disables inclusion of unistd.h, which is not available under Visual C++ + * on Win32. The C++ scanner uses STL streams instead. */ +#define YY_NO_UNISTD_H + +%} + +/*** Flex Declarations and Options ***/ + +/* enable c++ scanner class generation */ +%option c++ + +/* change the name of the scanner class. results in "OpenABEFlexLexer" */ +%option prefix="OpenABE" + +/* the manual says "somewhat more optimized" */ +%option batch + +/* enable scanner to generate debug output. disable this for release + * versions. */ +%option debug + +/* no support for include files is planned */ +%option yywrap nounput + +/* enables the use of start condition stacks */ +%option stack + +/* The following paragraph suffices to track locations accurately. Each time + * yylex is invoked, the begin position is moved onto the end position. */ +%{ +#define YY_USER_ACTION yylloc->columns(yyleng); +%} + +%% /*** Regular Expressions Part ***/ + + /* code to place at the beginning of yylex() */ +%{ + // reset location + yylloc->step(); +%} + + /*** BEGIN EXAMPLE - Change the example lexer rules below ***/ + +[0-9]+ { + errno = 0; + unsigned long n = strtoul (yytext, NULL, 10); + if (! (n < UINT_MAX && errno != ERANGE)) { /* 32-bit unsigned integers */ + std::cerr << *yylloc << ": unsigned integer is out of range" << std::endl; + return token::ERROR; + } else if ( n == 0 ) { + std::cerr << *yylloc << ": cannot build meaningful comparison trees with 0" << std::endl; + return token::ERROR; + } + yylval->uintVal = n; + return token::UINT; +} + +[A-Za-z/\\.\[\]$~][A-Za-z0-9_/\\,.\*\-:!~\[\]\&\$\#\@\%\^{}]* { + yylval->stringVal = new std::string(yytext, yyleng); + if(yylval->stringVal->compare("[0]:") == 0) { + delete yylval->stringVal; + return token::START_POLICY; + } else if(yylval->stringVal->compare("[1]:") == 0) { + delete yylval->stringVal; + return token::START_ATTRLIST; + } else if(yylval->stringVal->compare("or") == 0 || yylval->stringVal->compare("OR") == 0) { + delete yylval->stringVal; + return token::OR; + } else if(yylval->stringVal->compare("and") == 0 || yylval->stringVal->compare("AND") == 0) { + delete yylval->stringVal; + return token::AND; + } else if(yylval->stringVal->compare("in") == 0 || yylval->stringVal->compare("IN") == 0) { + delete yylval->stringVal; + return token::IN; + } else if(yylval->stringVal->find(EXPINT_KEYWORD) != std::string::npos) { + std::cerr << *yylloc << ": '" << EXPINT_KEYWORD << "' is reserved and cannot be user-specified." << std::endl; + return token::ERROR; + } else { + return token::LEAF; + } +} + +[<>=][=] { + yylval->stringVal = new std::string(yytext, yyleng); + if(yylval->stringVal->compare("<=") == 0) { + delete yylval->stringVal; + return token::LEQ; + } else if(yylval->stringVal->compare(">=") == 0) { + delete yylval->stringVal; + return token::GEQ; + } else if(yylval->stringVal->compare("==") == 0) { + delete yylval->stringVal; + return token::EQ; + } else { + delete yylval->stringVal; + std::cerr << *yylloc << ": invalid operator. Allowed operators: [<, <=, >, >=, ==]" << std::endl; + return token::ERROR; + } +} + + /* gobble up white-spaces */ +[ \t\r]+ { + yylloc->step(); +} + + /* gobble up end-of-lines */ +\n { + yylloc->lines(yyleng); yylloc->step(); + return token::EOL; +} + + /* pass all other characters up to bison */ +. { + return static_cast(*yytext); +} + + /*** END EXAMPLE - Change the example lexer rules above ***/ + +%% /*** Additional Code ***/ + +namespace oabe { + +Scanner::Scanner(std::istream* in, + std::ostream* out) + : OpenABEFlexLexer(in, out) +{ +} + +Scanner::~Scanner() +{ +} + +void Scanner::set_debug(bool b) +{ + yy_flex_debug = b; +} + +} + +/* This implementation of OpenABEFlexLexer::yylex() is required to fill the + * vtable of the class OpenABEFlexLexer. We define the scanner's main yylex + * function via YY_DECL to reside in the Scanner class instead. */ + +#ifdef yylex +#undef yylex +#endif + +int OpenABEFlexLexer::yylex() +{ + std::cerr << "in OpenABEFlexLexer::yylex() !" << std::endl; + return 0; +} + +/* When the scanner receives an end-of-file indication from YY_INPUT, it then + * checks the yywrap() function. If yywrap() returns false (zero), then it is + * assumed that the function has gone ahead and set up `yyin' to point to + * another input file, and scanning continues. If it returns true (non-zero), + * then the scanner terminates, returning 0 to its caller. */ + +int OpenABEFlexLexer::yywrap() +{ + return 1; +} diff --git a/src/zsymcrypto.cpp b/src/zsymcrypto.cpp new file mode 100644 index 00000000..1c5b6cd5 --- /dev/null +++ b/src/zsymcrypto.cpp @@ -0,0 +1,478 @@ +/// +/// Copyright (c) 2018 Zeutro, LLC. All rights reserved. +/// +/// This file is part of Zeutro's OpenABE. +/// +/// OpenABE is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// OpenABE is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public +/// License along with OpenABE. If not, see . +/// +/// You can be released from the requirements of the GNU Affero General +/// Public License and obtain additional features by purchasing a +/// commercial license. Buying such a license is mandatory if you +/// engage in commercial activities involving OpenABE that do not +/// comply with the open source requirements of the GNU Affero General +/// Public License. For more information on commerical licenses, +/// visit . +/// +/// \file zsymcrypto.cpp +/// +/// \brief Thin wrappers for symmetric key scheme contexts. +/// +/// \author Alan Dunn and J. Ayo Akinyele +/// + +#include +#include +#include +#include + +using namespace std; + +namespace oabe { + +namespace crypto { + +/******************************************************************************** + * Implementation of the OpenABESymKeyAuthEnc class + ********************************************************************************/ + +void OpenABEComputeHKDF(OpenABEByteString& key, OpenABEByteString& salt, + OpenABEByteString& info, size_t key_len, OpenABEByteString& output_key) { + EVP_PKEY_CTX *kctx = NULL; + string error_msg = ""; + // check if key is at least a certain size > 0, < 1024 + size_t out_len = key_len; + uint8_t out_key[out_len+1]; + const EVP_MD *md = EVP_sha256(); + + // allocates public key algorithm context using alg specified by id + kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); + + if (EVP_PKEY_derive_init(kctx) <= 0) { + error_msg = "EVP_PKEY_derive_init"; + goto out; + } + + if (EVP_PKEY_CTX_set_hkdf_md(kctx, md) <= 0) { + error_msg = "EVP_PKEY_CTX_set_hkdf_md"; + goto out; + } + + if (salt.size() > 0) { + if (EVP_PKEY_CTX_set1_hkdf_salt(kctx, salt.getInternalPtr(), salt.size()) <= 0) { + error_msg = "EVP_PKEY_CTX_set1_salt"; + goto out; + } + } + + if (EVP_PKEY_CTX_set1_hkdf_key(kctx, key.getInternalPtr(), key.size()) <= 0) { + error_msg = "EVP_PKEY_CTX_set1_key"; + goto out; + } + + if (info.size() > 0) { + if (EVP_PKEY_CTX_add1_hkdf_info(kctx, info.getInternalPtr(), info.size()) <= 0) { + error_msg = "EVP_PKEY_CTX_add1_hkdf_info"; + goto out; + } + } + + if (EVP_PKEY_derive(kctx, out_key, &out_len) <= 0) { + error_msg = "EVP_PKEY_derive"; + goto out; + } + + output_key.clear(); + output_key.appendArray(out_key, out_len); +out: + // if kctx is NULL, nothing is done. + EVP_PKEY_CTX_free(kctx); + if (error_msg != "") { + throw oabe::CryptoException(error_msg); + } +} + +void generateSymmetricKey(std::string& key, uint32_t keyLen) +{ + OpenABEByteString key_buf; + OpenABERNG rng; + rng.getRandomBytes(&key_buf, (int) keyLen); + key = key_buf.toString(); +} + +// For debug purposes only!! +const string printAsHex(const string& bin_buf) +{ + OpenABEByteString buf; + buf += bin_buf; + return buf.toLowerHex(); +} + +OpenABESymKeyAuthEnc::OpenABESymKeyAuthEnc(int securitylevel, const string& zkey): ZObject() +{ + if(securitylevel == DEFAULT_AES_SEC_LEVEL) { + this->cipher = (EVP_CIPHER *) EVP_aes_256_gcm(); + // cout << "cipher_block_size: " << EVP_CIPHER_block_size(this->cipher) << endl; + } + this->iv_len = AES_BLOCK_SIZE; + this->aad_set = false; + this->key = zkey; +} + +OpenABESymKeyAuthEnc::OpenABESymKeyAuthEnc(int securitylevel, OpenABEByteString& zkey): ZObject() +{ + if(securitylevel == DEFAULT_AES_SEC_LEVEL) { + this->cipher = (EVP_CIPHER *) EVP_aes_256_gcm(); + // cout << "cipher_block_size: " << EVP_CIPHER_block_size(this->cipher) << endl; + } + this->iv_len = AES_BLOCK_SIZE; + this->aad_set = false; + this->key = zkey; +} + + +OpenABESymKeyAuthEnc::~OpenABESymKeyAuthEnc() +{ + if (this->aad_set) { + this->aad.zeroize(); + } +} + +void +OpenABESymKeyAuthEnc::chooseRandomIV() +{ + RAND_bytes(this->iv, AES_BLOCK_SIZE); +} + +void +OpenABESymKeyAuthEnc::setAddAuthData(OpenABEByteString &aad) +{ + if(aad.size() == 0) { + // fill AAD buffer with 0's + this->aad.fillBuffer(0, AES_BLOCK_SIZE); + } + else { + // copy 'aad' + this->aad = aad; + } + this->aad_set = true; +} + +void +OpenABESymKeyAuthEnc::setAddAuthData(uint8_t *aad, uint32_t aad_len) +{ + this->aad.clear(); + if(aad) { + this->aad.appendArray(aad, aad_len); + } else { + // fill AAD buffer with 0's + this->aad.fillBuffer(0, AES_BLOCK_SIZE); + } + this->aad_set = true; +} + + +OpenABE_ERROR +OpenABESymKeyAuthEnc::encrypt(const string& plaintext, OpenABEByteString *iv, OpenABEByteString *ciphertext, OpenABEByteString *tag) +{ + OpenABE_ERROR result = OpenABE_NOERROR; + uint8_t *ct = nullptr; + + try { + ASSERT_NOTNULL(iv); + ASSERT_NOTNULL(ciphertext); + ASSERT_NOTNULL(tag); + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + OpenABEByteString ivObj, ctObj, tagObj; + uint8_t *pt_ptr = (uint8_t *) plaintext.c_str(); + int len = 0, ctlen, pt_len = plaintext.size(); + if(pt_len < AES_BLOCK_SIZE) + /* add block size to the len */ + len += AES_BLOCK_SIZE; + else + /* add pt_len + block size to len */ + len += pt_len; + // allocate the temp output ciphertext buffer + // uint8_t ct[len+1]; + ct = (uint8_t*) malloc(len+1); + MALLOC_CHECK_OUT_OF_MEMORY(ct); + memset(ct, 0, len+1); + + // cout << "Plaintext:\n"; + // BIO_dump_fp(stdout, (const char *) &((*plaintext)[0]), plaintext->size()); + // cout << "Enc Key:\n"; + // BIO_dump_fp(stdout, (const char *) this->key.getInternalPtr(), this->key.size()); + + /* set cipher type and mode */ + EVP_EncryptInit_ex(ctx, this->cipher, NULL, NULL, NULL); + /* set the IV length as 128-bits */ + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, AES_BLOCK_SIZE, NULL); + /* initialize key and IV */ + + chooseRandomIV(); + EVP_EncryptInit_ex(ctx, NULL, NULL, this->key.getInternalPtr(), this->iv); + iv->clear(); + iv->appendArray(this->iv, this->iv_len); + + /* specify the additional authentication data (aad) */ + if (this->aad_set) { + EVP_EncryptUpdate(ctx, NULL, &ctlen, this->aad.getInternalPtr(), this->aad.size()); + } + + /* encrypt plaintext */ + EVP_EncryptUpdate(ctx, ct, &ctlen, pt_ptr, pt_len); + + // cout << "Ciphertext:\n"; + // BIO_dump_fp(stdout, (const char *) ct, ctlen); + ciphertext->clear(); + ciphertext->appendArray(ct, ctlen); + + /* finalize: computes authentication tag*/ + EVP_EncryptFinal_ex(ctx, ct, &len); + // For AES-GCM, the 'len' should be '0' because there is no extra bytes used for padding. + ASSERT(len == 0, OpenABE_ERROR_UNEXPECTED_EXTRA_BYTES); + + /* retrieve the tag */ + int tag_len = AES_BLOCK_SIZE; + uint8_t tag_buf[tag_len+1]; + memset(tag_buf, 0, tag_len+1); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_len, tag_buf); + + // cout << "Tag:\n"; + // BIO_dump_fp(stdout, (const char *) tag_buf, tag_len); + tag->clear(); + tag->appendArray(tag_buf, tag_len); + + EVP_CIPHER_CTX_free(ctx); + } catch(OpenABE_ERROR& e) { + result = e; + } + if (ct) + free(ct); + return result; +} + +bool +OpenABESymKeyAuthEnc::decrypt(string& plaintext, OpenABEByteString* iv, OpenABEByteString* ciphertext, OpenABEByteString* tag) +{ + ASSERT_NOTNULL(iv); + ASSERT_NOTNULL(ciphertext); + ASSERT_NOTNULL(tag); + + if(ciphertext->size() == 0) { + /* ciphertext has to be greater than 0 */ + return false; + } + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + uint8_t *pt = nullptr; + OpenABEByteString pt_buf; + + int pt_len, retValue; + uint8_t *ct_ptr = ciphertext->getInternalPtr(); + int ct_len = ciphertext->size(); + // cout << "Dec Ciphertext:\n"; + // BIO_dump_fp(stdout, (const char *) ct_ptr, ct_len); + + uint8_t *tag_ptr = tag->getInternalPtr(); + int tag_len = tag->size(); + ASSERT(tag_len == AES_BLOCK_SIZE, OpenABE_ERROR_INVALID_TAG_LENGTH); + // cout << "Dec Tag:\n"; + // BIO_dump_fp(stdout, (const char *) tag_ptr, tag_len); + + /* set cipher type and mode */ + EVP_DecryptInit_ex(ctx, this->cipher, NULL, NULL, NULL); + /* set the IV length as 128-bits */ + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv->size(), NULL); + /* specify key and iv */ + // cout << "Dec Key:\n"; + // BIO_dump_fp(stdout, (const char *) this->key.getInternalPtr(), this->key.size()); + EVP_DecryptInit_ex(ctx, NULL, NULL, this->key.getInternalPtr(), iv->getInternalPtr()); + + // OpenSSL says tag must be set *before* any EVP_DecryptUpdate call. + // This is a restriction for OpenSSL v1.0.1c and prior versions but also works + // thesame for later versions. To avoid OpenSSL version checks, we set the tag + // here which should work across all versions. + /* set the tag expected value */ + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag_ptr); + + /* specify additional authentication data */ + if(this->aad_set) { + EVP_DecryptUpdate(ctx, NULL, &pt_len, this->aad.getInternalPtr(), this->aad.size()); + } + + // uint8_t pt[ct_len+1]; + pt = (uint8_t*) malloc(ct_len+1); + MALLOC_CHECK_OUT_OF_MEMORY(pt); + memset(pt, 0, ct_len+1); + /* decrypt and store plaintext in pt buffer */ + EVP_DecryptUpdate(ctx, pt, &pt_len, ct_ptr, ct_len); + pt_buf.appendArray(pt, (uint32_t) pt_len); + + // cout << "Plaintext:\n"; + // BIO_dump_fp(stdout, (const char *) pt, pt_len); + + /* finalize decryption */ + retValue = EVP_DecryptFinal_ex(ctx, pt, &pt_len); + if (pt) { + free(pt); + } + // printf("Tag Verify %s\n", retValue > 0 ? "Successful!" : "Failed!"); + + EVP_CIPHER_CTX_free(ctx); + if(retValue > 0) { + /* tag verification successful */ + plaintext = pt_buf.toString(); + pt_buf.zeroize(); + return true; + } + else { + /* authentication failure */ + return false; + } +} + +/******************************************************************************** + * Implementation of the OpenABESymKeyHandleImpl class + ********************************************************************************/ + +OpenABESymKeyHandleImpl::OpenABESymKeyHandleImpl(const string& keyBytes, bool apply_b64_encode) { + try { + if (keyBytes.size() != DEFAULT_SYM_KEY_BYTES) { + throw OpenABE_ERROR_INVALID_LENGTH; + } + + security_level_ = DEFAULT_AES_SEC_LEVEL; + } catch (OpenABE_ERROR& error) { + string msg = OpenABE_errorToString(error); + throw runtime_error(msg); + } + + key_ = keyBytes; + b64_encode_ = apply_b64_encode; +} + +OpenABESymKeyHandleImpl::OpenABESymKeyHandleImpl(OpenABEByteString& keyBytes, + OpenABEByteString& authData, bool apply_b64_encode) { + try { + key_ = keyBytes.toString(); + if (key_.size() != DEFAULT_SYM_KEY_BYTES) { + throw OpenABE_ERROR_INVALID_LENGTH; + } + + security_level_ = DEFAULT_AES_SEC_LEVEL; + } catch (OpenABE_ERROR& error) { + string msg = OpenABE_errorToString(error); + throw runtime_error(msg); + } + + authData_ = authData; + b64_encode_ = apply_b64_encode; +} + + +OpenABESymKeyHandleImpl::~OpenABESymKeyHandleImpl() { + key_.clear(); + authData_.clear(); +} + +void OpenABESymKeyHandleImpl::encrypt(string& ciphertext, const string& plaintext) +{ + unique_ptr symkeyContext_(new OpenABESymKeyAuthEnc(security_level_, key_)); + try { + OpenABEByteString zciphertext, ziv, zct, ztag; + // set the additional auth data (if set) + if (authData_.size() > 0) { + symkeyContext_->setAddAuthData(authData_); + } else { + symkeyContext_->setAddAuthData(NULL, 0); + } + // now we can encrypt with sym key + if (symkeyContext_->encrypt(plaintext, &ziv, &zct, &ztag) != OpenABE_NOERROR) { + throw runtime_error("Encryption failed"); + } + + // serialize all three ziv, zciphertext and ztag + // cout << "<=== ENCRYPT ===>" << endl; + // cout << "iv: " << ziv.toLowerHex() << endl; + // cout << "ct: " << zct.toLowerHex() << endl; + // cout << "tg: " << ztag.toLowerHex() << endl; + // cout << "<=== ENCRYPT ===>" << endl; + + zciphertext.smartPack(ziv); + zciphertext.smartPack(zct); + zciphertext.smartPack(ztag); + string s = zciphertext.toString(); + if (b64_encode_) { + // output base64 encoded version + ciphertext = Base64Encode((const unsigned char *)s.c_str(), s.size()); + } else { + // output binary (caller handles encoding format) + ciphertext = s; + } + } catch (OpenABE_ERROR& error) { + string msg = OpenABE_errorToString(error); + throw runtime_error(msg); + } +} + +void OpenABESymKeyHandleImpl::decrypt(string& plaintext, const string& ciphertext) +{ + unique_ptr symkeyContext_(new OpenABESymKeyAuthEnc(security_level_, key_)); + try { + size_t index = 0; + OpenABEByteString zciphertext; + if (b64_encode_) { + zciphertext += Base64Decode(ciphertext); + } else { + zciphertext += ciphertext; + } + OpenABEByteString ziv, zct, ztag; + ziv = zciphertext.smartUnpack(&index); + zct = zciphertext.smartUnpack(&index); + ztag = zciphertext.smartUnpack(&index); + + // set the additional auth data (if set) + if (authData_.size() > 0) { + symkeyContext_->setAddAuthData(authData_); + } else { + symkeyContext_->setAddAuthData(NULL, 0); + } + bool dec_status = symkeyContext_->decrypt(plaintext, &ziv, &zct, &ztag); + if (!dec_status) { + throw runtime_error("Decryption failed"); + } + } catch (OpenABE_ERROR& error) { + string msg = OpenABE_errorToString(error); + throw runtime_error(msg); + } +} + +void +OpenABESymKeyHandleImpl::exportRawKey(string& key) { + key = this->key_; +} + +void +OpenABESymKeyHandleImpl::exportKey(string& key) { + size_t key_len = this->key_.size(); + OpenABEByteString secret_key, salt, info, output_key; + secret_key += this->key_; + // info: export key is the label + info += "export key"; + OpenABEComputeHKDF(secret_key, salt, info, key_len, output_key); + key = output_key.toString(); +} + +}}