1 /*
2 * Copyright 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ecies_kem.h"
18
19 #include "nist_curve_key_exchange.h"
20 #include "openssl_err.h"
21
22 namespace keymaster {
23
EciesKem(const AuthorizationSet & kem_description,keymaster_error_t * error)24 EciesKem::EciesKem(const AuthorizationSet& kem_description, keymaster_error_t* error) {
25 AuthorizationSet authorizations(kem_description);
26
27 if (!authorizations.GetTagValue(TAG_EC_CURVE, &curve_)) {
28 LOG_E("%s", "EciesKem: no curve specified");
29 *error = KM_ERROR_INVALID_ARGUMENT;
30 return;
31 }
32
33 switch (curve_) {
34 case KM_EC_CURVE_P_224:
35 case KM_EC_CURVE_P_256:
36 case KM_EC_CURVE_P_384:
37 case KM_EC_CURVE_P_521:
38 break;
39 default:
40 LOG_E("EciesKem: curve %d is unsupported", curve_);
41 *error = KM_ERROR_UNSUPPORTED_EC_CURVE;
42 return;
43 }
44
45 keymaster_kdf_t kdf;
46 if (!authorizations.GetTagValue(TAG_KDF, &kdf)) {
47 LOG_E("EciesKem: No KDF specified", 0);
48 *error = KM_ERROR_UNSUPPORTED_KDF;
49 return;
50 }
51 switch (kdf) {
52 case KM_KDF_RFC5869_SHA256:
53 kdf_.reset(new Rfc5869Sha256Kdf());
54 break;
55 default:
56 LOG_E("Kdf %d is unsupported", kdf);
57 *error = KM_ERROR_UNSUPPORTED_KDF;
58 return;
59 }
60 if (!kdf_.get()) {
61 *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
62 return;
63 }
64
65 if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_bytes_to_generate_)) {
66 LOG_E("%s", "EciesKem: no key length specified");
67 *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
68 return;
69 }
70
71 single_hash_mode_ = authorizations.GetTagValue(TAG_ECIES_SINGLE_HASH_MODE);
72 *error = KM_ERROR_OK;
73 }
74
Encrypt(const Buffer & peer_public_value,Buffer * output_clear_key,Buffer * output_encrypted_key)75 bool EciesKem::Encrypt(const Buffer& peer_public_value, Buffer* output_clear_key,
76 Buffer* output_encrypted_key) {
77 return Encrypt(peer_public_value.peek_read(), peer_public_value.available_read(),
78 output_clear_key, output_encrypted_key);
79 }
80
81 // http://www.shoup.net/iso/std6.pdf, section 10.2.3.
Encrypt(const uint8_t * peer_public_value,size_t peer_public_value_len,Buffer * output_clear_key,Buffer * output_encrypted_key)82 bool EciesKem::Encrypt(const uint8_t* peer_public_value, size_t peer_public_value_len,
83 Buffer* output_clear_key, Buffer* output_encrypted_key) {
84
85 key_exchange_.reset(NistCurveKeyExchange::GenerateKeyExchange(curve_));
86 if (!key_exchange_.get()) {
87 return false;
88 }
89
90 Buffer shared_secret;
91 if (!key_exchange_->CalculateSharedKey(peer_public_value, peer_public_value_len,
92 &shared_secret)) {
93 LOG_E("EciesKem: ECDH failed, can't obtain shared secret", 0);
94 return false;
95 }
96 if (!key_exchange_->public_value(output_encrypted_key)) {
97 LOG_E("EciesKem: Can't obtain public value", 0);
98 return false;
99 }
100
101 Buffer z;
102 if (single_hash_mode_) {
103 // z is empty.
104 } else {
105 // z = C0
106 z.Reinitialize(output_encrypted_key->peek_read(), output_encrypted_key->available_read());
107 }
108
109 Buffer actual_secret(z.available_read() + shared_secret.available_read());
110 actual_secret.write(z.peek_read(), z.available_read());
111 actual_secret.write(shared_secret.peek_read(), shared_secret.available_read());
112
113 if (!kdf_->Init(actual_secret.peek_read(), actual_secret.available_read(), nullptr /* salt */,
114 0 /* salt_len */)) {
115 LOG_E("EciesKem: KDF failed, can't derived keys", 0);
116 return false;
117 }
118 output_clear_key->Reinitialize(key_bytes_to_generate_);
119 if (!kdf_->GenerateKey(nullptr /* info */, 0 /* info length */, output_clear_key->peek_write(),
120 key_bytes_to_generate_)) {
121 LOG_E("EciesKem: KDF failed, can't derived keys", 0);
122 return false;
123 }
124 output_clear_key->advance_write(key_bytes_to_generate_);
125
126 return true;
127 }
128
Decrypt(EC_KEY * private_key,const Buffer & encrypted_key,Buffer * output_key)129 bool EciesKem::Decrypt(EC_KEY* private_key, const Buffer& encrypted_key, Buffer* output_key) {
130 return Decrypt(private_key, encrypted_key.peek_read(), encrypted_key.available_read(),
131 output_key);
132 }
133
134 // http://www.shoup.net/iso/std6.pdf, section 10.2.4.
Decrypt(EC_KEY * private_key,const uint8_t * encrypted_key,size_t encrypted_key_len,Buffer * output_key)135 bool EciesKem::Decrypt(EC_KEY* private_key, const uint8_t* encrypted_key, size_t encrypted_key_len,
136 Buffer* output_key) {
137
138 keymaster_error_t error;
139 key_exchange_.reset(new NistCurveKeyExchange(private_key, &error));
140 if (!key_exchange_.get() || error != KM_ERROR_OK) {
141 return false;
142 }
143
144 Buffer shared_secret;
145 if (!key_exchange_->CalculateSharedKey(encrypted_key, encrypted_key_len, &shared_secret)) {
146 LOG_E("EciesKem: ECDH failed, can't obtain shared secret", 0);
147 return false;
148 }
149
150 Buffer public_value;
151 if (!key_exchange_->public_value(&public_value)) {
152 LOG_E("%s", "EciesKem: Can't obtain public value");
153 return false;
154 }
155
156 Buffer z;
157 if (single_hash_mode_) {
158 // z is empty.
159 } else {
160 // z = C0
161 z.Reinitialize(public_value.peek_read(), public_value.available_read());
162 }
163
164 Buffer actual_secret(z.available_read() + shared_secret.available_read());
165 actual_secret.write(z.peek_read(), z.available_read());
166 actual_secret.write(shared_secret.peek_read(), shared_secret.available_read());
167
168 if (!kdf_->Init(actual_secret.peek_read(), actual_secret.available_read(), nullptr /* salt */,
169 0 /* salt_len */)) {
170 LOG_E("%s", "EciesKem: KDF failed, can't derived keys");
171 return false;
172 }
173
174 output_key->Reinitialize(key_bytes_to_generate_);
175 if (!kdf_->GenerateKey(nullptr /* info */, 0 /* info_len */, output_key->peek_write(),
176 key_bytes_to_generate_)) {
177 LOG_E("%s", "EciesKem: KDF failed, can't derived keys");
178 return false;
179 }
180 output_key->advance_write(key_bytes_to_generate_);
181
182 return true;
183 }
184
185 } // namespace keymaster
186