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 #include "private_join_and_compute/crypto/commutative_elgamal.h"
17
18 #include <memory>
19 #include <string>
20 #include <utility>
21
22 #include "absl/strings/string_view.h"
23 #include "private_join_and_compute/crypto/big_num.h"
24 #include "private_join_and_compute/crypto/ec_group.h"
25 #include "private_join_and_compute/crypto/ec_point.h"
26 #include "private_join_and_compute/crypto/elgamal.h"
27 #include "private_join_and_compute/util/status.inc"
28
29 namespace private_join_and_compute {
30
CommutativeElGamal(std::unique_ptr<Context> ctx,ECGroup group,std::unique_ptr<elgamal::PublicKey> elgamal_public_key,std::unique_ptr<elgamal::PrivateKey> elgamal_private_key)31 CommutativeElGamal::CommutativeElGamal(
32 std::unique_ptr<Context> ctx, ECGroup group,
33 std::unique_ptr<elgamal::PublicKey> elgamal_public_key,
34 std::unique_ptr<elgamal::PrivateKey> elgamal_private_key)
35 : context_(std::move(ctx)),
36 group_(std::move(group)),
37 encrypter_(new ElGamalEncrypter(&group_, std::move(elgamal_public_key))),
38 decrypter_(new ElGamalDecrypter(std::move(elgamal_private_key))) {}
39
CommutativeElGamal(std::unique_ptr<Context> ctx,ECGroup group,std::unique_ptr<elgamal::PublicKey> elgamal_public_key)40 CommutativeElGamal::CommutativeElGamal(
41 std::unique_ptr<Context> ctx, ECGroup group,
42 std::unique_ptr<elgamal::PublicKey> elgamal_public_key)
43 : context_(std::move(ctx)),
44 group_(std::move(group)),
45 encrypter_(new ElGamalEncrypter(&group_, std::move(elgamal_public_key))),
46 decrypter_(nullptr) {}
47
48 StatusOr<std::unique_ptr<CommutativeElGamal>>
CreateWithNewKeyPair(int curve_id)49 CommutativeElGamal::CreateWithNewKeyPair(int curve_id) {
50 std::unique_ptr<Context> context(new Context);
51 ASSIGN_OR_RETURN(ECGroup group, ECGroup::Create(curve_id, context.get()));
52 ASSIGN_OR_RETURN(auto key_pair, elgamal::GenerateKeyPair(group));
53 std::unique_ptr<CommutativeElGamal> result(new CommutativeElGamal(
54 std::move(context), std::move(group), std::move(key_pair.first),
55 std::move(key_pair.second)));
56 return {std::move(result)};
57 }
58
59 StatusOr<std::unique_ptr<CommutativeElGamal>>
CreateFromPublicKey(int curve_id,const std::pair<std::string,std::string> & public_key_bytes)60 CommutativeElGamal::CreateFromPublicKey(
61 int curve_id, const std::pair<std::string, std::string>& public_key_bytes) {
62 std::unique_ptr<Context> context(new Context);
63 ASSIGN_OR_RETURN(ECGroup group, ECGroup::Create(curve_id, context.get()));
64
65 ASSIGN_OR_RETURN(ECPoint g, group.CreateECPoint(public_key_bytes.first));
66 ASSIGN_OR_RETURN(ECPoint y, group.CreateECPoint(public_key_bytes.second));
67
68 std::unique_ptr<elgamal::PublicKey> public_key(
69 new elgamal::PublicKey({std::move(g), std::move(y)}));
70 std::unique_ptr<CommutativeElGamal> result(new CommutativeElGamal(
71 std::move(context), std::move(group), std::move(public_key)));
72 return {std::move(result)};
73 }
74
75 StatusOr<std::unique_ptr<CommutativeElGamal>>
CreateFromPublicAndPrivateKeys(int curve_id,const std::pair<std::string,std::string> & public_key_bytes,absl::string_view private_key_bytes)76 CommutativeElGamal::CreateFromPublicAndPrivateKeys(
77 int curve_id, const std::pair<std::string, std::string>& public_key_bytes,
78 absl::string_view private_key_bytes) {
79 std::unique_ptr<Context> context(new Context);
80 ASSIGN_OR_RETURN(ECGroup group, ECGroup::Create(curve_id, context.get()));
81
82 ASSIGN_OR_RETURN(ECPoint g, group.CreateECPoint(public_key_bytes.first));
83 ASSIGN_OR_RETURN(ECPoint y, group.CreateECPoint(public_key_bytes.second));
84
85 BigNum x = context->CreateBigNum(private_key_bytes);
86
87 ASSIGN_OR_RETURN(ECPoint expected_y, g.Mul(x));
88
89 if (y != expected_y) {
90 return InvalidArgumentError(
91 "CommutativeElGamal::CreateFromPublicAndPrivateKeys : Public key is "
92 "not consistent with private key");
93 }
94
95 std::unique_ptr<elgamal::PublicKey> public_key(
96 new elgamal::PublicKey({std::move(g), std::move(y)}));
97 std::unique_ptr<elgamal::PrivateKey> private_key(
98 new elgamal::PrivateKey({std::move(x)}));
99 std::unique_ptr<CommutativeElGamal> result(
100 new CommutativeElGamal(std::move(context), std::move(group),
101 std::move(public_key), std::move(private_key)));
102 return {std::move(result)};
103 }
104
Encrypt(absl::string_view plaintext) const105 StatusOr<std::pair<std::string, std::string>> CommutativeElGamal::Encrypt(
106 absl::string_view plaintext) const {
107 ASSIGN_OR_RETURN(ECPoint plaintext_point, group_.CreateECPoint(plaintext));
108
109 ASSIGN_OR_RETURN(elgamal::Ciphertext ciphertext,
110 encrypter_->Encrypt(plaintext_point));
111
112 ASSIGN_OR_RETURN(std::string u_string, ciphertext.u.ToBytesCompressed());
113 ASSIGN_OR_RETURN(std::string e_string, ciphertext.e.ToBytesCompressed());
114
115 return {std::make_pair(std::move(u_string), std::move(e_string))};
116 }
117
118 StatusOr<std::pair<std::string, std::string>>
EncryptIdentityElement() const119 CommutativeElGamal::EncryptIdentityElement() const {
120 ASSIGN_OR_RETURN(ECPoint plaintext_point, group_.GetPointAtInfinity());
121
122 ASSIGN_OR_RETURN(elgamal::Ciphertext ciphertext,
123 encrypter_->Encrypt(plaintext_point));
124
125 ASSIGN_OR_RETURN(std::string u_string, ciphertext.u.ToBytesCompressed());
126 ASSIGN_OR_RETURN(std::string e_string, ciphertext.e.ToBytesCompressed());
127
128 return {std::make_pair(std::move(u_string), std::move(e_string))};
129 }
130
Decrypt(const std::pair<std::string,std::string> & ciphertext) const131 StatusOr<std::string> CommutativeElGamal::Decrypt(
132 const std::pair<std::string, std::string>& ciphertext) const {
133 if (nullptr == decrypter_) {
134 return InvalidArgumentError(
135 "CommutativeElGamal::Decrypt: cannot decrypt without the private key.");
136 }
137
138 ASSIGN_OR_RETURN(ECPoint u_point, group_.CreateECPoint(ciphertext.first));
139 ASSIGN_OR_RETURN(ECPoint e_point, group_.CreateECPoint(ciphertext.second));
140 elgamal::Ciphertext decoded_ciphertext(
141 {std::move(u_point), std::move(e_point)});
142
143 ASSIGN_OR_RETURN(ECPoint plaintext_point,
144 decrypter_->Decrypt(decoded_ciphertext));
145
146 ASSIGN_OR_RETURN(std::string plaintext, plaintext_point.ToBytesCompressed());
147
148 return {std::move(plaintext)};
149 }
150
151 StatusOr<std::pair<std::string, std::string>>
GetPublicKeyBytes() const152 CommutativeElGamal::GetPublicKeyBytes() const {
153 const elgamal::PublicKey* public_key = encrypter_->getPublicKey();
154 ASSIGN_OR_RETURN(std::string g_string, public_key->g.ToBytesCompressed());
155 ASSIGN_OR_RETURN(std::string y_string, public_key->y.ToBytesCompressed());
156
157 return {std::make_pair(std::move(g_string), std::move(y_string))};
158 }
159
GetPrivateKeyBytes() const160 StatusOr<std::string> CommutativeElGamal::GetPrivateKeyBytes() const {
161 if (nullptr == decrypter_) {
162 return InvalidArgumentError(
163 "CommutativeElGamal::GetPrivateKeyBytes: private key is not known.");
164 }
165 return {decrypter_->getPrivateKey()->x.ToBytes()};
166 }
167
168 } // namespace private_join_and_compute
169