Enable encryption authentication configurability (#8312)
* Enable encryption authentication configurability Description diff-1: Remove memcpy due to auth-token computation Address review comments Patch proposes major changes: 1. Enable FDB to choose encryption authentication as a configurable parameter. Fix issues choosing ENCRYPT_HEADER_AUTH_TOKEN_NONE mode. 2. Introduce AES_CMAC as supported encryption authentication scheme. Patch allows cluster to govern: if encryption authentication needs to enabled, if yes, then choose from two supported schemes: 1. HMAC_SHA_256 2. AES_256_CMAC Testing devRunCorrectness - 100K BlobCipher unittests EncryptionOps.toml BlobGranuleCorrectness/BlobGranuleCorrectnessClean
This commit is contained in:
parent
63b8d775a3
commit
03f1d13be3
|
@ -50,12 +50,6 @@
|
||||||
|
|
||||||
#define BLOB_CIPHER_DEBUG false
|
#define BLOB_CIPHER_DEBUG false
|
||||||
|
|
||||||
namespace {
|
|
||||||
bool isEncryptHeaderAuthTokenModeValid(const EncryptAuthTokenMode mode) {
|
|
||||||
return mode >= ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE && mode < ENCRYPT_HEADER_AUTH_TOKEN_LAST;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// BlobCipherMetrics methods
|
// BlobCipherMetrics methods
|
||||||
|
|
||||||
BlobCipherMetrics::CounterSet::CounterSet(CounterCollection& cc, std::string name)
|
BlobCipherMetrics::CounterSet::CounterSet(CounterCollection& cc, std::string name)
|
||||||
|
@ -168,8 +162,8 @@ void BlobCipherKey::applyHmacSha256Derivation() {
|
||||||
memcpy(&buf[0], baseCipher.get(), baseCipherLen);
|
memcpy(&buf[0], baseCipher.get(), baseCipherLen);
|
||||||
memcpy(&buf[0] + baseCipherLen, &randomSalt, sizeof(EncryptCipherRandomSalt));
|
memcpy(&buf[0] + baseCipherLen, &randomSalt, sizeof(EncryptCipherRandomSalt));
|
||||||
HmacSha256DigestGen hmacGen(baseCipher.get(), baseCipherLen);
|
HmacSha256DigestGen hmacGen(baseCipher.get(), baseCipherLen);
|
||||||
unsigned int digestLen =
|
unsigned int digestLen = hmacGen.digest(
|
||||||
hmacGen.digest(&buf[0], baseCipherLen + sizeof(EncryptCipherRandomSalt), cipher.get(), AUTH_TOKEN_SIZE);
|
{ { &buf[0], baseCipherLen + sizeof(EncryptCipherRandomSalt) } }, cipher.get(), AUTH_TOKEN_HMAC_SHA_SIZE);
|
||||||
if (digestLen < AES_256_KEY_LENGTH) {
|
if (digestLen < AES_256_KEY_LENGTH) {
|
||||||
memcpy(cipher.get() + digestLen, buf, AES_256_KEY_LENGTH - digestLen);
|
memcpy(cipher.get() + digestLen, buf, AES_256_KEY_LENGTH - digestLen);
|
||||||
}
|
}
|
||||||
|
@ -510,7 +504,21 @@ EncryptBlobCipherAes265Ctr::EncryptBlobCipherAes265Ctr(Reference<BlobCipherKey>
|
||||||
BlobCipherMetrics::UsageType usageType)
|
BlobCipherMetrics::UsageType usageType)
|
||||||
: ctx(EVP_CIPHER_CTX_new()), textCipherKey(tCipherKey), headerCipherKey(hCipherKey), authTokenMode(mode),
|
: ctx(EVP_CIPHER_CTX_new()), textCipherKey(tCipherKey), headerCipherKey(hCipherKey), authTokenMode(mode),
|
||||||
usageType(usageType) {
|
usageType(usageType) {
|
||||||
ASSERT(isEncryptHeaderAuthTokenModeValid(mode));
|
ASSERT_EQ(ivLen, AES_256_IV_LENGTH);
|
||||||
|
authTokenAlgo = getAuthTokenAlgoFromMode(authTokenMode);
|
||||||
|
memcpy(&iv[0], cipherIV, ivLen);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptBlobCipherAes265Ctr::EncryptBlobCipherAes265Ctr(Reference<BlobCipherKey> tCipherKey,
|
||||||
|
Reference<BlobCipherKey> hCipherKey,
|
||||||
|
const uint8_t* cipherIV,
|
||||||
|
const int ivLen,
|
||||||
|
const EncryptAuthTokenMode mode,
|
||||||
|
const EncryptAuthTokenAlgo algo,
|
||||||
|
BlobCipherMetrics::UsageType usageType)
|
||||||
|
: ctx(EVP_CIPHER_CTX_new()), textCipherKey(tCipherKey), headerCipherKey(hCipherKey), authTokenMode(mode),
|
||||||
|
authTokenAlgo(algo), usageType(usageType) {
|
||||||
ASSERT_EQ(ivLen, AES_256_IV_LENGTH);
|
ASSERT_EQ(ivLen, AES_256_IV_LENGTH);
|
||||||
memcpy(&iv[0], cipherIV, ivLen);
|
memcpy(&iv[0], cipherIV, ivLen);
|
||||||
init();
|
init();
|
||||||
|
@ -522,12 +530,33 @@ EncryptBlobCipherAes265Ctr::EncryptBlobCipherAes265Ctr(Reference<BlobCipherKey>
|
||||||
BlobCipherMetrics::UsageType usageType)
|
BlobCipherMetrics::UsageType usageType)
|
||||||
: ctx(EVP_CIPHER_CTX_new()), textCipherKey(tCipherKey), headerCipherKey(hCipherKey), authTokenMode(mode),
|
: ctx(EVP_CIPHER_CTX_new()), textCipherKey(tCipherKey), headerCipherKey(hCipherKey), authTokenMode(mode),
|
||||||
usageType(usageType) {
|
usageType(usageType) {
|
||||||
ASSERT(isEncryptHeaderAuthTokenModeValid(mode));
|
authTokenAlgo = getAuthTokenAlgoFromMode(authTokenMode);
|
||||||
|
deterministicRandom()->randomBytes(iv, AES_256_IV_LENGTH);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptBlobCipherAes265Ctr::EncryptBlobCipherAes265Ctr(Reference<BlobCipherKey> tCipherKey,
|
||||||
|
Reference<BlobCipherKey> hCipherKey,
|
||||||
|
const EncryptAuthTokenMode mode,
|
||||||
|
const EncryptAuthTokenAlgo algo,
|
||||||
|
BlobCipherMetrics::UsageType usageType)
|
||||||
|
: ctx(EVP_CIPHER_CTX_new()), textCipherKey(tCipherKey), headerCipherKey(hCipherKey), authTokenMode(mode),
|
||||||
|
usageType(usageType) {
|
||||||
deterministicRandom()->randomBytes(iv, AES_256_IV_LENGTH);
|
deterministicRandom()->randomBytes(iv, AES_256_IV_LENGTH);
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncryptBlobCipherAes265Ctr::init() {
|
void EncryptBlobCipherAes265Ctr::init() {
|
||||||
|
ASSERT(textCipherKey.isValid());
|
||||||
|
ASSERT(headerCipherKey.isValid());
|
||||||
|
|
||||||
|
if (!isEncryptHeaderAuthTokenDetailsValid(authTokenMode, authTokenAlgo)) {
|
||||||
|
TraceEvent(SevWarn, "InvalidAuthTokenDetails")
|
||||||
|
.detail("TokenMode", authTokenMode)
|
||||||
|
.detail("TokenAlgo", authTokenAlgo);
|
||||||
|
throw internal_error();
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx == nullptr) {
|
if (ctx == nullptr) {
|
||||||
throw encrypt_ops_error();
|
throw encrypt_ops_error();
|
||||||
}
|
}
|
||||||
|
@ -553,11 +582,10 @@ Reference<EncryptBuf> EncryptBlobCipherAes265Ctr::encrypt(const uint8_t* plainte
|
||||||
// Alloc buffer computation accounts for 'header authentication' generation scheme. If single-auth-token needs
|
// Alloc buffer computation accounts for 'header authentication' generation scheme. If single-auth-token needs
|
||||||
// to be generated, allocate buffer sufficient to append header to the cipherText optimizing memcpy cost.
|
// to be generated, allocate buffer sufficient to append header to the cipherText optimizing memcpy cost.
|
||||||
|
|
||||||
const int allocSize = authTokenMode == ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE
|
const int allocSize = plaintextLen + AES_BLOCK_SIZE;
|
||||||
? plaintextLen + AES_BLOCK_SIZE + sizeof(BlobCipherEncryptHeader)
|
|
||||||
: plaintextLen + AES_BLOCK_SIZE;
|
|
||||||
Reference<EncryptBuf> encryptBuf = makeReference<EncryptBuf>(allocSize, arena);
|
Reference<EncryptBuf> encryptBuf = makeReference<EncryptBuf>(allocSize, arena);
|
||||||
uint8_t* ciphertext = encryptBuf->begin();
|
uint8_t* ciphertext = encryptBuf->begin();
|
||||||
|
|
||||||
int bytes{ 0 };
|
int bytes{ 0 };
|
||||||
if (EVP_EncryptUpdate(ctx, ciphertext, &bytes, plaintext, plaintextLen) != 1) {
|
if (EVP_EncryptUpdate(ctx, ciphertext, &bytes, plaintext, plaintextLen) != 1) {
|
||||||
TraceEvent(SevWarn, "BlobCipherEncryptUpdateFailed")
|
TraceEvent(SevWarn, "BlobCipherEncryptUpdateFailed")
|
||||||
|
@ -586,50 +614,55 @@ Reference<EncryptBuf> EncryptBlobCipherAes265Ctr::encrypt(const uint8_t* plainte
|
||||||
header->flags.headerVersion = EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION;
|
header->flags.headerVersion = EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION;
|
||||||
header->flags.encryptMode = ENCRYPT_CIPHER_MODE_AES_256_CTR;
|
header->flags.encryptMode = ENCRYPT_CIPHER_MODE_AES_256_CTR;
|
||||||
header->flags.authTokenMode = authTokenMode;
|
header->flags.authTokenMode = authTokenMode;
|
||||||
|
header->flags.authTokenAlgo = authTokenAlgo;
|
||||||
|
|
||||||
|
// Ensure encryption header authToken details sanity
|
||||||
|
ASSERT(isEncryptHeaderAuthTokenDetailsValid(authTokenMode, authTokenAlgo));
|
||||||
|
|
||||||
// Populate cipherText encryption-key details
|
// Populate cipherText encryption-key details
|
||||||
header->cipherTextDetails.baseCipherId = textCipherKey->getBaseCipherId();
|
header->cipherTextDetails.baseCipherId = textCipherKey->getBaseCipherId();
|
||||||
header->cipherTextDetails.encryptDomainId = textCipherKey->getDomainId();
|
header->cipherTextDetails.encryptDomainId = textCipherKey->getDomainId();
|
||||||
header->cipherTextDetails.salt = textCipherKey->getSalt();
|
header->cipherTextDetails.salt = textCipherKey->getSalt();
|
||||||
|
// Populate header encryption-key details
|
||||||
|
// TODO: HeaderCipherKey is not necessary if AuthTokenMode == NONE
|
||||||
|
header->cipherHeaderDetails.encryptDomainId = headerCipherKey->getDomainId();
|
||||||
|
header->cipherHeaderDetails.baseCipherId = headerCipherKey->getBaseCipherId();
|
||||||
|
header->cipherHeaderDetails.salt = headerCipherKey->getSalt();
|
||||||
|
|
||||||
memcpy(&header->iv[0], &iv[0], AES_256_IV_LENGTH);
|
memcpy(&header->iv[0], &iv[0], AES_256_IV_LENGTH);
|
||||||
|
|
||||||
if (authTokenMode == ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE) {
|
if (authTokenMode == EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE) {
|
||||||
// No header 'authToken' generation needed.
|
// No header 'authToken' generation needed.
|
||||||
} else {
|
} else {
|
||||||
// Populate header encryption-key details
|
|
||||||
header->cipherHeaderDetails.encryptDomainId = headerCipherKey->getDomainId();
|
|
||||||
header->cipherHeaderDetails.baseCipherId = headerCipherKey->getBaseCipherId();
|
|
||||||
header->cipherHeaderDetails.salt = headerCipherKey->getSalt();
|
|
||||||
|
|
||||||
// Populate header authToken details
|
// Populate header authToken details
|
||||||
if (header->flags.authTokenMode == ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE) {
|
if (header->flags.authTokenMode == EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE) {
|
||||||
ASSERT_GE(allocSize, (bytes + finalBytes + sizeof(BlobCipherEncryptHeader)));
|
ASSERT_GE(allocSize, (bytes + finalBytes));
|
||||||
ASSERT_GE(encryptBuf->getLogicalSize(), (bytes + finalBytes + sizeof(BlobCipherEncryptHeader)));
|
ASSERT_GE(encryptBuf->getLogicalSize(), (bytes + finalBytes));
|
||||||
|
|
||||||
memcpy(&ciphertext[bytes + finalBytes],
|
computeAuthToken({ { ciphertext, bytes + finalBytes },
|
||||||
reinterpret_cast<const uint8_t*>(header),
|
{ reinterpret_cast<const uint8_t*>(header), sizeof(BlobCipherEncryptHeader) } },
|
||||||
sizeof(BlobCipherEncryptHeader));
|
|
||||||
computeAuthToken(ciphertext,
|
|
||||||
bytes + finalBytes + sizeof(BlobCipherEncryptHeader),
|
|
||||||
headerCipherKey->rawCipher(),
|
headerCipherKey->rawCipher(),
|
||||||
AES_256_KEY_LENGTH,
|
AES_256_KEY_LENGTH,
|
||||||
&header->singleAuthToken.authToken[0],
|
&header->singleAuthToken.authToken[0],
|
||||||
AUTH_TOKEN_SIZE);
|
(EncryptAuthTokenAlgo)header->flags.authTokenAlgo,
|
||||||
|
AUTH_TOKEN_MAX_SIZE);
|
||||||
} else {
|
} else {
|
||||||
ASSERT_EQ(header->flags.authTokenMode, ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI);
|
ASSERT_EQ(header->flags.authTokenMode, EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI);
|
||||||
|
|
||||||
computeAuthToken(ciphertext,
|
// TOOD: Use HMAC_SHA encyrption authentication scheme as AES_CMAC needs minimum 16 bytes cipher key
|
||||||
bytes + finalBytes,
|
computeAuthToken({ { ciphertext, bytes + finalBytes } },
|
||||||
reinterpret_cast<const uint8_t*>(&header->cipherTextDetails.salt),
|
reinterpret_cast<const uint8_t*>(&header->cipherTextDetails.salt),
|
||||||
sizeof(EncryptCipherRandomSalt),
|
sizeof(EncryptCipherRandomSalt),
|
||||||
&header->multiAuthTokens.cipherTextAuthToken[0],
|
&header->multiAuthTokens.cipherTextAuthToken[0],
|
||||||
AUTH_TOKEN_SIZE);
|
EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA,
|
||||||
computeAuthToken(reinterpret_cast<const uint8_t*>(header),
|
AUTH_TOKEN_MAX_SIZE);
|
||||||
sizeof(BlobCipherEncryptHeader),
|
computeAuthToken({ { reinterpret_cast<const uint8_t*>(header), sizeof(BlobCipherEncryptHeader) } },
|
||||||
headerCipherKey->rawCipher(),
|
headerCipherKey->rawCipher(),
|
||||||
AES_256_KEY_LENGTH,
|
AES_256_KEY_LENGTH,
|
||||||
&header->multiAuthTokens.headerAuthToken[0],
|
&header->multiAuthTokens.headerAuthToken[0],
|
||||||
AUTH_TOKEN_SIZE);
|
(EncryptAuthTokenAlgo)header->flags.authTokenAlgo,
|
||||||
|
AUTH_TOKEN_MAX_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,7 +672,13 @@ Reference<EncryptBuf> EncryptBlobCipherAes265Ctr::encrypt(const uint8_t* plainte
|
||||||
BlobCipherMetrics::counters(usageType).encryptCPUTimeNS += int64_t((timer_monotonic() - startTime) * 1e9);
|
BlobCipherMetrics::counters(usageType).encryptCPUTimeNS += int64_t((timer_monotonic() - startTime) * 1e9);
|
||||||
}
|
}
|
||||||
|
|
||||||
CODE_PROBE(true, "Encrypting data with BlobCipher");
|
CODE_PROBE(true, "BlobCipher data encryption");
|
||||||
|
CODE_PROBE(header->flags.authTokenAlgo == EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE,
|
||||||
|
"Encryption authentication disabled");
|
||||||
|
CODE_PROBE(header->flags.authTokenAlgo == EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA,
|
||||||
|
"HMAC_SHA Auth token generation");
|
||||||
|
CODE_PROBE(header->flags.authTokenAlgo == EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_AES_CMAC,
|
||||||
|
"AES_CMAC Auth token generation");
|
||||||
|
|
||||||
return encryptBuf;
|
return encryptBuf;
|
||||||
}
|
}
|
||||||
|
@ -677,26 +716,30 @@ void DecryptBlobCipherAes256Ctr::verifyHeaderAuthToken(const BlobCipherEncryptHe
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_EQ(header.flags.authTokenMode, ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI);
|
ASSERT_EQ(header.flags.authTokenMode, ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI);
|
||||||
|
ASSERT(isEncryptHeaderAuthTokenAlgoValid((EncryptAuthTokenAlgo)header.flags.authTokenAlgo));
|
||||||
|
|
||||||
BlobCipherEncryptHeader headerCopy;
|
BlobCipherEncryptHeader headerCopy;
|
||||||
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
reinterpret_cast<const uint8_t*>(&header),
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
sizeof(BlobCipherEncryptHeader));
|
sizeof(BlobCipherEncryptHeader));
|
||||||
memset(reinterpret_cast<uint8_t*>(&headerCopy.multiAuthTokens.headerAuthToken), 0, AUTH_TOKEN_SIZE);
|
memset(reinterpret_cast<uint8_t*>(&headerCopy.multiAuthTokens.headerAuthToken), 0, AUTH_TOKEN_MAX_SIZE);
|
||||||
uint8_t computedHeaderAuthToken[AUTH_TOKEN_SIZE];
|
uint8_t computedHeaderAuthToken[AUTH_TOKEN_MAX_SIZE]{};
|
||||||
computeAuthToken(reinterpret_cast<const uint8_t*>(&headerCopy),
|
computeAuthToken({ { reinterpret_cast<const uint8_t*>(&headerCopy), sizeof(BlobCipherEncryptHeader) } },
|
||||||
sizeof(BlobCipherEncryptHeader),
|
|
||||||
headerCipherKey->rawCipher(),
|
headerCipherKey->rawCipher(),
|
||||||
AES_256_KEY_LENGTH,
|
AES_256_KEY_LENGTH,
|
||||||
&computedHeaderAuthToken[0],
|
&computedHeaderAuthToken[0],
|
||||||
AUTH_TOKEN_SIZE);
|
(EncryptAuthTokenAlgo)header.flags.authTokenAlgo,
|
||||||
if (memcmp(&header.multiAuthTokens.headerAuthToken[0], &computedHeaderAuthToken[0], AUTH_TOKEN_SIZE) != 0) {
|
AUTH_TOKEN_MAX_SIZE);
|
||||||
|
|
||||||
|
int authTokenSize = getEncryptHeaderAuthTokenSize(header.flags.authTokenAlgo);
|
||||||
|
ASSERT_LE(authTokenSize, AUTH_TOKEN_MAX_SIZE);
|
||||||
|
if (memcmp(&header.multiAuthTokens.headerAuthToken[0], &computedHeaderAuthToken[0], authTokenSize) != 0) {
|
||||||
TraceEvent(SevWarn, "BlobCipherVerifyEncryptBlobHeaderAuthTokenMismatch")
|
TraceEvent(SevWarn, "BlobCipherVerifyEncryptBlobHeaderAuthTokenMismatch")
|
||||||
.detail("HeaderVersion", header.flags.headerVersion)
|
.detail("HeaderVersion", header.flags.headerVersion)
|
||||||
.detail("HeaderMode", header.flags.encryptMode)
|
.detail("HeaderMode", header.flags.encryptMode)
|
||||||
.detail("MultiAuthHeaderAuthToken",
|
.detail("MultiAuthHeaderAuthToken",
|
||||||
StringRef(arena, &header.multiAuthTokens.headerAuthToken[0], AUTH_TOKEN_SIZE).toString())
|
StringRef(arena, &header.multiAuthTokens.headerAuthToken[0], AUTH_TOKEN_MAX_SIZE).toString())
|
||||||
.detail("ComputedHeaderAuthToken", StringRef(computedHeaderAuthToken, AUTH_TOKEN_SIZE));
|
.detail("ComputedHeaderAuthToken", StringRef(computedHeaderAuthToken, AUTH_TOKEN_MAX_SIZE));
|
||||||
throw encrypt_header_authtoken_mismatch();
|
throw encrypt_header_authtoken_mismatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,32 +749,35 @@ void DecryptBlobCipherAes256Ctr::verifyHeaderAuthToken(const BlobCipherEncryptHe
|
||||||
void DecryptBlobCipherAes256Ctr::verifyHeaderSingleAuthToken(const uint8_t* ciphertext,
|
void DecryptBlobCipherAes256Ctr::verifyHeaderSingleAuthToken(const uint8_t* ciphertext,
|
||||||
const int ciphertextLen,
|
const int ciphertextLen,
|
||||||
const BlobCipherEncryptHeader& header,
|
const BlobCipherEncryptHeader& header,
|
||||||
uint8_t* buff,
|
|
||||||
Arena& arena) {
|
Arena& arena) {
|
||||||
// Header authToken not set for single auth-token mode.
|
// Header authToken not set for single auth-token mode.
|
||||||
ASSERT(!headerAuthTokenValidationDone);
|
ASSERT(!headerAuthTokenValidationDone);
|
||||||
|
|
||||||
// prepare the payload {cipherText + encryptionHeader}
|
// prepare the payload {cipherText + encryptionHeader}
|
||||||
memcpy(&buff[0], ciphertext, ciphertextLen);
|
|
||||||
memcpy(&buff[ciphertextLen], reinterpret_cast<const uint8_t*>(&header), sizeof(BlobCipherEncryptHeader));
|
|
||||||
// ensure the 'authToken' is reset before computing the 'authentication token'
|
// ensure the 'authToken' is reset before computing the 'authentication token'
|
||||||
BlobCipherEncryptHeader* eHeader = (BlobCipherEncryptHeader*)(&buff[ciphertextLen]);
|
BlobCipherEncryptHeader headerCopy;
|
||||||
memset(reinterpret_cast<uint8_t*>(&eHeader->singleAuthToken), 0, 2 * AUTH_TOKEN_SIZE);
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
uint8_t computed[AUTH_TOKEN_SIZE];
|
sizeof(BlobCipherEncryptHeader));
|
||||||
computeAuthToken(buff,
|
memset(reinterpret_cast<uint8_t*>(&headerCopy.singleAuthToken), 0, 2 * AUTH_TOKEN_MAX_SIZE);
|
||||||
ciphertextLen + sizeof(BlobCipherEncryptHeader),
|
uint8_t computed[AUTH_TOKEN_MAX_SIZE];
|
||||||
|
computeAuthToken({ { ciphertext, ciphertextLen },
|
||||||
|
{ reinterpret_cast<const uint8_t*>(&headerCopy), sizeof(BlobCipherEncryptHeader) } },
|
||||||
headerCipherKey->rawCipher(),
|
headerCipherKey->rawCipher(),
|
||||||
AES_256_KEY_LENGTH,
|
AES_256_KEY_LENGTH,
|
||||||
&computed[0],
|
&computed[0],
|
||||||
AUTH_TOKEN_SIZE);
|
(EncryptAuthTokenAlgo)header.flags.authTokenAlgo,
|
||||||
if (memcmp(&header.singleAuthToken.authToken[0], &computed[0], AUTH_TOKEN_SIZE) != 0) {
|
AUTH_TOKEN_MAX_SIZE);
|
||||||
|
|
||||||
|
int authTokenSize = getEncryptHeaderAuthTokenSize(header.flags.authTokenAlgo);
|
||||||
|
ASSERT_LE(authTokenSize, AUTH_TOKEN_MAX_SIZE);
|
||||||
|
if (memcmp(&header.singleAuthToken.authToken[0], &computed[0], authTokenSize) != 0) {
|
||||||
TraceEvent(SevWarn, "BlobCipherVerifyEncryptBlobHeaderAuthTokenMismatch")
|
TraceEvent(SevWarn, "BlobCipherVerifyEncryptBlobHeaderAuthTokenMismatch")
|
||||||
.detail("HeaderVersion", header.flags.headerVersion)
|
.detail("HeaderVersion", header.flags.headerVersion)
|
||||||
.detail("HeaderMode", header.flags.encryptMode)
|
.detail("HeaderMode", header.flags.encryptMode)
|
||||||
.detail("SingleAuthToken",
|
.detail("SingleAuthToken",
|
||||||
StringRef(arena, &header.singleAuthToken.authToken[0], AUTH_TOKEN_SIZE).toString())
|
StringRef(arena, &header.singleAuthToken.authToken[0], AUTH_TOKEN_MAX_SIZE).toString())
|
||||||
.detail("ComputedSingleAuthToken", StringRef(computed, AUTH_TOKEN_SIZE));
|
.detail("ComputedSingleAuthToken", StringRef(computed, AUTH_TOKEN_MAX_SIZE));
|
||||||
throw encrypt_header_authtoken_mismatch();
|
throw encrypt_header_authtoken_mismatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -739,25 +785,26 @@ void DecryptBlobCipherAes256Ctr::verifyHeaderSingleAuthToken(const uint8_t* ciph
|
||||||
void DecryptBlobCipherAes256Ctr::verifyHeaderMultiAuthToken(const uint8_t* ciphertext,
|
void DecryptBlobCipherAes256Ctr::verifyHeaderMultiAuthToken(const uint8_t* ciphertext,
|
||||||
const int ciphertextLen,
|
const int ciphertextLen,
|
||||||
const BlobCipherEncryptHeader& header,
|
const BlobCipherEncryptHeader& header,
|
||||||
uint8_t* buff,
|
|
||||||
Arena& arena) {
|
Arena& arena) {
|
||||||
if (!headerAuthTokenValidationDone) {
|
if (!headerAuthTokenValidationDone) {
|
||||||
verifyHeaderAuthToken(header, arena);
|
verifyHeaderAuthToken(header, arena);
|
||||||
}
|
}
|
||||||
uint8_t computedCipherTextAuthToken[AUTH_TOKEN_SIZE];
|
uint8_t computedCipherTextAuthToken[AUTH_TOKEN_MAX_SIZE];
|
||||||
computeAuthToken(ciphertext,
|
// TOOD: Use HMAC_SHA encyrption authentication scheme as AES_CMAC needs minimum 16 bytes cipher key
|
||||||
ciphertextLen,
|
computeAuthToken({ { ciphertext, ciphertextLen } },
|
||||||
reinterpret_cast<const uint8_t*>(&header.cipherTextDetails.salt),
|
reinterpret_cast<const uint8_t*>(&header.cipherTextDetails.salt),
|
||||||
sizeof(EncryptCipherRandomSalt),
|
sizeof(EncryptCipherRandomSalt),
|
||||||
&computedCipherTextAuthToken[0],
|
&computedCipherTextAuthToken[0],
|
||||||
AUTH_TOKEN_SIZE);
|
EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA,
|
||||||
if (memcmp(&header.multiAuthTokens.cipherTextAuthToken[0], &computedCipherTextAuthToken[0], AUTH_TOKEN_SIZE) != 0) {
|
AUTH_TOKEN_MAX_SIZE);
|
||||||
|
if (memcmp(&header.multiAuthTokens.cipherTextAuthToken[0], &computedCipherTextAuthToken[0], AUTH_TOKEN_MAX_SIZE) !=
|
||||||
|
0) {
|
||||||
TraceEvent(SevWarn, "BlobCipherVerifyEncryptBlobHeaderAuthTokenMismatch")
|
TraceEvent(SevWarn, "BlobCipherVerifyEncryptBlobHeaderAuthTokenMismatch")
|
||||||
.detail("HeaderVersion", header.flags.headerVersion)
|
.detail("HeaderVersion", header.flags.headerVersion)
|
||||||
.detail("HeaderMode", header.flags.encryptMode)
|
.detail("HeaderMode", header.flags.encryptMode)
|
||||||
.detail("MultiAuthCipherTextAuthToken",
|
.detail("MultiAuthCipherTextAuthToken",
|
||||||
StringRef(arena, &header.multiAuthTokens.cipherTextAuthToken[0], AUTH_TOKEN_SIZE).toString())
|
StringRef(arena, &header.multiAuthTokens.cipherTextAuthToken[0], AUTH_TOKEN_MAX_SIZE).toString())
|
||||||
.detail("ComputedCipherTextAuthToken", StringRef(computedCipherTextAuthToken, AUTH_TOKEN_SIZE));
|
.detail("ComputedCipherTextAuthToken", StringRef(computedCipherTextAuthToken, AUTH_TOKEN_MAX_SIZE));
|
||||||
throw encrypt_header_authtoken_mismatch();
|
throw encrypt_header_authtoken_mismatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -765,13 +812,12 @@ void DecryptBlobCipherAes256Ctr::verifyHeaderMultiAuthToken(const uint8_t* ciphe
|
||||||
void DecryptBlobCipherAes256Ctr::verifyAuthTokens(const uint8_t* ciphertext,
|
void DecryptBlobCipherAes256Ctr::verifyAuthTokens(const uint8_t* ciphertext,
|
||||||
const int ciphertextLen,
|
const int ciphertextLen,
|
||||||
const BlobCipherEncryptHeader& header,
|
const BlobCipherEncryptHeader& header,
|
||||||
uint8_t* buff,
|
|
||||||
Arena& arena) {
|
Arena& arena) {
|
||||||
if (header.flags.authTokenMode == ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE) {
|
if (header.flags.authTokenMode == EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE) {
|
||||||
verifyHeaderSingleAuthToken(ciphertext, ciphertextLen, header, buff, arena);
|
verifyHeaderSingleAuthToken(ciphertext, ciphertextLen, header, arena);
|
||||||
} else {
|
} else {
|
||||||
ASSERT_EQ(header.flags.authTokenMode, ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI);
|
ASSERT_EQ(header.flags.authTokenMode, ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI);
|
||||||
verifyHeaderMultiAuthToken(ciphertext, ciphertextLen, header, buff, arena);
|
verifyHeaderMultiAuthToken(ciphertext, ciphertextLen, header, arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
authTokensValidationDone = true;
|
authTokensValidationDone = true;
|
||||||
|
@ -780,13 +826,13 @@ void DecryptBlobCipherAes256Ctr::verifyAuthTokens(const uint8_t* ciphertext,
|
||||||
void DecryptBlobCipherAes256Ctr::verifyEncryptHeaderMetadata(const BlobCipherEncryptHeader& header) {
|
void DecryptBlobCipherAes256Ctr::verifyEncryptHeaderMetadata(const BlobCipherEncryptHeader& header) {
|
||||||
// validate header flag sanity
|
// validate header flag sanity
|
||||||
if (header.flags.headerVersion != EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION ||
|
if (header.flags.headerVersion != EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION ||
|
||||||
header.flags.encryptMode != ENCRYPT_CIPHER_MODE_AES_256_CTR ||
|
header.flags.encryptMode != EncryptCipherMode::ENCRYPT_CIPHER_MODE_AES_256_CTR ||
|
||||||
!isEncryptHeaderAuthTokenModeValid((EncryptAuthTokenMode)header.flags.authTokenMode)) {
|
!isEncryptHeaderAuthTokenModeValid((EncryptAuthTokenMode)header.flags.authTokenMode)) {
|
||||||
TraceEvent(SevWarn, "BlobCipherVerifyEncryptBlobHeader")
|
TraceEvent(SevWarn, "BlobCipherVerifyEncryptBlobHeader")
|
||||||
.detail("HeaderVersion", header.flags.headerVersion)
|
.detail("HeaderVersion", header.flags.headerVersion)
|
||||||
.detail("ExpectedVersion", EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION)
|
.detail("ExpectedVersion", EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION)
|
||||||
.detail("EncryptCipherMode", header.flags.encryptMode)
|
.detail("EncryptCipherMode", header.flags.encryptMode)
|
||||||
.detail("ExpectedCipherMode", ENCRYPT_CIPHER_MODE_AES_256_CTR)
|
.detail("ExpectedCipherMode", EncryptCipherMode::ENCRYPT_CIPHER_MODE_AES_256_CTR)
|
||||||
.detail("EncryptHeaderAuthTokenMode", header.flags.authTokenMode);
|
.detail("EncryptHeaderAuthTokenMode", header.flags.authTokenMode);
|
||||||
throw encrypt_header_metadata_mismatch();
|
throw encrypt_header_metadata_mismatch();
|
||||||
}
|
}
|
||||||
|
@ -803,19 +849,18 @@ Reference<EncryptBuf> DecryptBlobCipherAes256Ctr::decrypt(const uint8_t* ciphert
|
||||||
|
|
||||||
verifyEncryptHeaderMetadata(header);
|
verifyEncryptHeaderMetadata(header);
|
||||||
|
|
||||||
if (header.flags.authTokenMode != ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE && !headerCipherKey.isValid()) {
|
if (header.flags.authTokenMode != EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE &&
|
||||||
|
!headerCipherKey.isValid()) {
|
||||||
TraceEvent(SevWarn, "BlobCipherDecryptInvalidHeaderCipherKey")
|
TraceEvent(SevWarn, "BlobCipherDecryptInvalidHeaderCipherKey")
|
||||||
.detail("AuthTokenMode", header.flags.authTokenMode);
|
.detail("AuthTokenMode", header.flags.authTokenMode);
|
||||||
throw encrypt_ops_error();
|
throw encrypt_ops_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
const int allocSize = header.flags.authTokenMode == ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE
|
const int allocSize = ciphertextLen + AES_BLOCK_SIZE;
|
||||||
? ciphertextLen + AES_BLOCK_SIZE + sizeof(BlobCipherEncryptHeader)
|
|
||||||
: ciphertextLen + AES_BLOCK_SIZE;
|
|
||||||
Reference<EncryptBuf> decrypted = makeReference<EncryptBuf>(allocSize, arena);
|
Reference<EncryptBuf> decrypted = makeReference<EncryptBuf>(allocSize, arena);
|
||||||
|
|
||||||
if (header.flags.authTokenMode != ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE) {
|
if (header.flags.authTokenMode != EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE) {
|
||||||
verifyAuthTokens(ciphertext, ciphertextLen, header, decrypted->begin(), arena);
|
verifyAuthTokens(ciphertext, ciphertextLen, header, arena);
|
||||||
ASSERT(authTokensValidationDone);
|
ASSERT(authTokensValidationDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,7 +894,13 @@ Reference<EncryptBuf> DecryptBlobCipherAes256Ctr::decrypt(const uint8_t* ciphert
|
||||||
BlobCipherMetrics::counters(usageType).decryptCPUTimeNS += int64_t((timer_monotonic() - startTime) * 1e9);
|
BlobCipherMetrics::counters(usageType).decryptCPUTimeNS += int64_t((timer_monotonic() - startTime) * 1e9);
|
||||||
}
|
}
|
||||||
|
|
||||||
CODE_PROBE(true, "Decrypting data with BlobCipher");
|
CODE_PROBE(true, "BlobCipher data decryption");
|
||||||
|
CODE_PROBE(header.flags.authTokenAlgo == EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE,
|
||||||
|
"Decryption authentication disabled");
|
||||||
|
CODE_PROBE(header.flags.authTokenAlgo == EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA,
|
||||||
|
"Decryption HMAC_SHA Auth token verification");
|
||||||
|
CODE_PROBE(header.flags.authTokenAlgo == EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_AES_CMAC,
|
||||||
|
"Decryption AES_CMAC Auth token verification");
|
||||||
|
|
||||||
return decrypted;
|
return decrypted;
|
||||||
}
|
}
|
||||||
|
@ -874,14 +925,15 @@ HmacSha256DigestGen::~HmacSha256DigestGen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int HmacSha256DigestGen::digest(const unsigned char* data,
|
unsigned int HmacSha256DigestGen::digest(const std::vector<std::pair<const uint8_t*, size_t>>& payload,
|
||||||
size_t len,
|
|
||||||
unsigned char* buf,
|
unsigned char* buf,
|
||||||
unsigned int bufLen) {
|
unsigned int bufLen) {
|
||||||
ASSERT_EQ(bufLen, HMAC_size(ctx));
|
ASSERT_EQ(bufLen, HMAC_size(ctx));
|
||||||
|
|
||||||
if (HMAC_Update(ctx, data, len) != 1) {
|
for (const auto& p : payload) {
|
||||||
throw encrypt_ops_error();
|
if (HMAC_Update(ctx, p.first, p.second) != 1) {
|
||||||
|
throw encrypt_ops_error();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int digestLen = 0;
|
unsigned int digestLen = 0;
|
||||||
|
@ -889,23 +941,84 @@ unsigned int HmacSha256DigestGen::digest(const unsigned char* data,
|
||||||
throw encrypt_ops_error();
|
throw encrypt_ops_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
CODE_PROBE(true, "Digest generation");
|
CODE_PROBE(true, "HMAC_SHA Digest generation");
|
||||||
|
|
||||||
return digestLen;
|
return digestLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
void computeAuthToken(const uint8_t* payload,
|
// Aes256CtrCmacDigestGen methods
|
||||||
const int payloadLen,
|
Aes256CmacDigestGen::Aes256CmacDigestGen(const unsigned char* key, size_t keylen) : ctx(CMAC_CTX_new()) {
|
||||||
|
ASSERT_EQ(keylen, AES_256_KEY_LENGTH);
|
||||||
|
|
||||||
|
if (ctx == nullptr) {
|
||||||
|
throw encrypt_ops_error();
|
||||||
|
}
|
||||||
|
if (!CMAC_Init(ctx, key, keylen, EVP_aes_256_cbc(), NULL)) {
|
||||||
|
throw encrypt_ops_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Aes256CmacDigestGen::digest(const std::vector<std::pair<const uint8_t*, size_t>>& payload,
|
||||||
|
uint8_t* digest,
|
||||||
|
int digestlen) {
|
||||||
|
ASSERT(ctx != nullptr);
|
||||||
|
ASSERT_GE(digestlen, AUTH_TOKEN_AES_CMAC_SIZE);
|
||||||
|
|
||||||
|
for (const auto& p : payload) {
|
||||||
|
if (!CMAC_Update(ctx, p.first, p.second)) {
|
||||||
|
throw encrypt_ops_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t ret;
|
||||||
|
if (!CMAC_Final(ctx, digest, &ret)) {
|
||||||
|
throw encrypt_ops_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Aes256CmacDigestGen::~Aes256CmacDigestGen() {
|
||||||
|
if (ctx != nullptr) {
|
||||||
|
CMAC_CTX_free(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeAuthToken(const std::vector<std::pair<const uint8_t*, size_t>>& payload,
|
||||||
const uint8_t* key,
|
const uint8_t* key,
|
||||||
const int keyLen,
|
const int keyLen,
|
||||||
unsigned char* digestBuf,
|
unsigned char* digestBuf,
|
||||||
unsigned int digestBufSz) {
|
const EncryptAuthTokenAlgo algo,
|
||||||
HmacSha256DigestGen hmacGenerator(key, keyLen);
|
unsigned int digestBufMaxSz) {
|
||||||
unsigned int digestLen = hmacGenerator.digest(payload, payloadLen, digestBuf, digestBufSz);
|
ASSERT_EQ(digestBufMaxSz, AUTH_TOKEN_MAX_SIZE);
|
||||||
|
ASSERT(isEncryptHeaderAuthTokenAlgoValid(algo));
|
||||||
|
|
||||||
ASSERT_EQ(digestLen, digestBufSz);
|
int authTokenSz = getEncryptHeaderAuthTokenSize(algo);
|
||||||
|
ASSERT_LE(authTokenSz, AUTH_TOKEN_MAX_SIZE);
|
||||||
|
|
||||||
CODE_PROBE(true, "Auth token generation");
|
if (algo == EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA) {
|
||||||
|
ASSERT_EQ(authTokenSz, AUTH_TOKEN_HMAC_SHA_SIZE);
|
||||||
|
|
||||||
|
HmacSha256DigestGen hmacGenerator(key, keyLen);
|
||||||
|
unsigned int digestLen = hmacGenerator.digest(payload, digestBuf, authTokenSz);
|
||||||
|
|
||||||
|
ASSERT_EQ(digestLen, authTokenSz);
|
||||||
|
} else if (algo == EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_AES_CMAC) {
|
||||||
|
ASSERT_EQ(authTokenSz, AUTH_TOKEN_AES_CMAC_SIZE);
|
||||||
|
ASSERT_EQ(keyLen, AES_256_KEY_LENGTH);
|
||||||
|
|
||||||
|
Aes256CmacDigestGen cmacGenerator(key, keyLen);
|
||||||
|
size_t digestLen = cmacGenerator.digest(payload, digestBuf, authTokenSz);
|
||||||
|
|
||||||
|
ASSERT_EQ(digestLen, authTokenSz);
|
||||||
|
} else {
|
||||||
|
throw not_implemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptAuthTokenMode getEncryptAuthTokenMode(const EncryptAuthTokenMode mode) {
|
||||||
|
// Override mode if authToken isn't enabled
|
||||||
|
return FLOW_KNOBS->ENCRYPT_HEADER_AUTH_TOKEN_ENABLED ? mode
|
||||||
|
: EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only used to link unit tests
|
// Only used to link unit tests
|
||||||
|
@ -1075,13 +1188,13 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
BlobCipherEncryptHeader headerCopy;
|
BlobCipherEncryptHeader headerCopy;
|
||||||
// validate basic encrypt followed by decrypt operation for AUTH_MODE_NONE
|
// validate basic encrypt followed by decrypt operation for AUTH_MODE_NONE
|
||||||
{
|
{
|
||||||
TraceEvent("NoneAuthModeStart").log();
|
TraceEvent("NoneAuthModeStart");
|
||||||
|
|
||||||
EncryptBlobCipherAes265Ctr encryptor(cipherKey,
|
EncryptBlobCipherAes265Ctr encryptor(cipherKey,
|
||||||
Reference<BlobCipherKey>(),
|
headerCipherKey,
|
||||||
iv,
|
iv,
|
||||||
AES_256_IV_LENGTH,
|
AES_256_IV_LENGTH,
|
||||||
ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE,
|
EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE,
|
||||||
BlobCipherMetrics::TEST);
|
BlobCipherMetrics::TEST);
|
||||||
BlobCipherEncryptHeader header;
|
BlobCipherEncryptHeader header;
|
||||||
Reference<EncryptBuf> encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
Reference<EncryptBuf> encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
@ -1089,12 +1202,14 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
ASSERT_EQ(encrypted->getLogicalSize(), bufLen);
|
ASSERT_EQ(encrypted->getLogicalSize(), bufLen);
|
||||||
ASSERT_NE(memcmp(&orgData[0], encrypted->begin(), bufLen), 0);
|
ASSERT_NE(memcmp(&orgData[0], encrypted->begin(), bufLen), 0);
|
||||||
ASSERT_EQ(header.flags.headerVersion, EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION);
|
ASSERT_EQ(header.flags.headerVersion, EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION);
|
||||||
ASSERT_EQ(header.flags.encryptMode, ENCRYPT_CIPHER_MODE_AES_256_CTR);
|
ASSERT_EQ(header.flags.encryptMode, EncryptCipherMode::ENCRYPT_CIPHER_MODE_AES_256_CTR);
|
||||||
ASSERT_EQ(header.flags.authTokenMode, ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE);
|
ASSERT_EQ(header.flags.authTokenMode, EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE);
|
||||||
|
|
||||||
TraceEvent("BlobCipherTestEncryptDone")
|
TraceEvent("BlobCipherTestEncryptDone")
|
||||||
.detail("HeaderVersion", header.flags.headerVersion)
|
.detail("HeaderVersion", header.flags.headerVersion)
|
||||||
.detail("HeaderEncryptMode", header.flags.encryptMode)
|
.detail("HeaderEncryptMode", header.flags.encryptMode)
|
||||||
|
.detail("HeaderEncryptAuthTokenMode", header.flags.authTokenMode)
|
||||||
|
.detail("HeaderEncryptAuthTokenAlgo", header.flags.authTokenAlgo)
|
||||||
.detail("DomainId", header.cipherTextDetails.encryptDomainId)
|
.detail("DomainId", header.cipherTextDetails.encryptDomainId)
|
||||||
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId);
|
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId);
|
||||||
|
|
||||||
|
@ -1109,7 +1224,7 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
ASSERT_EQ(decrypted->getLogicalSize(), bufLen);
|
ASSERT_EQ(decrypted->getLogicalSize(), bufLen);
|
||||||
ASSERT_EQ(memcmp(decrypted->begin(), &orgData[0], bufLen), 0);
|
ASSERT_EQ(memcmp(decrypted->begin(), &orgData[0], bufLen), 0);
|
||||||
|
|
||||||
TraceEvent("BlobCipherTestDecryptDone").log();
|
TraceEvent("BlobCipherTestDecryptDone");
|
||||||
|
|
||||||
// induce encryption header corruption - headerVersion corrupted
|
// induce encryption header corruption - headerVersion corrupted
|
||||||
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
|
@ -1160,18 +1275,20 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceEvent("NoneAuthMode.Done").log();
|
TraceEvent("NoneAuthModeDone");
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate basic encrypt followed by decrypt operation for AUTH_TOKEN_MODE_SINGLE
|
// validate basic encrypt followed by decrypt operation for AUTH_TOKEN_MODE_SINGLE
|
||||||
|
// HMAC_SHA authToken algorithm
|
||||||
{
|
{
|
||||||
TraceEvent("SingleAuthMode.Start").log();
|
TraceEvent("SingleAuthModeHmacShaStart").log();
|
||||||
|
|
||||||
EncryptBlobCipherAes265Ctr encryptor(cipherKey,
|
EncryptBlobCipherAes265Ctr encryptor(cipherKey,
|
||||||
headerCipherKey,
|
headerCipherKey,
|
||||||
iv,
|
iv,
|
||||||
AES_256_IV_LENGTH,
|
AES_256_IV_LENGTH,
|
||||||
ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE,
|
EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE,
|
||||||
|
EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA,
|
||||||
BlobCipherMetrics::TEST);
|
BlobCipherMetrics::TEST);
|
||||||
BlobCipherEncryptHeader header;
|
BlobCipherEncryptHeader header;
|
||||||
Reference<EncryptBuf> encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
Reference<EncryptBuf> encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
@ -1180,15 +1297,130 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
ASSERT_NE(memcmp(&orgData[0], encrypted->begin(), bufLen), 0);
|
ASSERT_NE(memcmp(&orgData[0], encrypted->begin(), bufLen), 0);
|
||||||
ASSERT_EQ(header.flags.headerVersion, EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION);
|
ASSERT_EQ(header.flags.headerVersion, EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION);
|
||||||
ASSERT_EQ(header.flags.encryptMode, ENCRYPT_CIPHER_MODE_AES_256_CTR);
|
ASSERT_EQ(header.flags.encryptMode, ENCRYPT_CIPHER_MODE_AES_256_CTR);
|
||||||
ASSERT_EQ(header.flags.authTokenMode, ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE);
|
ASSERT_EQ(header.flags.authTokenMode, EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE);
|
||||||
|
ASSERT_EQ(header.flags.authTokenAlgo, EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA);
|
||||||
|
|
||||||
TraceEvent("BlobCipherTestEncryptDone")
|
TraceEvent("BlobCipherTestEncryptDone")
|
||||||
.detail("HeaderVersion", header.flags.headerVersion)
|
.detail("HeaderVersion", header.flags.headerVersion)
|
||||||
.detail("HeaderEncryptMode", header.flags.encryptMode)
|
.detail("HeaderEncryptMode", header.flags.encryptMode)
|
||||||
|
.detail("HeaderEncryptAuthTokenMode", header.flags.authTokenMode)
|
||||||
|
.detail("HeaderEncryptAuthTokenAlgo", header.flags.authTokenAlgo)
|
||||||
.detail("DomainId", header.cipherTextDetails.encryptDomainId)
|
.detail("DomainId", header.cipherTextDetails.encryptDomainId)
|
||||||
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId)
|
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId)
|
||||||
.detail("HeaderAuthToken",
|
.detail("HeaderAuthToken",
|
||||||
StringRef(arena, &header.singleAuthToken.authToken[0], AUTH_TOKEN_SIZE).toString());
|
StringRef(arena, &header.singleAuthToken.authToken[0], AUTH_TOKEN_HMAC_SHA_SIZE).toString());
|
||||||
|
|
||||||
|
Reference<BlobCipherKey> tCipherKeyKey = cipherKeyCache->getCipherKey(header.cipherTextDetails.encryptDomainId,
|
||||||
|
header.cipherTextDetails.baseCipherId,
|
||||||
|
header.cipherTextDetails.salt);
|
||||||
|
Reference<BlobCipherKey> hCipherKey = cipherKeyCache->getCipherKey(header.cipherHeaderDetails.encryptDomainId,
|
||||||
|
header.cipherHeaderDetails.baseCipherId,
|
||||||
|
header.cipherHeaderDetails.salt);
|
||||||
|
ASSERT(tCipherKeyKey->isEqual(cipherKey));
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKeyKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
Reference<EncryptBuf> decrypted = decryptor.decrypt(encrypted->begin(), bufLen, header, arena);
|
||||||
|
|
||||||
|
ASSERT_EQ(decrypted->getLogicalSize(), bufLen);
|
||||||
|
ASSERT_EQ(memcmp(decrypted->begin(), &orgData[0], bufLen), 0);
|
||||||
|
|
||||||
|
TraceEvent("BlobCipherTestDecryptDone");
|
||||||
|
|
||||||
|
// induce encryption header corruption - headerVersion corrupted
|
||||||
|
encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
|
sizeof(BlobCipherEncryptHeader));
|
||||||
|
headerCopy.flags.headerVersion += 1;
|
||||||
|
try {
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKeyKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
decrypted = decryptor.decrypt(encrypted->begin(), bufLen, headerCopy, arena);
|
||||||
|
ASSERT(false); // error expected
|
||||||
|
} catch (Error& e) {
|
||||||
|
if (e.code() != error_code_encrypt_header_metadata_mismatch) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// induce encryption header corruption - encryptionMode corrupted
|
||||||
|
encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
|
sizeof(BlobCipherEncryptHeader));
|
||||||
|
headerCopy.flags.encryptMode += 1;
|
||||||
|
try {
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKeyKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
decrypted = decryptor.decrypt(encrypted->begin(), bufLen, headerCopy, arena);
|
||||||
|
ASSERT(false); // error expected
|
||||||
|
} catch (Error& e) {
|
||||||
|
if (e.code() != error_code_encrypt_header_metadata_mismatch) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// induce encryption header corruption - authToken mismatch
|
||||||
|
encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
|
sizeof(BlobCipherEncryptHeader));
|
||||||
|
int hIdx = deterministicRandom()->randomInt(0, AUTH_TOKEN_HMAC_SHA_SIZE - 1);
|
||||||
|
headerCopy.singleAuthToken.authToken[hIdx] += 1;
|
||||||
|
try {
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKeyKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
decrypted = decryptor.decrypt(encrypted->begin(), bufLen, headerCopy, arena);
|
||||||
|
ASSERT(false); // error expected
|
||||||
|
} catch (Error& e) {
|
||||||
|
if (e.code() != error_code_encrypt_header_authtoken_mismatch) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// induce encrypted buffer payload corruption
|
||||||
|
try {
|
||||||
|
encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
uint8_t temp[bufLen];
|
||||||
|
memcpy(encrypted->begin(), &temp[0], bufLen);
|
||||||
|
int tIdx = deterministicRandom()->randomInt(0, bufLen - 1);
|
||||||
|
temp[tIdx] += 1;
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKeyKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
decrypted = decryptor.decrypt(&temp[0], bufLen, header, arena);
|
||||||
|
} catch (Error& e) {
|
||||||
|
if (e.code() != error_code_encrypt_header_authtoken_mismatch) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceEvent("SingleAuthModeHmacShaDone");
|
||||||
|
}
|
||||||
|
// AES_CMAC authToken algorithm
|
||||||
|
{
|
||||||
|
TraceEvent("SingleAuthModeAesCMacStart").log();
|
||||||
|
|
||||||
|
EncryptBlobCipherAes265Ctr encryptor(cipherKey,
|
||||||
|
headerCipherKey,
|
||||||
|
iv,
|
||||||
|
AES_256_IV_LENGTH,
|
||||||
|
EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE,
|
||||||
|
EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_AES_CMAC,
|
||||||
|
BlobCipherMetrics::TEST);
|
||||||
|
BlobCipherEncryptHeader header;
|
||||||
|
Reference<EncryptBuf> encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
|
||||||
|
ASSERT_EQ(encrypted->getLogicalSize(), bufLen);
|
||||||
|
ASSERT_NE(memcmp(&orgData[0], encrypted->begin(), bufLen), 0);
|
||||||
|
ASSERT_EQ(header.flags.headerVersion, EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION);
|
||||||
|
ASSERT_EQ(header.flags.encryptMode, ENCRYPT_CIPHER_MODE_AES_256_CTR);
|
||||||
|
ASSERT_EQ(header.flags.authTokenMode, EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE);
|
||||||
|
ASSERT_EQ(header.flags.authTokenAlgo, EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_AES_CMAC);
|
||||||
|
|
||||||
|
TraceEvent("BlobCipherTestEncryptDone")
|
||||||
|
.detail("HeaderVersion", header.flags.headerVersion)
|
||||||
|
.detail("HeaderEncryptMode", header.flags.encryptMode)
|
||||||
|
.detail("HeaderEncryptAuthTokenMode", header.flags.authTokenMode)
|
||||||
|
.detail("HeaderEncryptAuthTokenAlgo", header.flags.authTokenAlgo)
|
||||||
|
.detail("DomainId", header.cipherTextDetails.encryptDomainId)
|
||||||
|
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId)
|
||||||
|
.detail("HeaderAuthToken",
|
||||||
|
StringRef(arena, &header.singleAuthToken.authToken[0], AUTH_TOKEN_AES_CMAC_SIZE).toString());
|
||||||
|
|
||||||
Reference<BlobCipherKey> tCipherKeyKey = cipherKeyCache->getCipherKey(header.cipherTextDetails.encryptDomainId,
|
Reference<BlobCipherKey> tCipherKeyKey = cipherKeyCache->getCipherKey(header.cipherTextDetails.encryptDomainId,
|
||||||
header.cipherTextDetails.baseCipherId,
|
header.cipherTextDetails.baseCipherId,
|
||||||
|
@ -1242,7 +1474,7 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
reinterpret_cast<const uint8_t*>(&header),
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
sizeof(BlobCipherEncryptHeader));
|
sizeof(BlobCipherEncryptHeader));
|
||||||
int hIdx = deterministicRandom()->randomInt(0, AUTH_TOKEN_SIZE - 1);
|
int hIdx = deterministicRandom()->randomInt(0, AUTH_TOKEN_AES_CMAC_SIZE - 1);
|
||||||
headerCopy.singleAuthToken.authToken[hIdx] += 1;
|
headerCopy.singleAuthToken.authToken[hIdx] += 1;
|
||||||
try {
|
try {
|
||||||
DecryptBlobCipherAes256Ctr decryptor(tCipherKeyKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKeyKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
@ -1269,18 +1501,20 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceEvent("SingleAuthModeDone").log();
|
TraceEvent("SingleAuthModeAesCmacDone");
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate basic encrypt followed by decrypt operation for AUTH_TOKEN_MODE_MULTI
|
// validate basic encrypt followed by decrypt operation for AUTH_TOKEN_MODE_MULTI
|
||||||
|
// HMAC_SHA authToken algorithm
|
||||||
{
|
{
|
||||||
TraceEvent("MultiAuthModeStart").log();
|
TraceEvent("MultiAuthModeHmacShaStart").log();
|
||||||
|
|
||||||
EncryptBlobCipherAes265Ctr encryptor(cipherKey,
|
EncryptBlobCipherAes265Ctr encryptor(cipherKey,
|
||||||
headerCipherKey,
|
headerCipherKey,
|
||||||
iv,
|
iv,
|
||||||
AES_256_IV_LENGTH,
|
AES_256_IV_LENGTH,
|
||||||
ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI,
|
EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI,
|
||||||
|
EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA,
|
||||||
BlobCipherMetrics::TEST);
|
BlobCipherMetrics::TEST);
|
||||||
BlobCipherEncryptHeader header;
|
BlobCipherEncryptHeader header;
|
||||||
Reference<EncryptBuf> encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
Reference<EncryptBuf> encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
@ -1290,14 +1524,17 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
ASSERT_EQ(header.flags.headerVersion, EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION);
|
ASSERT_EQ(header.flags.headerVersion, EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION);
|
||||||
ASSERT_EQ(header.flags.encryptMode, ENCRYPT_CIPHER_MODE_AES_256_CTR);
|
ASSERT_EQ(header.flags.encryptMode, ENCRYPT_CIPHER_MODE_AES_256_CTR);
|
||||||
ASSERT_EQ(header.flags.authTokenMode, ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI);
|
ASSERT_EQ(header.flags.authTokenMode, ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI);
|
||||||
|
ASSERT_EQ(header.flags.authTokenAlgo, EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA);
|
||||||
|
|
||||||
TraceEvent("BlobCipherTestEncryptDone")
|
TraceEvent("BlobCipherTestEncryptDone")
|
||||||
.detail("HeaderVersion", header.flags.headerVersion)
|
.detail("HeaderVersion", header.flags.headerVersion)
|
||||||
.detail("HeaderEncryptMode", header.flags.encryptMode)
|
.detail("HeaderEncryptMode", header.flags.encryptMode)
|
||||||
|
.detail("HeaderEncryptAuthTokenMode", header.flags.authTokenMode)
|
||||||
|
.detail("HeaderEncryptAuthTokenAlgo", header.flags.authTokenAlgo)
|
||||||
.detail("DomainId", header.cipherTextDetails.encryptDomainId)
|
.detail("DomainId", header.cipherTextDetails.encryptDomainId)
|
||||||
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId)
|
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId)
|
||||||
.detail("HeaderAuthToken",
|
.detail("HeaderAuthToken",
|
||||||
StringRef(arena, &header.singleAuthToken.authToken[0], AUTH_TOKEN_SIZE).toString());
|
StringRef(arena, &header.singleAuthToken.authToken[0], AUTH_TOKEN_HMAC_SHA_SIZE).toString());
|
||||||
|
|
||||||
Reference<BlobCipherKey> tCipherKey = cipherKeyCache->getCipherKey(header.cipherTextDetails.encryptDomainId,
|
Reference<BlobCipherKey> tCipherKey = cipherKeyCache->getCipherKey(header.cipherTextDetails.encryptDomainId,
|
||||||
header.cipherTextDetails.baseCipherId,
|
header.cipherTextDetails.baseCipherId,
|
||||||
|
@ -1352,7 +1589,7 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
reinterpret_cast<const uint8_t*>(&header),
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
sizeof(BlobCipherEncryptHeader));
|
sizeof(BlobCipherEncryptHeader));
|
||||||
int hIdx = deterministicRandom()->randomInt(0, AUTH_TOKEN_SIZE - 1);
|
int hIdx = deterministicRandom()->randomInt(0, AUTH_TOKEN_HMAC_SHA_SIZE - 1);
|
||||||
headerCopy.multiAuthTokens.cipherTextAuthToken[hIdx] += 1;
|
headerCopy.multiAuthTokens.cipherTextAuthToken[hIdx] += 1;
|
||||||
try {
|
try {
|
||||||
DecryptBlobCipherAes256Ctr decryptor(tCipherKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
@ -1369,7 +1606,7 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
reinterpret_cast<const uint8_t*>(&header),
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
sizeof(BlobCipherEncryptHeader));
|
sizeof(BlobCipherEncryptHeader));
|
||||||
hIdx = deterministicRandom()->randomInt(0, AUTH_TOKEN_SIZE - 1);
|
hIdx = deterministicRandom()->randomInt(0, AUTH_TOKEN_HMAC_SHA_SIZE - 1);
|
||||||
headerCopy.multiAuthTokens.headerAuthToken[hIdx] += 1;
|
headerCopy.multiAuthTokens.headerAuthToken[hIdx] += 1;
|
||||||
try {
|
try {
|
||||||
DecryptBlobCipherAes256Ctr decryptor(tCipherKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
@ -1395,7 +1632,136 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceEvent("MultiAuthModeDone").log();
|
TraceEvent("MultiAuthModeHmacShaDone");
|
||||||
|
}
|
||||||
|
// AES_CMAC authToken algorithm
|
||||||
|
{
|
||||||
|
TraceEvent("MultiAuthModeAesCmacStart");
|
||||||
|
|
||||||
|
EncryptBlobCipherAes265Ctr encryptor(cipherKey,
|
||||||
|
headerCipherKey,
|
||||||
|
iv,
|
||||||
|
AES_256_IV_LENGTH,
|
||||||
|
EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI,
|
||||||
|
EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_AES_CMAC,
|
||||||
|
BlobCipherMetrics::TEST);
|
||||||
|
BlobCipherEncryptHeader header;
|
||||||
|
Reference<EncryptBuf> encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
|
||||||
|
ASSERT_EQ(encrypted->getLogicalSize(), bufLen);
|
||||||
|
ASSERT_NE(memcmp(&orgData[0], encrypted->begin(), bufLen), 0);
|
||||||
|
ASSERT_EQ(header.flags.headerVersion, EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION);
|
||||||
|
ASSERT_EQ(header.flags.encryptMode, ENCRYPT_CIPHER_MODE_AES_256_CTR);
|
||||||
|
ASSERT_EQ(header.flags.authTokenMode, ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI);
|
||||||
|
ASSERT_EQ(header.flags.authTokenAlgo, EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_AES_CMAC);
|
||||||
|
|
||||||
|
TraceEvent("BlobCipherTestEncryptDone")
|
||||||
|
.detail("HeaderVersion", header.flags.headerVersion)
|
||||||
|
.detail("HeaderEncryptMode", header.flags.encryptMode)
|
||||||
|
.detail("HeaderEncryptAuthTokenMode", header.flags.authTokenMode)
|
||||||
|
.detail("HeaderEncryptAuthTokenAlgo", header.flags.authTokenAlgo)
|
||||||
|
.detail("DomainId", header.cipherTextDetails.encryptDomainId)
|
||||||
|
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId)
|
||||||
|
.detail("HeaderAuthToken",
|
||||||
|
StringRef(arena, &header.singleAuthToken.authToken[0], AUTH_TOKEN_AES_CMAC_SIZE).toString());
|
||||||
|
|
||||||
|
Reference<BlobCipherKey> tCipherKey = cipherKeyCache->getCipherKey(header.cipherTextDetails.encryptDomainId,
|
||||||
|
header.cipherTextDetails.baseCipherId,
|
||||||
|
header.cipherTextDetails.salt);
|
||||||
|
Reference<BlobCipherKey> hCipherKey = cipherKeyCache->getCipherKey(header.cipherHeaderDetails.encryptDomainId,
|
||||||
|
header.cipherHeaderDetails.baseCipherId,
|
||||||
|
header.cipherHeaderDetails.salt);
|
||||||
|
|
||||||
|
ASSERT(tCipherKey->isEqual(cipherKey));
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
Reference<EncryptBuf> decrypted = decryptor.decrypt(encrypted->begin(), bufLen, header, arena);
|
||||||
|
|
||||||
|
ASSERT_EQ(decrypted->getLogicalSize(), bufLen);
|
||||||
|
ASSERT_EQ(memcmp(decrypted->begin(), &orgData[0], bufLen), 0);
|
||||||
|
|
||||||
|
TraceEvent("BlobCipherTestDecryptDone").log();
|
||||||
|
|
||||||
|
// induce encryption header corruption - headerVersion corrupted
|
||||||
|
encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
|
sizeof(BlobCipherEncryptHeader));
|
||||||
|
headerCopy.flags.headerVersion += 1;
|
||||||
|
try {
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
decrypted = decryptor.decrypt(encrypted->begin(), bufLen, headerCopy, arena);
|
||||||
|
ASSERT(false); // error expected
|
||||||
|
} catch (Error& e) {
|
||||||
|
if (e.code() != error_code_encrypt_header_metadata_mismatch) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// induce encryption header corruption - encryptionMode corrupted
|
||||||
|
encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
|
sizeof(BlobCipherEncryptHeader));
|
||||||
|
headerCopy.flags.encryptMode += 1;
|
||||||
|
try {
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
decrypted = decryptor.decrypt(encrypted->begin(), bufLen, headerCopy, arena);
|
||||||
|
ASSERT(false); // error expected
|
||||||
|
} catch (Error& e) {
|
||||||
|
if (e.code() != error_code_encrypt_header_metadata_mismatch) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// induce encryption header corruption - cipherText authToken mismatch
|
||||||
|
encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
|
sizeof(BlobCipherEncryptHeader));
|
||||||
|
int hIdx = deterministicRandom()->randomInt(0, AUTH_TOKEN_AES_CMAC_SIZE - 1);
|
||||||
|
headerCopy.multiAuthTokens.cipherTextAuthToken[hIdx] += 1;
|
||||||
|
try {
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
decrypted = decryptor.decrypt(encrypted->begin(), bufLen, headerCopy, arena);
|
||||||
|
ASSERT(false); // error expected
|
||||||
|
} catch (Error& e) {
|
||||||
|
if (e.code() != error_code_encrypt_header_authtoken_mismatch) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// induce encryption header corruption - header authToken mismatch
|
||||||
|
encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
memcpy(reinterpret_cast<uint8_t*>(&headerCopy),
|
||||||
|
reinterpret_cast<const uint8_t*>(&header),
|
||||||
|
sizeof(BlobCipherEncryptHeader));
|
||||||
|
hIdx = deterministicRandom()->randomInt(0, AUTH_TOKEN_AES_CMAC_SIZE - 1);
|
||||||
|
headerCopy.multiAuthTokens.headerAuthToken[hIdx] += 1;
|
||||||
|
try {
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
decrypted = decryptor.decrypt(encrypted->begin(), bufLen, headerCopy, arena);
|
||||||
|
ASSERT(false); // error expected
|
||||||
|
} catch (Error& e) {
|
||||||
|
if (e.code() != error_code_encrypt_header_authtoken_mismatch) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
encrypted = encryptor.encrypt(&orgData[0], bufLen, &header, arena);
|
||||||
|
uint8_t temp[bufLen];
|
||||||
|
memcpy(encrypted->begin(), &temp[0], bufLen);
|
||||||
|
int tIdx = deterministicRandom()->randomInt(0, bufLen - 1);
|
||||||
|
temp[tIdx] += 1;
|
||||||
|
DecryptBlobCipherAes256Ctr decryptor(tCipherKey, hCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
|
decrypted = decryptor.decrypt(&temp[0], bufLen, header, arena);
|
||||||
|
} catch (Error& e) {
|
||||||
|
if (e.code() != error_code_encrypt_header_authtoken_mismatch) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceEvent("MultiAuthModeAesCmacDone");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate dropping encryptDomainId cached keys
|
// Validate dropping encryptDomainId cached keys
|
||||||
|
@ -1411,6 +1777,6 @@ TEST_CASE("flow/BlobCipher") {
|
||||||
ASSERT(cachedKeys.empty());
|
ASSERT(cachedKeys.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceEvent("BlobCipherTestDone").log();
|
TraceEvent("BlobCipherTestDone");
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,9 @@
|
||||||
#include "flow/Arena.h"
|
#include "flow/Arena.h"
|
||||||
#include "flow/CompressionUtils.h"
|
#include "flow/CompressionUtils.h"
|
||||||
#include "flow/DeterministicRandom.h"
|
#include "flow/DeterministicRandom.h"
|
||||||
|
#include "flow/EncryptUtils.h"
|
||||||
#include "flow/IRandom.h"
|
#include "flow/IRandom.h"
|
||||||
|
#include "flow/Knobs.h"
|
||||||
#include "flow/Trace.h"
|
#include "flow/Trace.h"
|
||||||
#include "flow/serialize.h"
|
#include "flow/serialize.h"
|
||||||
#include "flow/UnitTest.h"
|
#include "flow/UnitTest.h"
|
||||||
|
@ -285,12 +287,13 @@ struct IndexBlockRef {
|
||||||
TraceEvent(SevDebug, "IndexBlockEncrypt_Before").detail("Chksum", chksum);
|
TraceEvent(SevDebug, "IndexBlockEncrypt_Before").detail("Chksum", chksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
EncryptBlobCipherAes265Ctr encryptor(eKeys.textCipherKey,
|
EncryptBlobCipherAes265Ctr encryptor(
|
||||||
eKeys.headerCipherKey,
|
eKeys.textCipherKey,
|
||||||
cipherKeysCtx.ivRef.begin(),
|
eKeys.headerCipherKey,
|
||||||
AES_256_IV_LENGTH,
|
cipherKeysCtx.ivRef.begin(),
|
||||||
ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE,
|
AES_256_IV_LENGTH,
|
||||||
BlobCipherMetrics::BLOB_GRANULE);
|
getEncryptAuthTokenMode(EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE),
|
||||||
|
BlobCipherMetrics::BLOB_GRANULE);
|
||||||
Value serializedBuff = ObjectWriter::toValue(block, IncludeVersion(ProtocolVersion::withBlobGranuleFile()));
|
Value serializedBuff = ObjectWriter::toValue(block, IncludeVersion(ProtocolVersion::withBlobGranuleFile()));
|
||||||
BlobCipherEncryptHeader header;
|
BlobCipherEncryptHeader header;
|
||||||
buffer = encryptor.encrypt(serializedBuff.contents().begin(), serializedBuff.contents().size(), &header, arena)
|
buffer = encryptor.encrypt(serializedBuff.contents().begin(), serializedBuff.contents().size(), &header, arena)
|
||||||
|
@ -408,12 +411,13 @@ struct IndexBlobGranuleFileChunkRef {
|
||||||
TraceEvent(SevDebug, "BlobChunkEncrypt_Before").detail("Chksum", chksum);
|
TraceEvent(SevDebug, "BlobChunkEncrypt_Before").detail("Chksum", chksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
EncryptBlobCipherAes265Ctr encryptor(eKeys.textCipherKey,
|
EncryptBlobCipherAes265Ctr encryptor(
|
||||||
eKeys.headerCipherKey,
|
eKeys.textCipherKey,
|
||||||
cipherKeysCtx.ivRef.begin(),
|
eKeys.headerCipherKey,
|
||||||
AES_256_IV_LENGTH,
|
cipherKeysCtx.ivRef.begin(),
|
||||||
ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE,
|
AES_256_IV_LENGTH,
|
||||||
BlobCipherMetrics::BLOB_GRANULE);
|
getEncryptAuthTokenMode(EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE),
|
||||||
|
BlobCipherMetrics::BLOB_GRANULE);
|
||||||
BlobCipherEncryptHeader header;
|
BlobCipherEncryptHeader header;
|
||||||
chunkRef.buffer =
|
chunkRef.buffer =
|
||||||
encryptor.encrypt(chunkRef.buffer.begin(), chunkRef.buffer.size(), &header, arena)->toStringRef();
|
encryptor.encrypt(chunkRef.buffer.begin(), chunkRef.buffer.size(), &header, arena)->toStringRef();
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
|
#include <openssl/cmac.h>
|
||||||
#include <openssl/engine.h>
|
#include <openssl/engine.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
|
@ -192,7 +193,8 @@ typedef struct BlobCipherEncryptHeader {
|
||||||
uint8_t headerVersion{};
|
uint8_t headerVersion{};
|
||||||
uint8_t encryptMode{};
|
uint8_t encryptMode{};
|
||||||
uint8_t authTokenMode{};
|
uint8_t authTokenMode{};
|
||||||
uint8_t _reserved[4]{};
|
uint8_t authTokenAlgo{};
|
||||||
|
uint8_t _reserved[3]{};
|
||||||
} flags;
|
} flags;
|
||||||
uint64_t _padding{};
|
uint64_t _padding{};
|
||||||
};
|
};
|
||||||
|
@ -223,12 +225,12 @@ typedef struct BlobCipherEncryptHeader {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
// Cipher text authentication token
|
// Cipher text authentication token
|
||||||
uint8_t cipherTextAuthToken[AUTH_TOKEN_SIZE]{};
|
uint8_t cipherTextAuthToken[AUTH_TOKEN_MAX_SIZE]{};
|
||||||
uint8_t headerAuthToken[AUTH_TOKEN_SIZE]{};
|
uint8_t headerAuthToken[AUTH_TOKEN_MAX_SIZE]{};
|
||||||
} multiAuthTokens;
|
} multiAuthTokens;
|
||||||
struct {
|
struct {
|
||||||
uint8_t authToken[AUTH_TOKEN_SIZE]{};
|
uint8_t authToken[AUTH_TOKEN_MAX_SIZE]{};
|
||||||
uint8_t _reserved[AUTH_TOKEN_SIZE]{};
|
uint8_t _reserved[AUTH_TOKEN_MAX_SIZE]{};
|
||||||
} singleAuthToken;
|
} singleAuthToken;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -555,7 +557,19 @@ public:
|
||||||
BlobCipherMetrics::UsageType usageType);
|
BlobCipherMetrics::UsageType usageType);
|
||||||
EncryptBlobCipherAes265Ctr(Reference<BlobCipherKey> tCipherKey,
|
EncryptBlobCipherAes265Ctr(Reference<BlobCipherKey> tCipherKey,
|
||||||
Reference<BlobCipherKey> hCipherKey,
|
Reference<BlobCipherKey> hCipherKey,
|
||||||
|
const uint8_t* iv,
|
||||||
|
const int ivLen,
|
||||||
const EncryptAuthTokenMode mode,
|
const EncryptAuthTokenMode mode,
|
||||||
|
const EncryptAuthTokenAlgo algo,
|
||||||
|
BlobCipherMetrics::UsageType usageType);
|
||||||
|
EncryptBlobCipherAes265Ctr(Reference<BlobCipherKey> tCipherKey,
|
||||||
|
Reference<BlobCipherKey> hCipherKey,
|
||||||
|
const EncryptAuthTokenMode mode,
|
||||||
|
BlobCipherMetrics::UsageType usageType);
|
||||||
|
EncryptBlobCipherAes265Ctr(Reference<BlobCipherKey> tCipherKey,
|
||||||
|
Reference<BlobCipherKey> hCipherKey,
|
||||||
|
const EncryptAuthTokenMode mode,
|
||||||
|
const EncryptAuthTokenAlgo algo,
|
||||||
BlobCipherMetrics::UsageType usageType);
|
BlobCipherMetrics::UsageType usageType);
|
||||||
~EncryptBlobCipherAes265Ctr();
|
~EncryptBlobCipherAes265Ctr();
|
||||||
|
|
||||||
|
@ -571,6 +585,7 @@ private:
|
||||||
EncryptAuthTokenMode authTokenMode;
|
EncryptAuthTokenMode authTokenMode;
|
||||||
uint8_t iv[AES_256_IV_LENGTH];
|
uint8_t iv[AES_256_IV_LENGTH];
|
||||||
BlobCipherMetrics::UsageType usageType;
|
BlobCipherMetrics::UsageType usageType;
|
||||||
|
EncryptAuthTokenAlgo authTokenAlgo;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
};
|
};
|
||||||
|
@ -608,17 +623,14 @@ private:
|
||||||
void verifyAuthTokens(const uint8_t* ciphertext,
|
void verifyAuthTokens(const uint8_t* ciphertext,
|
||||||
const int ciphertextLen,
|
const int ciphertextLen,
|
||||||
const BlobCipherEncryptHeader& header,
|
const BlobCipherEncryptHeader& header,
|
||||||
uint8_t* buff,
|
|
||||||
Arena& arena);
|
Arena& arena);
|
||||||
void verifyHeaderSingleAuthToken(const uint8_t* ciphertext,
|
void verifyHeaderSingleAuthToken(const uint8_t* ciphertext,
|
||||||
const int ciphertextLen,
|
const int ciphertextLen,
|
||||||
const BlobCipherEncryptHeader& header,
|
const BlobCipherEncryptHeader& header,
|
||||||
uint8_t* buff,
|
|
||||||
Arena& arena);
|
Arena& arena);
|
||||||
void verifyHeaderMultiAuthToken(const uint8_t* ciphertext,
|
void verifyHeaderMultiAuthToken(const uint8_t* ciphertext,
|
||||||
const int ciphertextLen,
|
const int ciphertextLen,
|
||||||
const BlobCipherEncryptHeader& header,
|
const BlobCipherEncryptHeader& header,
|
||||||
uint8_t* buff,
|
|
||||||
Arena& arena);
|
Arena& arena);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -627,17 +639,32 @@ public:
|
||||||
HmacSha256DigestGen(const unsigned char* key, size_t len);
|
HmacSha256DigestGen(const unsigned char* key, size_t len);
|
||||||
~HmacSha256DigestGen();
|
~HmacSha256DigestGen();
|
||||||
HMAC_CTX* getCtx() const { return ctx; }
|
HMAC_CTX* getCtx() const { return ctx; }
|
||||||
unsigned int digest(unsigned char const* data, size_t len, unsigned char* buf, unsigned int bufLen);
|
unsigned int digest(const std::vector<std::pair<const uint8_t*, size_t>>& payload,
|
||||||
|
unsigned char* buf,
|
||||||
|
unsigned int bufLen);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HMAC_CTX* ctx;
|
HMAC_CTX* ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
void computeAuthToken(const uint8_t* payload,
|
class Aes256CmacDigestGen final : NonCopyable {
|
||||||
const int payloadLen,
|
public:
|
||||||
|
Aes256CmacDigestGen(const unsigned char* key, size_t len);
|
||||||
|
~Aes256CmacDigestGen();
|
||||||
|
CMAC_CTX* getCtx() const { return ctx; }
|
||||||
|
size_t digest(const std::vector<std::pair<const uint8_t*, size_t>>& payload, uint8_t* digest, int digestlen);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CMAC_CTX* ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
void computeAuthToken(const std::vector<std::pair<const uint8_t*, size_t>>& payload,
|
||||||
const uint8_t* key,
|
const uint8_t* key,
|
||||||
const int keyLen,
|
const int keyLen,
|
||||||
unsigned char* digestBuf,
|
unsigned char* digestBuf,
|
||||||
unsigned int digestBufSz);
|
const EncryptAuthTokenAlgo algo,
|
||||||
|
unsigned int digestMaxBufSz);
|
||||||
|
|
||||||
|
EncryptAuthTokenMode getEncryptAuthTokenMode(const EncryptAuthTokenMode mode);
|
||||||
|
|
||||||
#endif // FDBCLIENT_BLOB_CIPHER_H
|
#endif // FDBCLIENT_BLOB_CIPHER_H
|
|
@ -27,6 +27,8 @@
|
||||||
#include "fdbclient/GetEncryptCipherKeys.actor.h"
|
#include "fdbclient/GetEncryptCipherKeys.actor.h"
|
||||||
#include "fdbclient/Knobs.h"
|
#include "fdbclient/Knobs.h"
|
||||||
#include "fdbclient/Tracing.h"
|
#include "fdbclient/Tracing.h"
|
||||||
|
#include "flow/EncryptUtils.h"
|
||||||
|
#include "flow/Knobs.h"
|
||||||
|
|
||||||
// The versioned message has wire format : -1, version, messages
|
// The versioned message has wire format : -1, version, messages
|
||||||
static const int32_t VERSION_HEADER = -1;
|
static const int32_t VERSION_HEADER = -1;
|
||||||
|
@ -153,12 +155,13 @@ struct MutationRef {
|
||||||
deterministicRandom()->randomBytes(iv, AES_256_IV_LENGTH);
|
deterministicRandom()->randomBytes(iv, AES_256_IV_LENGTH);
|
||||||
BinaryWriter bw(AssumeVersion(ProtocolVersion::withEncryptionAtRest()));
|
BinaryWriter bw(AssumeVersion(ProtocolVersion::withEncryptionAtRest()));
|
||||||
bw << *this;
|
bw << *this;
|
||||||
EncryptBlobCipherAes265Ctr cipher(textCipherItr->second,
|
EncryptBlobCipherAes265Ctr cipher(
|
||||||
headerCipherItr->second,
|
textCipherItr->second,
|
||||||
iv,
|
headerCipherItr->second,
|
||||||
AES_256_IV_LENGTH,
|
iv,
|
||||||
ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE,
|
AES_256_IV_LENGTH,
|
||||||
usageType);
|
getEncryptAuthTokenMode(EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE),
|
||||||
|
usageType);
|
||||||
BlobCipherEncryptHeader* header = new (arena) BlobCipherEncryptHeader;
|
BlobCipherEncryptHeader* header = new (arena) BlobCipherEncryptHeader;
|
||||||
StringRef headerRef(reinterpret_cast<const uint8_t*>(header), sizeof(BlobCipherEncryptHeader));
|
StringRef headerRef(reinterpret_cast<const uint8_t*>(header), sizeof(BlobCipherEncryptHeader));
|
||||||
StringRef payload =
|
StringRef payload =
|
||||||
|
|
|
@ -411,7 +411,7 @@ ACTOR Future<Void> getCipherKeysByBaseCipherKeyIds(Reference<EncryptKeyProxyData
|
||||||
|
|
||||||
const auto itr = lookupCipherInfoMap.find(std::make_pair(item.encryptDomainId, item.encryptKeyId));
|
const auto itr = lookupCipherInfoMap.find(std::make_pair(item.encryptDomainId, item.encryptKeyId));
|
||||||
if (itr == lookupCipherInfoMap.end()) {
|
if (itr == lookupCipherInfoMap.end()) {
|
||||||
TraceEvent(SevError, "GetCipherKeysByKeyIds_MappingNotFound", ekpProxyData->myId)
|
TraceEvent(SevError, "GetCipherKeysByKeyIdsMappingNotFound", ekpProxyData->myId)
|
||||||
.detail("DomainId", item.encryptDomainId);
|
.detail("DomainId", item.encryptDomainId);
|
||||||
throw encrypt_keys_fetch_failed();
|
throw encrypt_keys_fetch_failed();
|
||||||
}
|
}
|
||||||
|
@ -546,7 +546,7 @@ ACTOR Future<Void> getLatestCipherKeys(Reference<EncryptKeyProxyData> ekpProxyDa
|
||||||
// Record the fetched cipher details to the local cache for the future references
|
// Record the fetched cipher details to the local cache for the future references
|
||||||
const auto itr = lookupCipherDomains.find(item.encryptDomainId);
|
const auto itr = lookupCipherDomains.find(item.encryptDomainId);
|
||||||
if (itr == lookupCipherDomains.end()) {
|
if (itr == lookupCipherDomains.end()) {
|
||||||
TraceEvent(SevError, "GetLatestCipherKeys_DomainIdNotFound", ekpProxyData->myId)
|
TraceEvent(SevError, "GetLatestCipherKeysDomainIdNotFound", ekpProxyData->myId)
|
||||||
.detail("DomainId", item.encryptDomainId);
|
.detail("DomainId", item.encryptDomainId);
|
||||||
throw encrypt_keys_fetch_failed();
|
throw encrypt_keys_fetch_failed();
|
||||||
}
|
}
|
||||||
|
@ -602,7 +602,7 @@ ACTOR Future<Void> refreshEncryptionKeysCore(Reference<EncryptKeyProxyData> ekpP
|
||||||
KmsConnectorInterface kmsConnectorInf) {
|
KmsConnectorInterface kmsConnectorInf) {
|
||||||
state UID debugId = deterministicRandom()->randomUniqueID();
|
state UID debugId = deterministicRandom()->randomUniqueID();
|
||||||
|
|
||||||
state TraceEvent t("RefreshEKs_Start", ekpProxyData->myId);
|
state TraceEvent t("RefreshEKsStart", ekpProxyData->myId);
|
||||||
t.setMaxEventLength(SERVER_KNOBS->ENCRYPT_PROXY_MAX_DBG_TRACE_LENGTH);
|
t.setMaxEventLength(SERVER_KNOBS->ENCRYPT_PROXY_MAX_DBG_TRACE_LENGTH);
|
||||||
t.detail("KmsConnInf", kmsConnectorInf.id());
|
t.detail("KmsConnInf", kmsConnectorInf.id());
|
||||||
t.detail("DebugId", debugId);
|
t.detail("DebugId", debugId);
|
||||||
|
@ -634,7 +634,7 @@ ACTOR Future<Void> refreshEncryptionKeysCore(Reference<EncryptKeyProxyData> ekpP
|
||||||
for (const auto& item : rep.cipherKeyDetails) {
|
for (const auto& item : rep.cipherKeyDetails) {
|
||||||
const auto itr = ekpProxyData->baseCipherDomainIdCache.find(item.encryptDomainId);
|
const auto itr = ekpProxyData->baseCipherDomainIdCache.find(item.encryptDomainId);
|
||||||
if (itr == ekpProxyData->baseCipherDomainIdCache.end()) {
|
if (itr == ekpProxyData->baseCipherDomainIdCache.end()) {
|
||||||
TraceEvent(SevInfo, "RefreshEKs_DomainIdNotFound", ekpProxyData->myId)
|
TraceEvent(SevInfo, "RefreshEKsDomainIdNotFound", ekpProxyData->myId)
|
||||||
.detail("DomainId", item.encryptDomainId);
|
.detail("DomainId", item.encryptDomainId);
|
||||||
// Continue updating the cache with other elements
|
// Continue updating the cache with other elements
|
||||||
continue;
|
continue;
|
||||||
|
@ -662,7 +662,7 @@ ACTOR Future<Void> refreshEncryptionKeysCore(Reference<EncryptKeyProxyData> ekpP
|
||||||
t.detail("NumKeys", rep.cipherKeyDetails.size());
|
t.detail("NumKeys", rep.cipherKeyDetails.size());
|
||||||
} catch (Error& e) {
|
} catch (Error& e) {
|
||||||
if (!canReplyWith(e)) {
|
if (!canReplyWith(e)) {
|
||||||
TraceEvent(SevWarn, "RefreshEKs_Error").error(e);
|
TraceEvent(SevWarn, "RefreshEKsError").error(e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
TraceEvent("RefreshEKs").detail("ErrorCode", e.code());
|
TraceEvent("RefreshEKs").detail("ErrorCode", e.code());
|
||||||
|
@ -828,7 +828,7 @@ ACTOR Future<Void> encryptKeyProxyServer(EncryptKeyProxyInterface ekpInterface,
|
||||||
state KmsConnectorInterface kmsConnectorInf;
|
state KmsConnectorInterface kmsConnectorInf;
|
||||||
kmsConnectorInf.initEndpoints();
|
kmsConnectorInf.initEndpoints();
|
||||||
|
|
||||||
TraceEvent("EKP_Start", self->myId).detail("KmsConnectorInf", kmsConnectorInf.id());
|
TraceEvent("EKPStart", self->myId).detail("KmsConnectorInf", kmsConnectorInf.id());
|
||||||
|
|
||||||
activateKmsConnector(self, kmsConnectorInf);
|
activateKmsConnector(self, kmsConnectorInf);
|
||||||
|
|
||||||
|
@ -861,7 +861,7 @@ ACTOR Future<Void> encryptKeyProxyServer(EncryptKeyProxyInterface ekpInterface,
|
||||||
self->addActor.send(getLatestBlobMetadata(self, kmsConnectorInf, req));
|
self->addActor.send(getLatestBlobMetadata(self, kmsConnectorInf, req));
|
||||||
}
|
}
|
||||||
when(HaltEncryptKeyProxyRequest req = waitNext(ekpInterface.haltEncryptKeyProxy.getFuture())) {
|
when(HaltEncryptKeyProxyRequest req = waitNext(ekpInterface.haltEncryptKeyProxy.getFuture())) {
|
||||||
TraceEvent("EKP_Halted", self->myId).detail("ReqID", req.requesterID);
|
TraceEvent("EKPHalted", self->myId).detail("ReqID", req.requesterID);
|
||||||
req.reply.send(Void());
|
req.reply.send(Void());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -871,7 +871,7 @@ ACTOR Future<Void> encryptKeyProxyServer(EncryptKeyProxyInterface ekpInterface,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Error& e) {
|
} catch (Error& e) {
|
||||||
TraceEvent("EKP_Terminated", self->myId).errorUnsuppressed(e);
|
TraceEvent("EKPTerminated", self->myId).errorUnsuppressed(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Void();
|
return Void();
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "fdbserver/IKeyValueStore.h"
|
#include "fdbserver/IKeyValueStore.h"
|
||||||
#include "fdbserver/RadixTree.h"
|
#include "fdbserver/RadixTree.h"
|
||||||
#include "flow/ActorCollection.h"
|
#include "flow/ActorCollection.h"
|
||||||
|
#include "flow/EncryptUtils.h"
|
||||||
#include "flow/Knobs.h"
|
#include "flow/Knobs.h"
|
||||||
#include "flow/actorcompiler.h" // This must be the last #include.
|
#include "flow/actorcompiler.h" // This must be the last #include.
|
||||||
|
|
||||||
|
@ -489,10 +490,11 @@ private:
|
||||||
|
|
||||||
ASSERT(cipherKeys.cipherTextKey.isValid());
|
ASSERT(cipherKeys.cipherTextKey.isValid());
|
||||||
ASSERT(cipherKeys.cipherHeaderKey.isValid());
|
ASSERT(cipherKeys.cipherHeaderKey.isValid());
|
||||||
EncryptBlobCipherAes265Ctr cipher(cipherKeys.cipherTextKey,
|
EncryptBlobCipherAes265Ctr cipher(
|
||||||
cipherKeys.cipherHeaderKey,
|
cipherKeys.cipherTextKey,
|
||||||
ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE,
|
cipherKeys.cipherHeaderKey,
|
||||||
BlobCipherMetrics::KV_MEMORY);
|
getEncryptAuthTokenMode(EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE),
|
||||||
|
BlobCipherMetrics::KV_MEMORY);
|
||||||
BlobCipherEncryptHeader cipherHeader;
|
BlobCipherEncryptHeader cipherHeader;
|
||||||
Arena arena;
|
Arena arena;
|
||||||
StringRef ciphertext =
|
StringRef ciphertext =
|
||||||
|
|
|
@ -66,13 +66,13 @@ struct SimKmsConnectorContext : NonCopyable, ReferenceCounted<SimKmsConnectorCon
|
||||||
// Construct encryption keyStore.
|
// Construct encryption keyStore.
|
||||||
// Note the keys generated must be the same after restart.
|
// Note the keys generated must be the same after restart.
|
||||||
for (int i = 1; i <= maxEncryptionKeys; i++) {
|
for (int i = 1; i <= maxEncryptionKeys; i++) {
|
||||||
uint8_t digest[AUTH_TOKEN_SIZE];
|
uint8_t digest[AUTH_TOKEN_HMAC_SHA_SIZE];
|
||||||
computeAuthToken(reinterpret_cast<const unsigned char*>(&i),
|
computeAuthToken({ { reinterpret_cast<const uint8_t*>(&i), sizeof(i) } },
|
||||||
sizeof(i),
|
|
||||||
SHA_KEY,
|
SHA_KEY,
|
||||||
AES_256_KEY_LENGTH,
|
AES_256_KEY_LENGTH,
|
||||||
&digest[0],
|
&digest[0],
|
||||||
AUTH_TOKEN_SIZE);
|
EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA,
|
||||||
|
AUTH_TOKEN_HMAC_SHA_SIZE);
|
||||||
simEncryptKeyStore[i] = std::make_unique<SimEncryptKeyCtx>(i, reinterpret_cast<const char*>(&digest[0]));
|
simEncryptKeyStore[i] = std::make_unique<SimEncryptKeyCtx>(i, reinterpret_cast<const char*>(&digest[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,13 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fdbclient/BlobCipher.h"
|
|
||||||
#if defined(NO_INTELLISENSE) && !defined(FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_G_H)
|
#if defined(NO_INTELLISENSE) && !defined(FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_G_H)
|
||||||
#define FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_G_H
|
#define FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_G_H
|
||||||
#include "fdbserver/IPageEncryptionKeyProvider.actor.g.h"
|
#include "fdbserver/IPageEncryptionKeyProvider.actor.g.h"
|
||||||
#elif !defined(FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_H)
|
#elif !defined(FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_H)
|
||||||
#define FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_H
|
#define FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_H
|
||||||
|
|
||||||
|
#include "fdbclient/BlobCipher.h"
|
||||||
#include "fdbclient/GetEncryptCipherKeys.actor.h"
|
#include "fdbclient/GetEncryptCipherKeys.actor.h"
|
||||||
#include "fdbclient/Tenant.h"
|
#include "fdbclient/Tenant.h"
|
||||||
|
|
||||||
|
@ -208,14 +208,15 @@ private:
|
||||||
Reference<BlobCipherKey> generateCipherKey(const BlobCipherDetails& cipherDetails) {
|
Reference<BlobCipherKey> generateCipherKey(const BlobCipherDetails& cipherDetails) {
|
||||||
static unsigned char SHA_KEY[] = "3ab9570b44b8315fdb261da6b1b6c13b";
|
static unsigned char SHA_KEY[] = "3ab9570b44b8315fdb261da6b1b6c13b";
|
||||||
Arena arena;
|
Arena arena;
|
||||||
uint8_t digest[AUTH_TOKEN_SIZE];
|
uint8_t digest[AUTH_TOKEN_HMAC_SHA_SIZE];
|
||||||
computeAuthToken(reinterpret_cast<const unsigned char*>(&cipherDetails.baseCipherId),
|
computeAuthToken(
|
||||||
sizeof(EncryptCipherBaseKeyId),
|
{ { reinterpret_cast<const uint8_t*>(&cipherDetails.baseCipherId), sizeof(EncryptCipherBaseKeyId) } },
|
||||||
SHA_KEY,
|
SHA_KEY,
|
||||||
AES_256_KEY_LENGTH,
|
AES_256_KEY_LENGTH,
|
||||||
&digest[0],
|
&digest[0],
|
||||||
AUTH_TOKEN_SIZE);
|
EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA,
|
||||||
ASSERT_EQ(AUTH_TOKEN_SIZE, AES_256_KEY_LENGTH);
|
AUTH_TOKEN_HMAC_SHA_SIZE);
|
||||||
|
ASSERT_EQ(AUTH_TOKEN_HMAC_SHA_SIZE, AES_256_KEY_LENGTH);
|
||||||
return makeReference<BlobCipherKey>(cipherDetails.encryptDomainId,
|
return makeReference<BlobCipherKey>(cipherDetails.encryptDomainId,
|
||||||
cipherDetails.baseCipherId,
|
cipherDetails.baseCipherId,
|
||||||
&digest[0],
|
&digest[0],
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#ifndef FDBSERVER_IPAGER_H
|
#ifndef FDBSERVER_IPAGER_H
|
||||||
#define FDBSERVER_IPAGER_H
|
#define FDBSERVER_IPAGER_H
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "fdbclient/BlobCipher.h"
|
#include "fdbclient/BlobCipher.h"
|
||||||
|
@ -28,8 +29,10 @@
|
||||||
#include "fdbclient/GetEncryptCipherKeys.actor.h"
|
#include "fdbclient/GetEncryptCipherKeys.actor.h"
|
||||||
#include "fdbclient/Tenant.h"
|
#include "fdbclient/Tenant.h"
|
||||||
#include "fdbserver/IClosable.h"
|
#include "fdbserver/IClosable.h"
|
||||||
|
#include "flow/EncryptUtils.h"
|
||||||
#include "flow/Error.h"
|
#include "flow/Error.h"
|
||||||
#include "flow/FastAlloc.h"
|
#include "flow/FastAlloc.h"
|
||||||
|
#include "flow/Knobs.h"
|
||||||
#include "flow/flow.h"
|
#include "flow/flow.h"
|
||||||
#include "flow/ProtocolVersion.h"
|
#include "flow/ProtocolVersion.h"
|
||||||
|
|
||||||
|
@ -369,7 +372,7 @@ public:
|
||||||
Header* h = reinterpret_cast<Header*>(header);
|
Header* h = reinterpret_cast<Header*>(header);
|
||||||
EncryptBlobCipherAes265Ctr cipher(cipherKeys.cipherTextKey,
|
EncryptBlobCipherAes265Ctr cipher(cipherKeys.cipherTextKey,
|
||||||
cipherKeys.cipherHeaderKey,
|
cipherKeys.cipherHeaderKey,
|
||||||
ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE,
|
getEncryptAuthTokenMode(ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE),
|
||||||
BlobCipherMetrics::KV_REDWOOD);
|
BlobCipherMetrics::KV_REDWOOD);
|
||||||
Arena arena;
|
Arena arena;
|
||||||
StringRef ciphertext = cipher.encrypt(payload, len, h, arena)->toStringRef();
|
StringRef ciphertext = cipher.encrypt(payload, len, h, arena)->toStringRef();
|
||||||
|
|
|
@ -57,7 +57,7 @@ struct EncryptKeyProxyTestWorkload : TestWorkload {
|
||||||
enableTest = true;
|
enableTest = true;
|
||||||
minDomainId = 1000 + (++seed * 30) + 1;
|
minDomainId = 1000 + (++seed * 30) + 1;
|
||||||
maxDomainId = deterministicRandom()->randomInt(minDomainId, minDomainId + 50) + 5;
|
maxDomainId = deterministicRandom()->randomInt(minDomainId, minDomainId + 50) + 5;
|
||||||
TraceEvent("EKPTest_Init").detail("MinDomainId", minDomainId).detail("MaxDomainId", maxDomainId);
|
TraceEvent("EKPTestInit").detail("MinDomainId", minDomainId).detail("MaxDomainId", maxDomainId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ struct EncryptKeyProxyTestWorkload : TestWorkload {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceEvent("SimEmptyDomainIdCache_Done").log();
|
TraceEvent("SimEmptyDomainIdCacheDone").log();
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ struct EncryptKeyProxyTestWorkload : TestWorkload {
|
||||||
state int expectedHits;
|
state int expectedHits;
|
||||||
state int expectedMisses;
|
state int expectedMisses;
|
||||||
|
|
||||||
TraceEvent("SimPartialDomainIdCache_Start").log();
|
TraceEvent("SimPartialDomainIdCacheStart").log();
|
||||||
|
|
||||||
self->domainInfos.clear();
|
self->domainInfos.clear();
|
||||||
|
|
||||||
|
@ -178,14 +178,14 @@ struct EncryptKeyProxyTestWorkload : TestWorkload {
|
||||||
}
|
}
|
||||||
self->domainInfos.clear();
|
self->domainInfos.clear();
|
||||||
|
|
||||||
TraceEvent("SimPartialDomainIdCache_Done").log();
|
TraceEvent("SimPartialDomainIdCacheDone").log();
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTOR Future<Void> simRandomBaseCipherIdCache(EncryptKeyProxyTestWorkload* self) {
|
ACTOR Future<Void> simRandomBaseCipherIdCache(EncryptKeyProxyTestWorkload* self) {
|
||||||
state int expectedHits;
|
state int expectedHits;
|
||||||
|
|
||||||
TraceEvent("SimRandomDomainIdCache_Start").log();
|
TraceEvent("SimRandomDomainIdCacheStart").log();
|
||||||
|
|
||||||
self->domainInfos.clear();
|
self->domainInfos.clear();
|
||||||
for (int i = 0; i < self->numDomains; i++) {
|
for (int i = 0; i < self->numDomains; i++) {
|
||||||
|
@ -271,14 +271,14 @@ struct EncryptKeyProxyTestWorkload : TestWorkload {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceEvent("SimRandomDomainIdCache_Done").log();
|
TraceEvent("SimRandomDomainIdCacheDone").log();
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTOR Future<Void> simLookupInvalidKeyId(EncryptKeyProxyTestWorkload* self) {
|
ACTOR Future<Void> simLookupInvalidKeyId(EncryptKeyProxyTestWorkload* self) {
|
||||||
Arena arena;
|
Arena arena;
|
||||||
|
|
||||||
TraceEvent("SimLookupInvalidKeyId_Start").log();
|
TraceEvent("SimLookupInvalidKeyIdStart").log();
|
||||||
|
|
||||||
// Prepare a lookup with valid and invalid keyIds - SimEncryptKmsProxy should throw encrypt_key_not_found()
|
// Prepare a lookup with valid and invalid keyIds - SimEncryptKmsProxy should throw encrypt_key_not_found()
|
||||||
EKPGetBaseCipherKeysByIdsRequest req;
|
EKPGetBaseCipherKeysByIdsRequest req;
|
||||||
|
@ -294,7 +294,7 @@ struct EncryptKeyProxyTestWorkload : TestWorkload {
|
||||||
ASSERT(rep.error.present());
|
ASSERT(rep.error.present());
|
||||||
ASSERT_EQ(rep.error.get().code(), error_code_encrypt_key_not_found);
|
ASSERT_EQ(rep.error.get().code(), error_code_encrypt_key_not_found);
|
||||||
|
|
||||||
TraceEvent("SimLookupInvalidKeyId_Done").log();
|
TraceEvent("SimLookupInvalidKeyIdDone").log();
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
.detail("EnableTTL", enableTTLTest);
|
.detail("EnableTTL", enableTTLTest);
|
||||||
}
|
}
|
||||||
|
|
||||||
~EncryptionOpsWorkload() { TraceEvent("EncryptionOpsWorkload.Done").log(); }
|
~EncryptionOpsWorkload() { TraceEvent("EncryptionOpsWorkloadDone").log(); }
|
||||||
|
|
||||||
bool isFixedSizePayload() { return mode == 1; }
|
bool isFixedSizePayload() { return mode == 1; }
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
void setupCipherEssentials() {
|
void setupCipherEssentials() {
|
||||||
Reference<BlobCipherKeyCache> cipherKeyCache = BlobCipherKeyCache::getInstance();
|
Reference<BlobCipherKeyCache> cipherKeyCache = BlobCipherKeyCache::getInstance();
|
||||||
|
|
||||||
TraceEvent("SetupCipherEssentials.Start").detail("MinDomainId", minDomainId).detail("MaxDomainId", maxDomainId);
|
TraceEvent("SetupCipherEssentialsStart").detail("MinDomainId", minDomainId).detail("MaxDomainId", maxDomainId);
|
||||||
|
|
||||||
uint8_t buff[AES_256_KEY_LENGTH];
|
uint8_t buff[AES_256_KEY_LENGTH];
|
||||||
std::vector<Reference<BlobCipherKey>> cipherKeys;
|
std::vector<Reference<BlobCipherKey>> cipherKeys;
|
||||||
|
@ -208,7 +208,7 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
ASSERT_EQ(memcmp(latestCipher->rawBaseCipher(), buff, cipherLen), 0);
|
ASSERT_EQ(memcmp(latestCipher->rawBaseCipher(), buff, cipherLen), 0);
|
||||||
headerRandomSalt = latestCipher->getSalt();
|
headerRandomSalt = latestCipher->getSalt();
|
||||||
|
|
||||||
TraceEvent("SetupCipherEssentials.Done")
|
TraceEvent("SetupCipherEssentialsDone")
|
||||||
.detail("MinDomainId", minDomainId)
|
.detail("MinDomainId", minDomainId)
|
||||||
.detail("MaxDomainId", maxDomainId)
|
.detail("MaxDomainId", maxDomainId)
|
||||||
.detail("HeaderBaseCipherId", headerBaseCipherId)
|
.detail("HeaderBaseCipherId", headerBaseCipherId)
|
||||||
|
@ -216,6 +216,8 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetCipherEssentials() {
|
void resetCipherEssentials() {
|
||||||
|
TraceEvent("ResetCipherEssentialsStart").detail("Min", minDomainId).detail("Max", maxDomainId);
|
||||||
|
|
||||||
Reference<BlobCipherKeyCache> cipherKeyCache = BlobCipherKeyCache::getInstance();
|
Reference<BlobCipherKeyCache> cipherKeyCache = BlobCipherKeyCache::getInstance();
|
||||||
for (EncryptCipherDomainId id = minDomainId; id <= maxDomainId; id++) {
|
for (EncryptCipherDomainId id = minDomainId; id <= maxDomainId; id++) {
|
||||||
cipherKeyCache->resetEncryptDomainId(id);
|
cipherKeyCache->resetEncryptDomainId(id);
|
||||||
|
@ -225,7 +227,7 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
cipherKeyCache->resetEncryptDomainId(SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_ID);
|
cipherKeyCache->resetEncryptDomainId(SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_ID);
|
||||||
cipherKeyCache->resetEncryptDomainId(ENCRYPT_HEADER_DOMAIN_ID);
|
cipherKeyCache->resetEncryptDomainId(ENCRYPT_HEADER_DOMAIN_ID);
|
||||||
|
|
||||||
TraceEvent("ResetCipherEssentials.Done").log();
|
TraceEvent("ResetCipherEssentialsDone");
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateLatestBaseCipher(const EncryptCipherDomainId encryptDomainId,
|
void updateLatestBaseCipher(const EncryptCipherDomainId encryptDomainId,
|
||||||
|
@ -272,11 +274,12 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
uint8_t* payload,
|
uint8_t* payload,
|
||||||
int len,
|
int len,
|
||||||
const EncryptAuthTokenMode authMode,
|
const EncryptAuthTokenMode authMode,
|
||||||
|
const EncryptAuthTokenAlgo authAlgo,
|
||||||
BlobCipherEncryptHeader* header) {
|
BlobCipherEncryptHeader* header) {
|
||||||
uint8_t iv[AES_256_IV_LENGTH];
|
uint8_t iv[AES_256_IV_LENGTH];
|
||||||
deterministicRandom()->randomBytes(&iv[0], AES_256_IV_LENGTH);
|
deterministicRandom()->randomBytes(&iv[0], AES_256_IV_LENGTH);
|
||||||
EncryptBlobCipherAes265Ctr encryptor(
|
EncryptBlobCipherAes265Ctr encryptor(
|
||||||
textCipherKey, headerCipherKey, &iv[0], AES_256_IV_LENGTH, authMode, BlobCipherMetrics::TEST);
|
textCipherKey, headerCipherKey, &iv[0], AES_256_IV_LENGTH, authMode, authAlgo, BlobCipherMetrics::TEST);
|
||||||
|
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
Reference<EncryptBuf> encrypted = encryptor.encrypt(payload, len, header, arena);
|
Reference<EncryptBuf> encrypted = encryptor.encrypt(payload, len, header, arena);
|
||||||
|
@ -307,6 +310,8 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
header.cipherHeaderDetails.salt);
|
header.cipherHeaderDetails.salt);
|
||||||
ASSERT(cipherKey.isValid());
|
ASSERT(cipherKey.isValid());
|
||||||
ASSERT(cipherKey->isEqual(orgCipherKey));
|
ASSERT(cipherKey->isEqual(orgCipherKey));
|
||||||
|
ASSERT(headerCipherKey.isValid() ||
|
||||||
|
header.flags.authTokenMode == EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE);
|
||||||
|
|
||||||
DecryptBlobCipherAes256Ctr decryptor(cipherKey, headerCipherKey, header.iv, BlobCipherMetrics::TEST);
|
DecryptBlobCipherAes256Ctr decryptor(cipherKey, headerCipherKey, header.iv, BlobCipherMetrics::TEST);
|
||||||
const bool validateHeaderAuthToken = deterministicRandom()->randomInt(0, 100) < 65;
|
const bool validateHeaderAuthToken = deterministicRandom()->randomInt(0, 100) < 65;
|
||||||
|
@ -374,12 +379,14 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
|
|
||||||
// Encrypt the payload - generates BlobCipherEncryptHeader to assist decryption later
|
// Encrypt the payload - generates BlobCipherEncryptHeader to assist decryption later
|
||||||
BlobCipherEncryptHeader header;
|
BlobCipherEncryptHeader header;
|
||||||
const EncryptAuthTokenMode authMode = deterministicRandom()->randomInt(0, 100) < 50
|
const EncryptAuthTokenMode authMode = getRandomAuthTokenMode();
|
||||||
? ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE
|
const EncryptAuthTokenAlgo authAlgo = authMode == EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE
|
||||||
: ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI;
|
? EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_NONE
|
||||||
|
: getRandomAuthTokenAlgo();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Reference<EncryptBuf> encrypted =
|
Reference<EncryptBuf> encrypted =
|
||||||
doEncryption(cipherKey, headerCipherKey, buff.get(), dataLen, authMode, &header);
|
doEncryption(cipherKey, headerCipherKey, buff.get(), dataLen, authMode, authAlgo, &header);
|
||||||
|
|
||||||
// Decrypt the payload - parses the BlobCipherEncryptHeader, fetch corresponding cipherKey and
|
// Decrypt the payload - parses the BlobCipherEncryptHeader, fetch corresponding cipherKey and
|
||||||
// decrypt
|
// decrypt
|
||||||
|
@ -388,7 +395,8 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
TraceEvent("Failed")
|
TraceEvent("Failed")
|
||||||
.detail("DomainId", encryptDomainId)
|
.detail("DomainId", encryptDomainId)
|
||||||
.detail("BaseCipherId", cipherKey->getBaseCipherId())
|
.detail("BaseCipherId", cipherKey->getBaseCipherId())
|
||||||
.detail("AuthMode", authMode);
|
.detail("AuthTokenMode", authMode)
|
||||||
|
.detail("AuthTokenAlgo", authAlgo);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +433,7 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
state int64_t refreshAt;
|
state int64_t refreshAt;
|
||||||
state int64_t expAt;
|
state int64_t expAt;
|
||||||
|
|
||||||
TraceEvent("TestBlobCipherCacheTTL.Start").detail("DomId", domId);
|
TraceEvent("TestBlobCipherCacheTTLStart").detail("DomId", domId);
|
||||||
|
|
||||||
deterministicRandom()->randomBytes(baseCipher.get(), AES_256_KEY_LENGTH);
|
deterministicRandom()->randomBytes(baseCipher.get(), AES_256_KEY_LENGTH);
|
||||||
|
|
||||||
|
@ -436,7 +444,7 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
cipherKey = cipherKeyCache->getLatestCipherKey(domId);
|
cipherKey = cipherKeyCache->getLatestCipherKey(domId);
|
||||||
compareCipherDetails(cipherKey, domId, baseCipherId, baseCipher.get(), AES_256_KEY_LENGTH, refreshAt, expAt);
|
compareCipherDetails(cipherKey, domId, baseCipherId, baseCipher.get(), AES_256_KEY_LENGTH, refreshAt, expAt);
|
||||||
|
|
||||||
TraceEvent("TestBlobCipherCacheTTL.NonRevocableNoExpiry").detail("DomId", domId);
|
TraceEvent("TestBlobCipherCacheTTLNonRevocableNoExpiry").detail("DomId", domId);
|
||||||
|
|
||||||
// Validate 'non-revocable' cipher with expiration
|
// Validate 'non-revocable' cipher with expiration
|
||||||
state EncryptCipherBaseKeyId baseCipherId_1 = baseCipherId + 1;
|
state EncryptCipherBaseKeyId baseCipherId_1 = baseCipherId + 1;
|
||||||
|
@ -454,7 +462,7 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
ASSERT(cipherKey.isValid());
|
ASSERT(cipherKey.isValid());
|
||||||
compareCipherDetails(cipherKey, domId, baseCipherId_1, baseCipher.get(), AES_256_KEY_LENGTH, refreshAt, expAt);
|
compareCipherDetails(cipherKey, domId, baseCipherId_1, baseCipher.get(), AES_256_KEY_LENGTH, refreshAt, expAt);
|
||||||
|
|
||||||
TraceEvent("TestBlobCipherCacheTTL.NonRevocableWithExpiry").detail("DomId", domId);
|
TraceEvent("TestBlobCipherCacheTTLNonRevocableWithExpiry").detail("DomId", domId);
|
||||||
|
|
||||||
// Validate 'revocable' cipher with expiration
|
// Validate 'revocable' cipher with expiration
|
||||||
state EncryptCipherBaseKeyId baseCipherId_2 = baseCipherId + 2;
|
state EncryptCipherBaseKeyId baseCipherId_2 = baseCipherId + 2;
|
||||||
|
@ -479,7 +487,7 @@ struct EncryptionOpsWorkload : TestWorkload {
|
||||||
cipherKey = cipherKeyCache->getCipherKey(domId, baseCipherId_2, salt);
|
cipherKey = cipherKeyCache->getCipherKey(domId, baseCipherId_2, salt);
|
||||||
ASSERT(!cipherKey.isValid());
|
ASSERT(!cipherKey.isValid());
|
||||||
|
|
||||||
TraceEvent("TestBlobCipherCacheTTL.End").detail("DomId", domId);
|
TraceEvent("TestBlobCipherCacheTTLEnd").detail("DomId", domId);
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "flow/EncryptUtils.h"
|
#include "flow/EncryptUtils.h"
|
||||||
|
#include "flow/IRandom.h"
|
||||||
|
#include "flow/Knobs.h"
|
||||||
#include "flow/Trace.h"
|
#include "flow/Trace.h"
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
@ -71,3 +73,72 @@ std::string getEncryptDbgTraceKeyWithTS(std::string_view prefix,
|
||||||
boost::format fmter("%s.%lld.%s.%llu.%lld.%lld");
|
boost::format fmter("%s.%lld.%s.%llu.%lld.%lld");
|
||||||
return boost::str(boost::format(fmter % prefix % domainId % dName % baseCipherId % refAfterTS % expAfterTS));
|
return boost::str(boost::format(fmter % prefix % domainId % dName % baseCipherId % refAfterTS % expAfterTS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getEncryptHeaderAuthTokenSize(int algo) {
|
||||||
|
switch (algo) {
|
||||||
|
case ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA:
|
||||||
|
return 32;
|
||||||
|
case ENCRYPT_HEADER_AUTH_TOKEN_ALGO_AES_CMAC:
|
||||||
|
return 16;
|
||||||
|
default:
|
||||||
|
throw not_implemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEncryptHeaderAuthTokenAlgoValid(const EncryptAuthTokenAlgo algo) {
|
||||||
|
return algo >= EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_NONE &&
|
||||||
|
algo < EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_LAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEncryptHeaderAuthTokenModeValid(const EncryptAuthTokenMode mode) {
|
||||||
|
return mode >= EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE &&
|
||||||
|
mode < EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_LAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEncryptHeaderAuthTokenDetailsValid(const EncryptAuthTokenMode mode, const EncryptAuthTokenAlgo algo) {
|
||||||
|
if (!isEncryptHeaderAuthTokenModeValid(mode) || !isEncryptHeaderAuthTokenAlgoValid(algo) ||
|
||||||
|
(mode == EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE &&
|
||||||
|
algo != EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_NONE) ||
|
||||||
|
(mode != EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE &&
|
||||||
|
algo == EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_NONE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Routine enables mapping EncryptHeader authTokenAlgo for a given authTokenMode; rules followed are:
|
||||||
|
// 1. AUTH_TOKEN_NONE overrides authTokenAlgo configuration (as expected)
|
||||||
|
// 2. AuthToken mode governed by the FLOW_KNOBS->ENCRYPT_HEADER_AUTH_TOKEN_ALGO
|
||||||
|
EncryptAuthTokenAlgo getAuthTokenAlgoFromMode(const EncryptAuthTokenMode mode) {
|
||||||
|
EncryptAuthTokenAlgo algo;
|
||||||
|
|
||||||
|
if (mode == EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE) {
|
||||||
|
// TOKEN_MODE_NONE overrides authTokenAlgo
|
||||||
|
algo = EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_NONE;
|
||||||
|
} else {
|
||||||
|
algo = (EncryptAuthTokenAlgo)FLOW_KNOBS->ENCRYPT_HEADER_AUTH_TOKEN_ALGO;
|
||||||
|
// Ensure cluster authTokenAlgo sanity
|
||||||
|
if (algo == EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_NONE) {
|
||||||
|
TraceEvent(SevWarn, "AuthTokenAlgoMisconfiguration").detail("Algo", algo).detail("Mode", mode);
|
||||||
|
throw not_implemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT(isEncryptHeaderAuthTokenDetailsValid(mode, algo));
|
||||||
|
return algo;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptAuthTokenMode getRandomAuthTokenMode() {
|
||||||
|
std::vector<EncryptAuthTokenMode> modes = { EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE,
|
||||||
|
EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE,
|
||||||
|
EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI };
|
||||||
|
int idx = deterministicRandom()->randomInt(0, modes.size());
|
||||||
|
return modes[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptAuthTokenAlgo getRandomAuthTokenAlgo() {
|
||||||
|
EncryptAuthTokenAlgo algo = deterministicRandom()->coinflip()
|
||||||
|
? EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_AES_CMAC
|
||||||
|
: EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA;
|
||||||
|
|
||||||
|
return algo;
|
||||||
|
}
|
|
@ -18,8 +18,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "flow/flow.h"
|
#include "flow/EncryptUtils.h"
|
||||||
#include "flow/Error.h"
|
#include "flow/Error.h"
|
||||||
|
#include "flow/flow.h"
|
||||||
#include "flow/Knobs.h"
|
#include "flow/Knobs.h"
|
||||||
#include "flow/BooleanParam.h"
|
#include "flow/BooleanParam.h"
|
||||||
#include "flow/UnitTest.h"
|
#include "flow/UnitTest.h"
|
||||||
|
@ -301,6 +302,10 @@ void FlowKnobs::initialize(Randomize randomize, IsSimulated isSimulated) {
|
||||||
init( TOKEN_CACHE_SIZE, 100 );
|
init( TOKEN_CACHE_SIZE, 100 );
|
||||||
init( ENCRYPT_KEY_CACHE_LOGGING_INTERVAL, 5.0 );
|
init( ENCRYPT_KEY_CACHE_LOGGING_INTERVAL, 5.0 );
|
||||||
init( ENCRYPT_KEY_CACHE_LOGGING_SAMPLE_SIZE, 1000 );
|
init( ENCRYPT_KEY_CACHE_LOGGING_SAMPLE_SIZE, 1000 );
|
||||||
|
// Refer to EncryptUtil::EncryptAuthTokenAlgo for more details
|
||||||
|
init( ENCRYPT_HEADER_AUTH_TOKEN_ENABLED, true ); if ( randomize && BUGGIFY ) { ENCRYPT_HEADER_AUTH_TOKEN_ENABLED = !ENCRYPT_HEADER_AUTH_TOKEN_ENABLED; }
|
||||||
|
init( ENCRYPT_HEADER_AUTH_TOKEN_ALGO, 1 ); if ( randomize && BUGGIFY ) { ENCRYPT_HEADER_AUTH_TOKEN_ALGO = getRandomAuthTokenAlgo(); }
|
||||||
|
|
||||||
|
|
||||||
// REST Client
|
// REST Client
|
||||||
init( RESTCLIENT_MAX_CONNECTIONPOOL_SIZE, 10 );
|
init( RESTCLIENT_MAX_CONNECTIONPOOL_SIZE, 10 );
|
||||||
|
|
|
@ -29,7 +29,9 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#define AUTH_TOKEN_SIZE 32
|
constexpr const int AUTH_TOKEN_HMAC_SHA_SIZE = 32;
|
||||||
|
constexpr const int AUTH_TOKEN_AES_CMAC_SIZE = 16;
|
||||||
|
constexpr const int AUTH_TOKEN_MAX_SIZE = AUTH_TOKEN_HMAC_SHA_SIZE;
|
||||||
|
|
||||||
using EncryptCipherDomainId = int64_t;
|
using EncryptCipherDomainId = int64_t;
|
||||||
using EncryptCipherDomainNameRef = StringRef;
|
using EncryptCipherDomainNameRef = StringRef;
|
||||||
|
@ -78,6 +80,23 @@ typedef enum {
|
||||||
static_assert(EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_LAST <= std::numeric_limits<uint8_t>::max(),
|
static_assert(EncryptAuthTokenMode::ENCRYPT_HEADER_AUTH_TOKEN_LAST <= std::numeric_limits<uint8_t>::max(),
|
||||||
"EncryptHeaderAuthToken value overflow");
|
"EncryptHeaderAuthToken value overflow");
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ENCRYPT_HEADER_AUTH_TOKEN_ALGO_NONE = 0,
|
||||||
|
ENCRYPT_HEADER_AUTH_TOKEN_ALGO_HMAC_SHA = 1,
|
||||||
|
ENCRYPT_HEADER_AUTH_TOKEN_ALGO_AES_CMAC = 2,
|
||||||
|
ENCRYPT_HEADER_AUTH_TOKEN_ALGO_LAST = 3 // Always the last element
|
||||||
|
} EncryptAuthTokenAlgo;
|
||||||
|
|
||||||
|
static_assert(EncryptAuthTokenAlgo::ENCRYPT_HEADER_AUTH_TOKEN_ALGO_LAST <= std::numeric_limits<uint8_t>::max(),
|
||||||
|
"EncryptHeaerAuthTokenAlgo value overflow");
|
||||||
|
|
||||||
|
bool isEncryptHeaderAuthTokenModeValid(const EncryptAuthTokenMode mode);
|
||||||
|
bool isEncryptHeaderAuthTokenAlgoValid(const EncryptAuthTokenAlgo algo);
|
||||||
|
bool isEncryptHeaderAuthTokenDetailsValid(const EncryptAuthTokenMode mode, const EncryptAuthTokenAlgo algo);
|
||||||
|
EncryptAuthTokenAlgo getAuthTokenAlgoFromMode(const EncryptAuthTokenMode mode);
|
||||||
|
EncryptAuthTokenMode getRandomAuthTokenMode();
|
||||||
|
EncryptAuthTokenAlgo getRandomAuthTokenAlgo();
|
||||||
|
|
||||||
constexpr std::string_view ENCRYPT_DBG_TRACE_CACHED_PREFIX = "Chd";
|
constexpr std::string_view ENCRYPT_DBG_TRACE_CACHED_PREFIX = "Chd";
|
||||||
constexpr std::string_view ENCRYPT_DBG_TRACE_QUERY_PREFIX = "Qry";
|
constexpr std::string_view ENCRYPT_DBG_TRACE_QUERY_PREFIX = "Qry";
|
||||||
constexpr std::string_view ENCRYPT_DBG_TRACE_INSERT_PREFIX = "Ins";
|
constexpr std::string_view ENCRYPT_DBG_TRACE_INSERT_PREFIX = "Ins";
|
||||||
|
@ -96,4 +115,6 @@ std::string getEncryptDbgTraceKeyWithTS(std::string_view prefix,
|
||||||
int64_t refAfterTS,
|
int64_t refAfterTS,
|
||||||
int64_t expAfterTS);
|
int64_t expAfterTS);
|
||||||
|
|
||||||
|
int getEncryptHeaderAuthTokenSize(int algo);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -364,6 +364,8 @@ public:
|
||||||
int64_t ENCRYPT_KEY_REFRESH_INTERVAL;
|
int64_t ENCRYPT_KEY_REFRESH_INTERVAL;
|
||||||
double ENCRYPT_KEY_CACHE_LOGGING_INTERVAL;
|
double ENCRYPT_KEY_CACHE_LOGGING_INTERVAL;
|
||||||
double ENCRYPT_KEY_CACHE_LOGGING_SAMPLE_SIZE;
|
double ENCRYPT_KEY_CACHE_LOGGING_SAMPLE_SIZE;
|
||||||
|
bool ENCRYPT_HEADER_AUTH_TOKEN_ENABLED;
|
||||||
|
int ENCRYPT_HEADER_AUTH_TOKEN_ALGO;
|
||||||
|
|
||||||
// Authorization
|
// Authorization
|
||||||
int TOKEN_CACHE_SIZE;
|
int TOKEN_CACHE_SIZE;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
[configuration]
|
[configuration]
|
||||||
|
buggify = false
|
||||||
testClass = "Encryption"
|
testClass = "Encryption"
|
||||||
|
|
||||||
[[knobs]]
|
[[knobs]]
|
||||||
|
|
Loading…
Reference in New Issue