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 <keymaster/km_openssl/ecies_kem.h> 18 19 #include <keymaster/km_openssl/nist_curve_key_exchange.h> 20 #include <keymaster/km_openssl/openssl_err.h> 21 22 namespace keymaster { 23 24 EciesKem::EciesKem(const AuthorizationSet& kem_description, keymaster_error_t* error) { 25 const 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(std::nothrow) 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 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. 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 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. 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(std::nothrow) 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