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_EC_COMMUTATIVE_CIPHER_H_ 17 #define PRIVATE_JOIN_AND_COMPUTE_EC_COMMUTATIVE_CIPHER_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/big_num.h" 25 #include "private_join_and_compute/crypto/context.h" 26 #include "private_join_and_compute/crypto/ec_group.h" 27 #include "private_join_and_compute/crypto/ec_point.h" 28 #include "private_join_and_compute/util/status.inc" 29 30 namespace private_join_and_compute { 31 32 // ECCommutativeCipher class with the property that K1(K2(a)) = K2(K1(a)) 33 // where K(a) is encryption with the key K. https://eprint.iacr.org/2008/356.pdf 34 // 35 // This class allows two parties to determine if they share the same value, 36 // without revealing the sensitive value to each other. 37 // 38 // This class also allows homomorphically re-encrypting an ElGamal ciphertext 39 // with an EC cipher key K. If the original ciphertext was an encryption of m, 40 // then the re-encrypted ciphertext is effectively an encryption of K(m). This 41 // re-encryption does not re-randomize the ciphertext, and so is only secure 42 // when the underlying messages "m" are pseudorandom. 43 // 44 // The encryption is performed over an elliptic curve. 45 // 46 // This class is not thread-safe. 47 // 48 // Security: The provided bit security is half the number of bits of the 49 // underlying curve. For example, using curve NID_X9_62_prime256v1 gives 128 50 // bit security. 51 // 52 // Example: To generate a cipher with a new private key for the named curve 53 // NID_X9_62_prime256v1. The key can be securely stored and reused. 54 // #include <openssl/obj_mac.h> 55 // std::unique_ptr<ECCommutativeCipher> cipher = 56 // ECCommutativeCipher::CreateWithNewKey( 57 // NID_X9_62_prime256v1, ECCommutativeCipher::HashType::SSWU_RO); 58 // string key_bytes = cipher->GetPrivateKeyBytes(); 59 // 60 // Example: To generate a cipher with an existing private key for the named 61 // curve NID_X9_62_prime256v1. 62 // #include <openssl/obj_mac.h> 63 // std::unique_ptr<ECCommutativeCipher> cipher = 64 // ECCommutativeCipher::CreateFromKey( 65 // NID_X9_62_prime256v1, key_bytes, 66 // ECCommutativeCipher::HashType::SSWU_RO); 67 // 68 // Example: To encrypt a message using a std::unique_ptr<ECCommutativeCipher> 69 // cipher generated as above. 70 // string encrypted_string = cipher->Encrypt("secret"); 71 // 72 // Example: To re-encrypt a message already encrypted by another party using a 73 // std::unique_ptr<ECCommutativeCipher> cipher generated as above. 74 // ::private_join_and_compute::StatusOr<string> double_encrypted_string = 75 // cipher->ReEncrypt(encrypted_string); 76 // 77 // Example: To decrypt a message that has already been encrypted by the same 78 // party using a std::unique_ptr<ECCommutativeCipher> cipher generated as 79 // above. 80 // ::private_join_and_compute::StatusOr<string> decrypted_string = 81 // cipher->Decrypt(encrypted_string); 82 // 83 // Example: To re-encrypt a message that has already been encrypted using a 84 // std::unique_ptr<CommutativeElGamal> ElGamal key: 85 // ::private_join_and_compute::StatusOr<std::pair<string, string>> 86 // double_encrypted_string = 87 // cipher->ReEncryptElGamalCiphertext(elgamal_ciphertext); 88 89 class ECCommutativeCipher { 90 public: 91 // The hash function used by the ECCommutativeCipher in order to hash strings 92 // to EC curve points. 93 enum HashType { 94 SHA256, 95 SHA384, 96 SHA512, 97 SSWU_RO, 98 }; 99 100 // Check for valid HashType. 101 static bool ValidateHashType(HashType hash_type); 102 103 // Check for valid HashType. 104 static bool ValidateHashType(int hash_type); 105 106 // ECCommutativeCipher is neither copyable nor assignable. 107 ECCommutativeCipher(const ECCommutativeCipher&) = delete; 108 ECCommutativeCipher& operator=(const ECCommutativeCipher&) = delete; 109 110 // Creates an ECCommutativeCipher object with a new random private key. 111 // Use this method when the key is created for the first time or it needs to 112 // be refreshed. 113 // Returns INVALID_ARGUMENT status instead if the curve_id is not valid 114 // or INTERNAL status when crypto operations are not successful. 115 static ::private_join_and_compute::StatusOr< 116 std::unique_ptr<ECCommutativeCipher>> 117 CreateWithNewKey(int curve_id, HashType hash_type); 118 119 // Creates an ECCommutativeCipher object with the given private key. 120 // A new key should be created for each session and all values should be 121 // unique in one session because the encryption is deterministic. 122 // Use this when the key is stored securely to be used at different steps of 123 // the protocol in the same session or by multiple processes. 124 // Returns INVALID_ARGUMENT status instead if the private_key is not valid for 125 // the given curve or the curve_id is not valid. 126 // Returns INTERNAL status when crypto operations are not successful. 127 static ::private_join_and_compute::StatusOr< 128 std::unique_ptr<ECCommutativeCipher>> 129 CreateFromKey(int curve_id, absl::string_view key_bytes, HashType hash_type); 130 131 // Creates an ECCommutativeCipher object with a new private key generated from 132 // the given seed and index. This will deterministically generate a key and 133 // this should not be re-used across multiple sessions. The seed should be a 134 // cryptographically strong random string of at least 16 bytes. 135 // Returns INTERNAL status when crypto operations are not successful. 136 static ::private_join_and_compute::StatusOr< 137 std::unique_ptr<ECCommutativeCipher>> 138 CreateWithKeyFromSeed(int curve_id, absl::string_view seed_bytes, 139 absl::string_view tag_bytes, HashType hash_type); 140 141 // Encrypts a string with the private key to a point on the elliptic curve. 142 // 143 // To encrypt, the string is hashed to a point on the curve which is then 144 // multiplied with the private key. 145 // 146 // The resulting point is returned encoded in compressed form as defined in 147 // ANSI X9.62 ECDSA. 148 // 149 // Returns an INVALID_ARGUMENT error code if an error occurs. 150 // 151 // This method is not threadsafe. 152 ::private_join_and_compute::StatusOr<std::string> Encrypt( 153 absl::string_view plaintext); 154 155 // Encrypts an encoded point with the private key. 156 // 157 // Returns an INVALID_ARGUMENT error code if the input is not a valid encoding 158 // of a point on this curve as defined in ANSI X9.62 ECDSA. 159 // 160 // The result is a point encoded in compressed form. 161 // 162 // This method can also be used to encrypt a value that has already been 163 // hashed to the curve. 164 // 165 // This method is not threadsafe. 166 ::private_join_and_compute::StatusOr<std::string> ReEncrypt( 167 absl::string_view ciphertext); 168 169 // Encrypts an ElGamal ciphertext with the private key. 170 // 171 // Returns an INVALID_ARGUMENT error code if the input is not a valid encoding 172 // of an ElGamal ciphertext on this curve as defined in ANSI X9.62 ECDSA. 173 // 174 // The result is another ElGamal ciphertext, encoded in compressed form. 175 // 176 // This method is not threadsafe. 177 ::private_join_and_compute::StatusOr<std::pair<std::string, std::string>> 178 ReEncryptElGamalCiphertext( 179 const std::pair<std::string, std::string>& elgamal_ciphertext); 180 181 // Decrypts an encoded point with the private key. 182 // 183 // Returns an INVALID_ARGUMENT error code if the input is not a valid encoding 184 // of a point on this curve as defined in ANSI X9.62 ECDSA. 185 // 186 // The result is a point encoded in compressed form. 187 // 188 // If the input point was double-encrypted, once with this key and once with 189 // another key, then the result point is single-encrypted with the other key. 190 // 191 // If the input point was single encrypted with this key, then the result 192 // point is the original, unencrypted point. Note that this will not reverse 193 // hashing to the curve. 194 // 195 // This method is not threadsafe. 196 ::private_join_and_compute::StatusOr<std::string> Decrypt( 197 absl::string_view ciphertext); 198 199 // Hashes a string to a point on the elliptic curve using the 200 // "try-and-increment" method. 201 // See Section 5.2 of https://crypto.stanford.edu/~dabo/papers/bfibe.pdf. 202 // 203 // The resulting point is returned encoded in compressed form as defined in 204 // ANSI X9.62 ECDSA. 205 // 206 // Returns an INVALID_ARGUMENT error code if an error occurs. 207 // 208 // This method is not threadsafe. 209 ::private_join_and_compute::StatusOr<std::string> HashToTheCurve( 210 absl::string_view plaintext); 211 212 // Returns the private key bytes so the key can be stored and reused. 213 std::string GetPrivateKeyBytes() const; 214 215 private: 216 // Creates a new ECCommutativeCipher object with the given private key for 217 // the given EC group. 218 ECCommutativeCipher(std::unique_ptr<Context> context, ECGroup group, 219 BigNum private_key, HashType hash_type); 220 221 // Encrypts a point by multiplying the point with the private key. 222 ::private_join_and_compute::StatusOr<ECPoint> Encrypt(const ECPoint& point); 223 224 // Hashes a string to a point on the elliptic curve. 225 ::private_join_and_compute::StatusOr<ECPoint> HashToTheCurveInternal( 226 absl::string_view plaintext); 227 228 // Context used for storing temporary values to be reused across openssl 229 // function calls for better performance. 230 std::unique_ptr<Context> context_; 231 232 // The EC Group representing the curve definition. 233 const ECGroup group_; 234 235 // The private key used for encryption. 236 const BigNum private_key_; 237 238 // The private key inverse, used for decryption. 239 const BigNum private_key_inverse_; 240 241 // The hash function used by the cipher. 242 const HashType hash_type_; 243 }; 244 245 } // namespace private_join_and_compute 246 247 #endif // PRIVATE_JOIN_AND_COMPUTE_EC_COMMUTATIVE_CIPHER_H_ 248