123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- /*
- * Copyright (C) 2014-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "at_aes_crypt.h"
- #include "at_log.h"
- /*
- * The OpenSSL 1.1.0 API requires we allocate these dynamically. Cache them
- * globally to avoid alocator thrash and the potential for another dynamic
- * failure.
- */
- static EVP_CIPHER_CTX *cipher_ctx;
- static HMAC_CTX *hmac_ctx;
- static void crypt_init(void) {
- cipher_ctx = EVP_CIPHER_CTX_new();
- assert(cipher_ctx);
- }
- static void hmac_init(void) {
- hmac_ctx = HMAC_CTX_new();
- assert(hmac_ctx);
- }
- static void crypt_shutdown(void) {
- EVP_CIPHER_CTX_free(cipher_ctx);
- cipher_ctx = NULL;
- }
- static void hmac_shutdown(void) {
- HMAC_CTX_free(hmac_ctx);
- hmac_ctx = NULL;
- }
- /**
- * crypt - Helper function for encrypt and decrypt.
- * @key: Key object.
- * @data_in_out: Data to encrypt or decrypt.
- * @data_size: Number of bytes in @data_in_out.
- * @iv: Initialization vector to use for Cipher Block Chaining.
- * @padding: Have padding or not.
- * @encrypt: %true to select encrypt, %false to select decrypt.
- *
- * Return: 0 on success, -1 if an error was detected.
- */
- static int crypt(const struct key *key, at_crypt_data *in, at_crypt_data *out,
- const struct iv *iv, bool padding, bool encrypt) {
- int evp_ret;
- const EVP_CIPHER *cipher;
- int out_data_size;
- size_t key_len;
- /*
- * Make sure iv is large enough. Current implementation allows static
- * check.
- * TODO: Switch to runtime check for selcted cipher if EVP_MAX_IV_LENGTH
- * changes to cover larger ivs used by other cipers.
- */
- STATIC_ASSERT(sizeof(*iv) >= EVP_MAX_IV_LENGTH);
- cipher = EVP_aes_128_cbc();
- key_len = EVP_CIPHER_key_length(cipher);
- if (key_len > sizeof(*key)) {
- ATLOGE("key too small for selected cipher, %zd < %zd\n", sizeof(*key),
- key_len);
- evp_ret = 0;
- goto err;
- }
- assert(cipher_ctx);
- EVP_CIPHER_CTX_reset(cipher_ctx);
- evp_ret =
- EVP_CipherInit_ex(cipher_ctx, cipher, NULL, key->byte, iv->byte, encrypt);
- if (!evp_ret) {
- ATLOGE("EVP_CipherInit_ex failed\n");
- goto err;
- }
- evp_ret = EVP_CIPHER_CTX_set_padding(cipher_ctx, padding);
- if (!evp_ret) {
- ATLOGE("EVP_CIPHER_CTX_set_padding failed\n");
- goto err;
- }
- evp_ret =
- EVP_CipherUpdate(cipher_ctx, out->data, &out->size, in->data, in->size);
- if (!evp_ret) {
- ATLOGE("EVP_CipherUpdate failed\n");
- goto err;
- }
- out_data_size = out->size;
- evp_ret =
- EVP_CipherFinal_ex(cipher_ctx, out->data + out_data_size, &out_data_size);
- if (!evp_ret) {
- ATLOGE("EVP_CipherFinal_ex failed\n");
- goto err;
- }
- out->size += out_data_size;
- err:
- return evp_ret ? 0 : -1;
- }
- /**
- * calculate_mac - Calulate keyed-hash message authentication code (HMAC SHA256)
- * @key: Key object.
- * @mac: Mac object to return calulated mac in.
- * @data: Data to calculate mac for.
- * @data_size: Number of bytes in @data.
- *
- * Return: 0 on success, -1 if an error was detected.
- */
- static int calculate_mac(const struct key *key, struct mac *mac,
- const void *data, size_t data_size) {
- int hmac_ret;
- unsigned int md_len;
- unsigned char mac_buf[EVP_MAX_MD_SIZE];
- assert(hmac_ctx);
- HMAC_CTX_reset(hmac_ctx);
- hmac_ret = HMAC_Init_ex(hmac_ctx, key, sizeof(*key), EVP_sha256(), NULL);
- if (!hmac_ret) {
- fprintf(stderr, "HMAC_Init_ex failed\n");
- goto err;
- }
- hmac_ret = HMAC_Update(hmac_ctx, data, data_size);
- if (!hmac_ret) {
- fprintf(stderr, "HMAC_Update failed\n");
- goto err;
- }
- hmac_ret = HMAC_Final(hmac_ctx, mac_buf, &md_len);
- if (!hmac_ret) {
- fprintf(stderr, "HMAC_Final failed\n");
- goto err;
- }
- if (md_len < sizeof(*mac)) {
- fprintf(stderr, "bad md_len %d < %zd\n", md_len, sizeof(*mac));
- hmac_ret = 0;
- goto err;
- }
- memcpy(mac, mac_buf, sizeof(*mac));
- err:
- return hmac_ret ? 0 : -1;
- }
- /**
- * at_aes_hmac_encrypt - Encrypt data using AES-128-CBC and HMAC.
- * @key: Key object.
- * @data_in: Data to encrypt.
- * @data_out: Data to encrypt for.
- * @iv_in: Initialization vector to use for Cipher Block Chaining.
- *
- * Return: 0 on success, -1 if an error was detected.
- */
- int at_aes_hmac_encrypt(const struct key *key, at_crypt_data *data_in,
- at_crypt_data *data_out, const struct iv *iv_in) {
- if (key == NULL || data_in == NULL || data_out == NULL || iv_in == NULL) {
- ATLOGE("encrypt param error.\n");
- goto param_err;
- }
- at_crypt_data crypt_out;
- crypt_out.size = data_in->size / 16 * 16 +
- (1 + (data_in->size % 16 & INT_MAX) ? 1 : 0) * 16;
- crypt_out.data = (uint8_t *)malloc(sizeof(uint8_t) * crypt_out.size + 1);
- if (crypt_out.data == NULL) {
- ATLOGE("malloc error.\n");
- goto malloc_err;
- }
- memset(crypt_out.data, 0, crypt_out.size + 1);
- data_out->size = crypt_out.size + AT_HMAC_SIZE;
- data_out->data = (uint8_t *)malloc(sizeof(uint8_t) * data_out->size + 1);
- if (data_out->data == NULL) {
- ATLOGE("malloc error.\n");
- goto malloc_err;
- }
- memset(data_out->data, 0, data_out->size + 1);
- crypt_init();
- int rc = crypt(key, data_in, &crypt_out, iv_in, true, true);
- if (rc < 0) {
- ATLOGE("crypt faild.\n");
- goto crypt_err;
- }
- hmac_init();
- struct mac mac;
- rc = calculate_mac(key, &mac, crypt_out.data, crypt_out.size);
- if (rc < 0) {
- ATLOGE("calculate_mac faild.\n");
- goto hash_err;
- }
- memcpy(data_out->data, mac.byte, AT_HMAC_SIZE);
- memcpy(data_out->data + AT_HMAC_SIZE, crypt_out.data, crypt_out.size);
- data_out->size = crypt_out.size + AT_HMAC_SIZE;
- hmac_shutdown();
- crypt_shutdown();
- if (crypt_out.data != NULL) {
- free(crypt_out.data);
- }
- return 0;
- hash_err:
- hmac_shutdown();
- crypt_err:
- crypt_shutdown();
- if (data_out->data != NULL) {
- free(data_out->data);
- }
- malloc_err:
- if (crypt_out.data != NULL) {
- free(crypt_out.data);
- }
- param_err:
- return -1;
- }
- /**
- * at_aes_hmac_decrypt - Decrypt data using AES-128-CBC and verify HMAC.
- * @key: Key object.
- * @data_in: Data to decrypt.
- * @data_out: Data to decrypt for.
- * @iv_in: Initialization vector to use for Cipher Block Chaining.
- *
- * Return: 0 on success, -1 if an error was detected.
- */
- int at_aes_hmac_decrypt(const struct key *key, at_crypt_data *data_in,
- at_crypt_data *data_out, const struct iv *iv_in) {
- if (key == NULL || data_in == NULL || data_out == NULL || iv_in == NULL) {
- ATLOGE("encrypt param error.\n");
- goto param_err;
- }
- if((data_in->size/16 < 2) || (data_in->size%16 != 0) || (data_in->size == 0)) {
- ATLOGE("data_in size error.\n");
- goto param_err;
- }
- hmac_init();
- struct mac mac;
- int rc = calculate_mac(key, &mac, data_in->data + AT_HMAC_SIZE,
- data_in->size - AT_HMAC_SIZE);
- if (rc < 0) {
- ATLOGE("calculate_mac faild.\n");
- goto hash_err;
- }
- rc = memcmp(data_in->data, mac.byte, AT_HMAC_SIZE);
- if (rc != 0) {
- ATLOGE("hash error.\n");
- goto hash_err;
- }
- int decrypt_osize = data_in->size - AT_HMAC_SIZE;
- uint8_t *decrypt_odata = (uint8_t *)malloc(sizeof(uint8_t) * decrypt_osize);
- if (decrypt_odata == NULL) {
- ATLOGE("malloc error.\n");
- goto malloc_err;
- }
- memset(decrypt_odata, 0, decrypt_osize);
- data_out->size = data_in->size - AT_HMAC_SIZE;
- data_out->data = (uint8_t *)malloc(sizeof(uint8_t) * data_out->size);
- if (data_out->data == NULL) {
- ATLOGE("malloc error.\n");
- goto malloc_err;
- }
- at_crypt_data decrypt_in;
- at_crypt_data decrypt_out;
- decrypt_in.data = data_in->data + AT_HMAC_SIZE;
- decrypt_in.size = data_in->size - AT_HMAC_SIZE;
- decrypt_out.data = decrypt_odata;
- decrypt_out.size = decrypt_osize;
- crypt_init();
- rc = crypt(key, &decrypt_in, &decrypt_out, iv_in, true, false);
- if (rc < 0) {
- ATLOGE("crypt faild.\n");
- goto decrypt_err;
- }
- memset(data_out->data, 0, data_out->size);
- memcpy(data_out->data, decrypt_out.data, decrypt_out.size);
- data_out->size = decrypt_out.size;
- hmac_shutdown();
- crypt_shutdown();
- if (decrypt_odata != NULL) {
- free(decrypt_odata);
- }
- return 0;
- decrypt_err:
- crypt_shutdown();
- if (data_out->data != NULL) {
- free(data_out->data);
- }
- malloc_err:
- if (decrypt_odata != NULL) {
- free(decrypt_odata);
- }
- hash_err:
- hmac_shutdown();
- param_err:
- return -1;
- }
- /**
- * at_aes_encrypt - Encrypt data using AES-128-CBC.
- * @key: Key object.
- * @data_in: Data to encrypt.
- * @data_out: Data to encrypt for.
- * @iv_in: Initialization vector to use for Cipher Block Chaining.
- *
- * Return: 0 on success, -1 if an error was detected.
- */
- int at_aes_encrypt(const struct key *key, at_crypt_data *data_in,
- at_crypt_data *data_out, const struct iv *iv_in) {
- if (key == NULL || data_in == NULL || data_out == NULL || iv_in == NULL) {
- ATLOGE("encrypt param error.\n");
- goto param_err;
- }
- if((data_in->size%16 != 0) || (data_in->size == 0)) {
- ATLOGE("data_in size error.\n");
- goto param_err;
- }
- data_out->size = data_in->size;
- data_out->data = (uint8_t *)malloc(sizeof(uint8_t) * data_out->size);
- if (data_out->data == NULL) {
- ATLOGE("malloc error.\n");
- goto malloc_err;
- }
- memset(data_out->data, 0, data_out->size);
- crypt_init();
- int rc = crypt(key, data_in, data_out, iv_in, false, true);
- if (rc < 0) {
- ATLOGE("crypt faild.\n");
- goto crypt_err;
- }
- crypt_shutdown();
- return 0;
- crypt_err:
- crypt_shutdown();
- if (data_out->data != NULL) {
- free(data_out->data);
- }
- malloc_err:
- param_err:
- return -1;
- }
- /**
- * at_aes_decrypt - Decrypt data using AES-128-CBC.
- * @key: Key object.
- * @data_in: Data to decrypt.
- * @data_out: Data to decrypt for.
- * @iv_in: Initialization vector to use for Cipher Block Chaining.
- *
- * Return: 0 on success, -1 if an error was detected.
- */
- int at_aes_decrypt(const struct key *key, at_crypt_data *data_in,
- at_crypt_data *data_out, const struct iv *iv_in) {
- if (key == NULL || data_in == NULL || data_out == NULL || iv_in == NULL) {
- ATLOGE("encrypt param error.\n");
- goto param_err;
- }
- if((data_in->size%16 != 0) || (data_in->size == 0)) {
- ATLOGE("data_in size error.\n");
- goto param_err;
- }
- data_out->size = data_in->size;
- data_out->data = (uint8_t *)malloc(sizeof(uint8_t) * data_out->size);
- if (data_out->data == NULL) {
- ATLOGE("malloc error.\n");
- goto malloc_err;
- }
- memset(data_out->data, 0, data_out->size);
- crypt_init();
- int rc = crypt(key, data_in, data_out, iv_in, false, false);
- if (rc < 0) {
- ATLOGE("crypt faild.\n");
- goto decrypt_err;
- }
- crypt_shutdown();
- return 0;
- decrypt_err:
- crypt_shutdown();
- if (data_out->data != NULL) {
- free(data_out->data);
- }
- malloc_err:
- param_err:
- return -1;
- }
|