1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 #include "openssl_ops.h" 26 27 #include <libatap/libatap.h> 28 #include <openssl/aead.h> 29 #include <openssl/curve25519.h> 30 #include <openssl/digest.h> 31 #include <openssl/ec.h> 32 #include <openssl/ecdh.h> 33 #include <openssl/hkdf.h> 34 #include <openssl/obj_mac.h> 35 #include <openssl/rand.h> 36 #include <openssl/sha.h> 37 38 namespace atap { 39 40 OpensslOps::OpensslOps() {} 41 OpensslOps::~OpensslOps() {} 42 43 AtapResult OpensslOps::get_random_bytes(uint8_t* buf, uint32_t buf_size) { 44 if (RAND_bytes(buf, buf_size) != 1) { 45 atap_error("Error getting random bytes"); 46 return ATAP_RESULT_ERROR_IO; 47 } 48 return ATAP_RESULT_OK; 49 } 50 51 AtapResult OpensslOps::ecdh_shared_secret_compute( 52 AtapCurveType curve, 53 const uint8_t other_public_key[ATAP_ECDH_KEY_LEN], 54 uint8_t public_key[ATAP_ECDH_KEY_LEN], 55 uint8_t shared_secret[ATAP_ECDH_SHARED_SECRET_LEN]) { 56 AtapResult result = ATAP_RESULT_OK; 57 EC_GROUP* group = NULL; 58 EC_POINT* other_point = NULL; 59 EC_KEY* pkey = NULL; 60 if (curve == ATAP_CURVE_TYPE_X25519) { 61 uint8_t x25519_priv_key[32]; 62 uint8_t x25519_pub_key[32]; 63 if (test_key_size_ == 32) { 64 atap_memcpy(x25519_priv_key, test_key_, 32); 65 X25519_public_from_private(x25519_pub_key, x25519_priv_key); 66 } else { 67 // Generate an ephemeral key pair. 68 X25519_keypair(x25519_pub_key, x25519_priv_key); 69 } 70 atap_memset(public_key, 0, ATAP_ECDH_KEY_LEN); 71 atap_memcpy(public_key, x25519_pub_key, 32); 72 X25519(shared_secret, x25519_priv_key, other_public_key); 73 } else if (curve == ATAP_CURVE_TYPE_P256) { 74 group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); 75 other_point = EC_POINT_new(group); 76 if (!EC_POINT_oct2point(group, 77 other_point, 78 other_public_key, 79 ATAP_ECDH_KEY_LEN, 80 NULL)) { 81 atap_error("Deserializing other_public_key failed"); 82 result = ATAP_RESULT_ERROR_CRYPTO; 83 goto out; 84 } 85 86 if (test_key_size_ > 0) { 87 const uint8_t* buf_ptr = test_key_; 88 pkey = d2i_ECPrivateKey(nullptr, &buf_ptr, test_key_size_); 89 EC_KEY_set_group(pkey, group); 90 } else { 91 pkey = EC_KEY_new(); 92 if (!pkey) { 93 atap_error("Error allocating EC key"); 94 result = ATAP_RESULT_ERROR_OOM; 95 goto out; 96 } 97 if (1 != EC_KEY_set_group(pkey, group)) { 98 atap_error("EC_KEY_set_group failed"); 99 result = ATAP_RESULT_ERROR_CRYPTO; 100 goto out; 101 } 102 if (1 != EC_KEY_generate_key(pkey)) { 103 atap_error("EC_KEY_generate_key failed"); 104 result = ATAP_RESULT_ERROR_CRYPTO; 105 goto out; 106 } 107 } 108 const EC_POINT* public_point = EC_KEY_get0_public_key(pkey); 109 if (!EC_POINT_point2oct(group, 110 public_point, 111 POINT_CONVERSION_COMPRESSED, 112 public_key, 113 ATAP_ECDH_KEY_LEN, 114 NULL)) { 115 atap_error("Serializing public_key failed"); 116 result = ATAP_RESULT_ERROR_CRYPTO; 117 goto out; 118 } 119 120 if (-1 == ECDH_compute_key(shared_secret, 121 ATAP_ECDH_SHARED_SECRET_LEN, 122 other_point, 123 pkey, 124 NULL)) { 125 atap_error("Error computing shared secret"); 126 result = ATAP_RESULT_ERROR_CRYPTO; 127 goto out; 128 } 129 } else { 130 atap_error("Unsupported ECDH curve"); 131 result = ATAP_RESULT_ERROR_UNSUPPORTED_OPERATION; 132 goto out; 133 } 134 135 out: 136 if (group) EC_GROUP_free(group); 137 if (other_point) EC_POINT_free(other_point); 138 if (pkey) EC_KEY_free(pkey); 139 return result; 140 } 141 142 AtapResult OpensslOps::aes_gcm_128_encrypt( 143 const uint8_t* plaintext, 144 uint32_t len, 145 const uint8_t iv[ATAP_GCM_IV_LEN], 146 const uint8_t key[ATAP_AES_128_KEY_LEN], 147 uint8_t* ciphertext, 148 uint8_t tag[ATAP_GCM_TAG_LEN]) { 149 AtapResult ret = ATAP_RESULT_OK; 150 EVP_AEAD_CTX ctx; 151 if (!EVP_AEAD_CTX_init(&ctx, 152 EVP_aead_aes_128_gcm(), 153 key, 154 ATAP_AES_128_KEY_LEN, 155 ATAP_GCM_TAG_LEN, 156 NULL)) { 157 atap_error("Error initializing EVP_AEAD_CTX"); 158 return ATAP_RESULT_ERROR_CRYPTO; 159 } 160 uint8_t* out_buf = (uint8_t*)atap_malloc(len + ATAP_GCM_TAG_LEN); 161 size_t out_len = len + ATAP_GCM_TAG_LEN; 162 if (!EVP_AEAD_CTX_seal(&ctx, 163 out_buf, 164 &out_len, 165 len + ATAP_GCM_TAG_LEN, 166 iv, 167 ATAP_GCM_IV_LEN, 168 plaintext, 169 len, 170 NULL, 171 0)) { 172 atap_error("Error encrypting"); 173 ret = ATAP_RESULT_ERROR_CRYPTO; 174 goto out; 175 } 176 atap_memcpy(ciphertext, out_buf, len); 177 atap_memcpy(tag, out_buf + len, ATAP_GCM_TAG_LEN); 178 179 out: 180 atap_free(out_buf); 181 EVP_AEAD_CTX_cleanup(&ctx); 182 return ret; 183 } 184 185 AtapResult OpensslOps::aes_gcm_128_decrypt( 186 const uint8_t* ciphertext, 187 uint32_t len, 188 const uint8_t iv[ATAP_GCM_IV_LEN], 189 const uint8_t key[ATAP_AES_128_KEY_LEN], 190 const uint8_t tag[ATAP_GCM_TAG_LEN], 191 uint8_t* plaintext) { 192 AtapResult ret = ATAP_RESULT_OK; 193 EVP_AEAD_CTX ctx; 194 if (!EVP_AEAD_CTX_init(&ctx, 195 EVP_aead_aes_128_gcm(), 196 key, 197 ATAP_AES_128_KEY_LEN, 198 ATAP_GCM_TAG_LEN, 199 NULL)) { 200 atap_error("Error initializing EVP_AEAD_CTX"); 201 return ATAP_RESULT_ERROR_CRYPTO; 202 } 203 uint8_t* in_buf = (uint8_t*)atap_malloc(len + ATAP_GCM_TAG_LEN); 204 atap_memcpy(in_buf, ciphertext, len); 205 atap_memcpy(in_buf + len, tag, ATAP_GCM_TAG_LEN); 206 size_t out_len = len; 207 if (!EVP_AEAD_CTX_open(&ctx, 208 plaintext, 209 &out_len, 210 len, 211 iv, 212 ATAP_GCM_IV_LEN, 213 in_buf, 214 len + ATAP_GCM_TAG_LEN, 215 NULL, 216 0)) { 217 atap_error("Error decrypting"); 218 ret = ATAP_RESULT_ERROR_CRYPTO; 219 goto out; 220 } 221 out: 222 atap_free(in_buf); 223 EVP_AEAD_CTX_cleanup(&ctx); 224 return ret; 225 } 226 227 AtapResult OpensslOps::sha256(const uint8_t* plaintext, 228 uint32_t plaintext_len, 229 uint8_t hash[ATAP_SHA256_DIGEST_LEN]) { 230 SHA256(plaintext, plaintext_len, hash); 231 return ATAP_RESULT_OK; 232 } 233 234 AtapResult OpensslOps::hkdf_sha256(const uint8_t* salt, 235 uint32_t salt_len, 236 const uint8_t* ikm, 237 uint32_t ikm_len, 238 const uint8_t* info, 239 uint32_t info_len, 240 uint8_t* okm, 241 int32_t okm_len) { 242 if (!HKDF(okm, 243 okm_len, 244 EVP_sha256(), 245 ikm, 246 ikm_len, 247 salt, 248 salt_len, 249 info, 250 info_len)) { 251 atap_error("Error in key derivation"); 252 return ATAP_RESULT_ERROR_CRYPTO; 253 } 254 return ATAP_RESULT_OK; 255 } 256 257 void OpensslOps::SetEcdhKeyForTesting(const void* key_data, 258 size_t size_in_bytes) { 259 if (size_in_bytes > sizeof(test_key_)) { 260 size_in_bytes = sizeof(test_key_); 261 } 262 if (size_in_bytes > 0) { 263 atap_memcpy(test_key_, key_data, size_in_bytes); 264 } 265 test_key_size_ = size_in_bytes; 266 } 267 268 } // namespace atap 269