blob: 8c52e4c67cb17f19ac69bdc31f34981c0d03165a [file] [log] [blame]
/*
* Copyright (C) 2020 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.
*/
#define LOG_TAG "keystore2"
#include "crypto.hpp"
#include <log/log.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <vector>
// Copied from system/security/keystore/blob.h.
constexpr size_t kGcmTagLength = 128 / 8;
constexpr size_t kAes128KeySizeBytes = 128 / 8;
// Copied from system/security/keystore/blob.cpp.
#if defined(__clang__)
#define OPTNONE __attribute__((optnone))
#elif defined(__GNUC__)
#define OPTNONE __attribute__((optimize("O0")))
#else
#error Need a definition for OPTNONE
#endif
class ArrayEraser {
public:
ArrayEraser(uint8_t* arr, size_t size) : mArr(arr), mSize(size) {}
OPTNONE ~ArrayEraser() { std::fill(mArr, mArr + mSize, 0); }
private:
volatile uint8_t* mArr;
size_t mSize;
};
/**
* Returns a EVP_CIPHER appropriate for the given key size.
*/
const EVP_CIPHER* getAesCipherForKey(size_t key_size) {
const EVP_CIPHER* cipher = EVP_aes_256_gcm();
if (key_size == kAes128KeySizeBytes) {
cipher = EVP_aes_128_gcm();
}
return cipher;
}
/*
* Encrypt 'len' data at 'in' with AES-GCM, using 128-bit or 256-bit key at 'key', 96-bit IV at
* 'iv' and write output to 'out' (which may be the same location as 'in') and 128-bit tag to
* 'tag'.
*/
bool AES_gcm_encrypt(const uint8_t* in, uint8_t* out, size_t len, const uint8_t* key,
size_t key_size, const uint8_t* iv, uint8_t* tag) {
// There can be 128-bit and 256-bit keys
const EVP_CIPHER* cipher = getAesCipherForKey(key_size);
bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
EVP_EncryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key, iv);
EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
std::vector<uint8_t> out_tmp(len);
uint8_t* out_pos = out_tmp.data();
int out_len;
EVP_EncryptUpdate(ctx.get(), out_pos, &out_len, in, len);
out_pos += out_len;
EVP_EncryptFinal_ex(ctx.get(), out_pos, &out_len);
out_pos += out_len;
if (out_pos - out_tmp.data() != static_cast<ssize_t>(len)) {
ALOGD("Encrypted ciphertext is the wrong size, expected %zu, got %zd", len,
out_pos - out_tmp.data());
return false;
}
std::copy(out_tmp.data(), out_pos, out);
EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kGcmTagLength, tag);
return true;
}
/*
* Decrypt 'len' data at 'in' with AES-GCM, using 128-bit or 256-bit key at 'key', 96-bit IV at
* 'iv', checking 128-bit tag at 'tag' and writing plaintext to 'out'(which may be the same
* location as 'in').
*/
bool AES_gcm_decrypt(const uint8_t* in, uint8_t* out, size_t len, const uint8_t* key,
size_t key_size, const uint8_t* iv, const uint8_t* tag) {
// There can be 128-bit and 256-bit keys
const EVP_CIPHER* cipher = getAesCipherForKey(key_size);
bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
EVP_DecryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key, iv);
EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kGcmTagLength, const_cast<uint8_t*>(tag));
std::vector<uint8_t> out_tmp(len);
ArrayEraser out_eraser(out_tmp.data(), len);
uint8_t* out_pos = out_tmp.data();
int out_len;
EVP_DecryptUpdate(ctx.get(), out_pos, &out_len, in, len);
out_pos += out_len;
if (!EVP_DecryptFinal_ex(ctx.get(), out_pos, &out_len)) {
ALOGE("Failed to decrypt blob; ciphertext or tag is likely corrupted");
return false;
}
out_pos += out_len;
if (out_pos - out_tmp.data() != static_cast<ssize_t>(len)) {
ALOGE("Encrypted plaintext is the wrong size, expected %zu, got %zd", len,
out_pos - out_tmp.data());
return false;
}
std::copy(out_tmp.data(), out_pos, out);
return true;
}
// Copied from system/security/keystore/keymaster_enforcement.cpp.
class EvpMdCtx {
public:
EvpMdCtx() { EVP_MD_CTX_init(&ctx_); }
~EvpMdCtx() { EVP_MD_CTX_cleanup(&ctx_); }
EVP_MD_CTX* get() { return &ctx_; }
private:
EVP_MD_CTX ctx_;
};
bool CreateKeyId(const uint8_t* key_blob, size_t len, km_id_t* out_id) {
EvpMdCtx ctx;
uint8_t hash[EVP_MAX_MD_SIZE];
unsigned int hash_len;
if (EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr /* ENGINE */) &&
EVP_DigestUpdate(ctx.get(), key_blob, len) &&
EVP_DigestFinal_ex(ctx.get(), hash, &hash_len)) {
assert(hash_len >= sizeof(*out_id));
memcpy(out_id, hash, sizeof(*out_id));
return true;
}
return false;
}
// Copied from system/security/keystore/user_state.h
static constexpr size_t SALT_SIZE = 16;
// Copied from system/security/keystore/user_state.cpp.
void generateKeyFromPassword(uint8_t* key, size_t key_len, const char* pw, size_t pw_len,
uint8_t* salt) {
size_t saltSize;
if (salt != nullptr) {
saltSize = SALT_SIZE;
} else {
// Pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
salt = (uint8_t*)"keystore";
// sizeof = 9, not strlen = 8
saltSize = sizeof("keystore");
}
const EVP_MD* digest = EVP_sha256();
// SHA1 was used prior to increasing the key size
if (key_len == kAes128KeySizeBytes) {
digest = EVP_sha1();
}
PKCS5_PBKDF2_HMAC(pw, pw_len, salt, saltSize, 8192, digest, key_len, key);
}