1 /* 2 * Copyright 2019 Google LLC. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * https://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PRIVATE_JOIN_AND_COMPUTE_COMMUTATIVE_ELGAMAL_H_ 17 #define PRIVATE_JOIN_AND_COMPUTE_COMMUTATIVE_ELGAMAL_H_ 18 19 #include <memory> 20 #include <string> 21 #include <utility> 22 23 #include "absl/strings/string_view.h" 24 #include "private_join_and_compute/crypto/elgamal.h" 25 #include "private_join_and_compute/util/status.inc" 26 27 // Defines functions to generate ElGamal public/private keys, and 28 // to encrypt/decrypt messages using those keys. 29 // The ciphertexts thus produced are "commutative" with ec_commutative_cipher. 30 // That is, one can perform an ElGamal encryption, followed by an EC encryption, 31 // followed by decryptions in any order. Note that we only support one level of 32 // ElGamal encryption (and any number of levels of EC encryption.) 33 // 34 // This class is NOT thread-safe. 35 // 36 // Example: To generate a with new public/private ElGamal key pair for the named 37 // curve NID_X9_62_prime256v1. The key can be securely stored and reused. 38 // #include <openssl/obj_mac.h> 39 // std::unique_ptr<CommutativeElGamal> elgamal = 40 // CommutativeElGamal::CreateWithNewKeyPair(NID_X9_62_prime256v1).value(); 41 // StatusOr<stringpair> public_key_bytes = elgamal->GetPublicKeyBytes(); 42 // StatusOr<string> private_key_bytes = elgamal->GetPrivateKeyBytes(); 43 // 44 // Example: To generate a cipher with an existing public/private key pair for 45 // the named curve NID_X9_62_prime256v1. 46 // #include <openssl/obj_mac.h> 47 // StatusOr<std::unique_ptr<CommutativeElGamal>> elgamal = 48 // CommutativeElGamal::CreateFromPublicAndPrivateKeys(NID_X9_62_prime256v1, 49 // public_key_bytes, private_key_bytes); 50 // 51 // Example: To generate a cipher with an existing public key _only_ for 52 // the named curve NID_X9_62_prime256v1. The resulting object can only encrypt, 53 // not decrypt. 54 // #include <openssl/obj_mac.h> 55 // StatusOr<std::unique_ptr<CommutativeElGamal>> elgamal = 56 // CommutativeElGamal::CreateFromPublicKey(NID_X9_62_prime256v1, 57 // public_key_bytes); 58 // 59 // Example: To encrypt a message using a std::unique_ptr<ECCommutativeCipher> 60 // cipher generated as above. Note that the secret must already mapped to the 61 // curve before encrypting it. 62 // #include <openssl/obj_mac.h> 63 // Context context; 64 // EcPointUtil ec_point_util = 65 // ECPointUtil::Create(NID_X9_62_prime256v1).value(); 66 // string point = 67 // ec_point_util->HashToCurve("secret").value(); 68 // StatusOr<stringpair> encrypted_point = elgamal->Encrypt(point); 69 // 70 // Example: To decrypt a message that has been encrypted using the same ElGamal 71 // key. This does not reverse hashing to the curve. 72 // 73 // StatusOr<string> decrypted_point = 74 // cipher->Decrypt(encrypted_point); 75 76 namespace private_join_and_compute { 77 78 class CommutativeElGamal { 79 public: 80 // CommutativeElGamal is neither copyable nor assignable. 81 CommutativeElGamal(const CommutativeElGamal&) = delete; 82 CommutativeElGamal& operator=(const CommutativeElGamal&) = delete; 83 84 ~CommutativeElGamal() = default; 85 86 // Creates a new CommutativeElGamal object by generating a new public/private 87 // key pair. 88 // Returns INVALID_ARGUMENT status instead if the curve_id is not valid 89 // or INTERNAL status when crypto operations are not successful. 90 static StatusOr<std::unique_ptr<CommutativeElGamal>> CreateWithNewKeyPair( 91 int curve_id); 92 93 // Creates a new CommutativeElGamal object using the given public key. 94 // The resulting object will not be able to decrypt ciphertexts, since it 95 // doesn't have the private key. However, it can still create encryptions. 96 // Returns INVALID_ARGUMENT status instead if the public_key is not valid for 97 // the given curve or the curve_id is not valid. 98 // Returns INTERNAL status when crypto operations are not successful. 99 static StatusOr<std::unique_ptr<CommutativeElGamal>> CreateFromPublicKey( 100 int curve_id, 101 const std::pair<std::string, std::string>& public_key_bytes); 102 103 // Creates a new CommutativeElGamal object using the given public and private 104 // keys. The resulting object will be able to both encrypt and decrypt. 105 // Returns INVALID_ARGUMENT status instead if either key is not valid for 106 // the given curve, the keys are inconsistent, or the curve_id is not valid. 107 // Returns INTERNAL status when crypto operations are not successful. 108 static StatusOr<std::unique_ptr<CommutativeElGamal>> 109 CreateFromPublicAndPrivateKeys( 110 int curve_id, const std::pair<std::string, std::string>& public_key_bytes, 111 absl::string_view private_key_bytes); 112 113 // Encrypts the supplied point, and returns the resulting ElGamal ciphertext. 114 // Returns INVALID_ARGUMENT if the input is not on the same curve. 115 // Returns INTERNAL when crypto operations fail. 116 StatusOr<std::pair<std::string, std::string>> Encrypt( 117 absl::string_view plaintext) const; 118 119 // Encrypts the identity element of the EC group (typically the point at 120 // infinity). Note that the ciphertext returned by this method will never 121 // decrypt successfully; however, it can be used in homomorphic operations, 122 // though doing so is equivalent to rerandomizing the ciphertext. 123 StatusOr<std::pair<std::string, std::string>> EncryptIdentityElement() const; 124 125 // Decrypts the supplied ElGamal ciphertext, and returns the underlying 126 // EC point. 127 // Returns INVALID_ARGUMENT if the input ciphertext is not on the same curve, 128 // or if this object does not have the ElGamal private key. 129 // Returns INTERNAL when crypto operations fail. 130 // A special point to note is that the decryption fails if the message 131 // decrypts to the point at infinity. This is because the point at infinity 132 // does not have a valid serialization in OpenSSL. 133 StatusOr<std::string> Decrypt( 134 const std::pair<std::string, std::string>& ciphertext) const; 135 136 // Returns a byte representation of the public key. 137 // Return INTERNAL error if converting the public key to bytes fails. 138 StatusOr<std::pair<std::string, std::string>> GetPublicKeyBytes() const; 139 140 // Returns a byte representation of the private key. 141 // Return INVALID_ARGUMENT if the object doesn't have the private key. 142 StatusOr<std::string> GetPrivateKeyBytes() const; 143 144 private: 145 CommutativeElGamal(std::unique_ptr<Context> ctx, ECGroup group, 146 std::unique_ptr<elgamal::PublicKey> elgamal_public_key, 147 std::unique_ptr<elgamal::PrivateKey> elgamal_private_key); 148 149 CommutativeElGamal(std::unique_ptr<Context> ctx, ECGroup group, 150 std::unique_ptr<elgamal::PublicKey> elgamal_public_key); 151 152 // Context used for storing temporary values to be reused across openssl 153 // function calls for better performance. 154 std::unique_ptr<Context> context_; 155 156 // The EC Group representing the curve definition. 157 const ECGroup group_; 158 159 std::unique_ptr<ElGamalEncrypter> encrypter_; 160 std::unique_ptr<ElGamalDecrypter> decrypter_; 161 }; 162 163 } // namespace private_join_and_compute 164 #endif // PRIVATE_JOIN_AND_COMPUTE_COMMUTATIVE_ELGAMAL_H_ 165