Increase the master key size to 256 bits
NIAP certification finds that the 128 bit key size is insufficient
and requires a 256 bit key size. This change increases the
size of new master keys to 256 bits. Any existing master keys are
not changed and continue to be supported.
A new BlobType, TYPE_MASTER_KEY_AES256, is used to signal when a
key is the new larger size.
Bug: 121272336
Test: (1) Ran Keystore CTS tests against Walleye.
(2) Created keys in build without change, moved to build
with change and verified old key could be loaded and
used. Also, a new key could be created with the
increased size and could be reloaded after a reboot.
Change-Id: If00331c303e6cc7bc95a2ab624d0e19bec4e587e
diff --git a/keystore/blob.cpp b/keystore/blob.cpp
index 4b7d6c1..b2a4a1b 100644
--- a/keystore/blob.cpp
+++ b/keystore/blob.cpp
@@ -69,13 +69,28 @@
size_t mSize;
};
+/**
+ * Returns a EVP_CIPHER appropriate for the given key, based on the key's size.
+ */
+const EVP_CIPHER* getAesCipherForKey(const std::vector<uint8_t>& key) {
+ 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 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'.
+ * 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'.
*/
ResponseCode AES_gcm_encrypt(const uint8_t* in, uint8_t* out, size_t len,
const std::vector<uint8_t>& key, const uint8_t* iv, uint8_t* tag) {
- const EVP_CIPHER* cipher = EVP_aes_128_gcm();
+
+ // There can be 128-bit and 256-bit keys
+ const EVP_CIPHER* cipher = getAesCipherForKey(key);
+
EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
EVP_EncryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
@@ -102,13 +117,17 @@
}
/*
- * Decrypt 'len' data at 'in' with AES-GCM, using 128-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').
+ * 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').
*/
ResponseCode AES_gcm_decrypt(const uint8_t* in, uint8_t* out, size_t len,
const std::vector<uint8_t> key, const uint8_t* iv,
const uint8_t* tag) {
- const EVP_CIPHER* cipher = EVP_aes_128_gcm();
+
+ // There can be 128-bit and 256-bit keys
+ const EVP_CIPHER* cipher = getAesCipherForKey(key);
+
EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
EVP_DecryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
diff --git a/keystore/blob.h b/keystore/blob.h
index 8d68fc4..77b6f38 100644
--- a/keystore/blob.h
+++ b/keystore/blob.h
@@ -36,6 +36,7 @@
constexpr size_t kAesKeySize = 128 / 8;
constexpr size_t kGcmTagLength = 128 / 8;
constexpr size_t kGcmIvLength = 96 / 8;
+constexpr size_t kAes128KeySizeBytes = 128 / 8;
/* Here is the file format. There are two parts in blob.value, the secret and
* the description. The secret is stored in ciphertext, and its original size
@@ -88,6 +89,7 @@
TYPE_KEYMASTER_10 = 4,
TYPE_KEY_CHARACTERISTICS = 5,
TYPE_KEY_CHARACTERISTICS_CACHE = 6,
+ TYPE_MASTER_KEY_AES256 = 7,
} BlobType;
class LockedKeyBlobEntry;
diff --git a/keystore/user_state.cpp b/keystore/user_state.cpp
index 6026227..bc3f6d9 100644
--- a/keystore/user_state.cpp
+++ b/keystore/user_state.cpp
@@ -142,7 +142,8 @@
ResponseCode UserState::writeMasterKey(const android::String8& pw) {
std::vector<uint8_t> passwordKey(MASTER_KEY_SIZE_BYTES);
generateKeyFromPassword(passwordKey, pw, mSalt);
- Blob masterKeyBlob(mMasterKey.data(), mMasterKey.size(), mSalt, sizeof(mSalt), TYPE_MASTER_KEY);
+ Blob masterKeyBlob(mMasterKey.data(), mMasterKey.size(), mSalt, sizeof(mSalt),
+ TYPE_MASTER_KEY_AES256);
auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
return lockedEntry.writeBlobs(masterKeyBlob, {}, passwordKey, STATE_NO_ERROR);
}
@@ -171,7 +172,12 @@
salt = nullptr;
}
- std::vector<uint8_t> passwordKey(MASTER_KEY_SIZE_BYTES);
+ size_t masterKeySize = MASTER_KEY_SIZE_BYTES;
+ if (rawBlob.type == TYPE_MASTER_KEY) {
+ masterKeySize = SHA1_DIGEST_SIZE_BYTES;
+ }
+
+ std::vector<uint8_t> passwordKey(masterKeySize);
generateKeyFromPassword(passwordKey, pw, salt);
Blob masterKeyBlob, dummyBlob;
ResponseCode response;
@@ -180,7 +186,10 @@
if (response == ResponseCode::SYSTEM_ERROR) {
return response;
}
- if (response == ResponseCode::NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
+
+ size_t masterKeyBlobLength = static_cast<size_t>(masterKeyBlob.getLength());
+
+ if (response == ResponseCode::NO_ERROR && masterKeyBlobLength == masterKeySize) {
// If salt was missing, generate one and write a new master key file with the salt.
if (salt == nullptr) {
if (!generateSalt()) {
diff --git a/keystore/user_state.h b/keystore/user_state.h
index 9403552..b0671e3 100644
--- a/keystore/user_state.h
+++ b/keystore/user_state.h
@@ -78,7 +78,7 @@
static const int SHA1_DIGEST_SIZE_BYTES = 16;
static const int SHA256_DIGEST_SIZE_BYTES = 32;
- static const int MASTER_KEY_SIZE_BYTES = SHA1_DIGEST_SIZE_BYTES;
+ static const int MASTER_KEY_SIZE_BYTES = SHA256_DIGEST_SIZE_BYTES;
static const int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8;
static const int MAX_RETRY = 4;