diff options
Diffstat (limited to 'private_join_and_compute/crypto/ec_commutative_cipher.h')
-rw-r--r-- | private_join_and_compute/crypto/ec_commutative_cipher.h | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/private_join_and_compute/crypto/ec_commutative_cipher.h b/private_join_and_compute/crypto/ec_commutative_cipher.h new file mode 100644 index 0000000..7142784 --- /dev/null +++ b/private_join_and_compute/crypto/ec_commutative_cipher.h @@ -0,0 +1,232 @@ +/* + * Copyright 2019 Google Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef EC_COMMUTATIVE_CIPHER_H_ +#define EC_COMMUTATIVE_CIPHER_H_ + +#include <memory> +#include <string> + +#include "absl/base/port.h" +#include "absl/strings/string_view.h" +#include "private_join_and_compute/crypto/big_num.h" +#include "private_join_and_compute/crypto/context.h" +#include "private_join_and_compute/crypto/ec_group.h" +#include "private_join_and_compute/crypto/ec_point.h" +#include "private_join_and_compute/util/status.inc" + +namespace private_join_and_compute { + +// ECCommutativeCipher class with the property that K1(K2(a)) = K2(K1(a)) +// where K(a) is encryption with the key K. https://eprint.iacr.org/2008/356.pdf +// +// This class allows two parties to determine if they share the same value, +// without revealing the sensitive value to each other. +// +// This class also allows homomorphically re-encrypting an ElGamal ciphertext +// with an EC cipher key K. If the original ciphertext was an encryption of m, +// then the re-encrypted ciphertext is effectively an encryption of K(m). This +// re-encryption does not re-randomize the ciphertext, and so is only secure +// when the underlying messages "m" are pseudorandom. +// +// The encryption is performed over an elliptic curve. +// +// This class is not thread-safe. +// +// Security: The provided bit security is half the number of bits of the +// underlying curve. For example, using curve NID_X9_62_prime256v1 gives 128 +// bit security. +// +// Example: To generate a cipher with a new private key for the named curve +// NID_X9_62_prime256v1. The key can be securely stored and reused. +// #include <openssl/obj_mac.h> +// std::unique_ptr<ECCommutativeCipher> cipher = +// ECCommutativeCipher::CreateWithNewKey( +// NID_X9_62_prime256v1, ECCommutativeCipher::HashType::SHA256); +// string key_bytes = cipher->GetPrivateKeyBytes(); +// +// Example: To generate a cipher with an existing private key for the named +// curve NID_X9_62_prime256v1. +// #include <openssl/obj_mac.h> +// std::unique_ptr<ECCommutativeCipher> cipher = +// ECCommutativeCipher::CreateFromKey( +// NID_X9_62_prime256v1, key_bytes, +// ECCommutativeCipher::HashType::SHA256); +// +// Example: To encrypt a message using a std::unique_ptr<ECCommutativeCipher> +// cipher generated as above. +// string encrypted_string = cipher->Encrypt("secret"); +// +// Example: To re-encrypt a message already encrypted by another party using a +// std::unique_ptr<ECCommutativeCipher> cipher generated as above. +// ::private_join_and_compute::StatusOr<string> double_encrypted_string = +// cipher->ReEncrypt(encrypted_string); +// +// Example: To decrypt a message that has already been encrypted by the same +// party using a std::unique_ptr<ECCommutativeCipher> cipher generated as +// above. +// ::private_join_and_compute::StatusOr<string> decrypted_string = +// cipher->Decrypt(encrypted_string); +// +// Example: To re-encrypt a message that has already been encrypted using a +// std::unique_ptr<CommutativeElGamal> ElGamal key: +// ::private_join_and_compute::StatusOr<std::pair<string, string>> +// double_encrypted_string = +// cipher->ReEncryptElGamalCiphertext(elgamal_ciphertext); + +class ECCommutativeCipher { + public: + // The hash function used by the ECCommutativeCipher in order to hash strings + // to EC curve points. The suggested default is the SHA256 option. + enum HashType { + SHA256, + SHA512, + }; + + // Check for valid HashType. + static bool ValidateHashType(HashType hash_type); + + // ECCommutativeCipher is neither copyable nor assignable. + ECCommutativeCipher(const ECCommutativeCipher&) = delete; + ECCommutativeCipher& operator=(const ECCommutativeCipher&) = delete; + + // Creates an ECCommutativeCipher object with a new random private key. + // Use this method when the key is created for the first time or it needs to + // be refreshed. + // Returns INVALID_ARGUMENT status instead if the curve_id is not valid + // or INTERNAL status when crypto operations are not successful. + static ::private_join_and_compute::StatusOr< + std::unique_ptr<ECCommutativeCipher>> + CreateWithNewKey(int curve_id, HashType hash_type); + + // Creates an ECCommutativeCipher object with the given private key. + // A new key should be created for each session and all values should be + // unique in one session because the encryption is deterministic. + // Use this when the key is stored securely to be used at different steps of + // the protocol in the same session or by multiple processes. + // Returns INVALID_ARGUMENT status instead if the private_key is not valid for + // the given curve or the curve_id is not valid. + // Returns INTERNAL status when crypto operations are not successful. + static ::private_join_and_compute::StatusOr< + std::unique_ptr<ECCommutativeCipher>> + CreateFromKey(int curve_id, absl::string_view key_bytes, HashType hash_type); + + // Encrypts a string with the private key to a point on the elliptic curve. + // + // To encrypt, the string is hashed to a point on the curve which is then + // multiplied with the private key. + // + // The resulting point is returned encoded in compressed form as defined in + // ANSI X9.62 ECDSA. + // + // Returns an INVALID_ARGUMENT error code if an error occurs. + // + // This method is not threadsafe. + ::private_join_and_compute::StatusOr<std::string> Encrypt( + absl::string_view plaintext); + + // Encrypts an encoded point with the private key. + // + // Returns an INVALID_ARGUMENT error code if the input is not a valid encoding + // of a point on this curve as defined in ANSI X9.62 ECDSA. + // + // The result is a point encoded in compressed form. + // + // This method can also be used to encrypt a value that has already been + // hashed to the curve. + // + // This method is not threadsafe. + ::private_join_and_compute::StatusOr<std::string> ReEncrypt( + absl::string_view ciphertext); + + // Encrypts an ElGamal ciphertext with the private key. + // + // Returns an INVALID_ARGUMENT error code if the input is not a valid encoding + // of an ElGamal ciphertext on this curve as defined in ANSI X9.62 ECDSA. + // + // The result is another ElGamal ciphertext, encoded in compressed form. + // + // This method is not threadsafe. + ::private_join_and_compute::StatusOr<std::pair<std::string, std::string>> + ReEncryptElGamalCiphertext( + const std::pair<std::string, std::string>& elgamal_ciphertext); + + // Decrypts an encoded point with the private key. + // + // Returns an INVALID_ARGUMENT error code if the input is not a valid encoding + // of a point on this curve as defined in ANSI X9.62 ECDSA. + // + // The result is a point encoded in compressed form. + // + // If the input point was double-encrypted, once with this key and once with + // another key, then the result point is single-encrypted with the other key. + // + // If the input point was single encrypted with this key, then the result + // point is the original, unencrypted point. Note that this will not reverse + // hashing to the curve. + // + // This method is not threadsafe. + ::private_join_and_compute::StatusOr<std::string> Decrypt( + absl::string_view ciphertext); + + // Hashes a string to a point on the elliptic curve using the + // "try-and-increment" method. + // See Section 5.2 of https://crypto.stanford.edu/~dabo/papers/bfibe.pdf. + // + // The resulting point is returned encoded in compressed form as defined in + // ANSI X9.62 ECDSA. + // + // Returns an INVALID_ARGUMENT error code if an error occurs. + // + // This method is not threadsafe. + ::private_join_and_compute::StatusOr<std::string> HashToTheCurve( + absl::string_view plaintext); + + // Returns the private key bytes so the key can be stored and reused. + std::string GetPrivateKeyBytes() const; + + private: + // Creates a new ECCommutativeCipher object with the given private key for + // the given EC group. + ECCommutativeCipher(std::unique_ptr<Context> context, ECGroup group, + BigNum private_key, HashType hash_type); + + // Encrypts a point by multiplying the point with the private key. + ::private_join_and_compute::StatusOr<ECPoint> Encrypt(const ECPoint& point); + + // Hashes a string to a point on the elliptic curve. + ::private_join_and_compute::StatusOr<ECPoint> HashToTheCurveInternal( + absl::string_view plaintext); + + // Context used for storing temporary values to be reused across openssl + // function calls for better performance. + std::unique_ptr<Context> context_; + + // The EC Group representing the curve definition. + const ECGroup group_; + + // The private key used for encryption. + const BigNum private_key_; + + // The private key inverse, used for decryption. + const BigNum private_key_inverse_; + + // The hash function used by the cipher. + const HashType hash_type_; +}; + +} // namespace private_join_and_compute + +#endif // EC_COMMUTATIVE_CIPHER_H_ |