Home | History | Annotate | Download | only in ops
      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