| 302 | std::string description() const override { return "EncryptionOps"; } |
| 303 | |
| 304 | Future<Void> start(Database const& cx) override { |
| 305 | uint8_t baseCipher[AES_256_KEY_LENGTH]; |
| 306 | int baseCipherLen = 0; |
| 307 | EncryptCipherBaseKeyId nextBaseCipherId; |
| 308 | |
| 309 | // Setup encryptDomainIds and corresponding baseCipher details |
| 310 | setupCipherEssentials(); |
| 311 | |
| 312 | for (int i = 0; i < numIterations; i++) { |
| 313 | bool updateBaseCipher = deterministicRandom()->randomInt(1, 100) < 5; |
| 314 | |
| 315 | // Step-1: Encryption key derivation, caching the cipher for later use |
| 316 | Reference<BlobCipherKeyCache> cipherKeyCache = BlobCipherKeyCache::getInstance(); |
| 317 | |
| 318 | // randomly select a domainId |
| 319 | const EncryptCipherDomainId encryptDomainId = deterministicRandom()->randomInt(minDomainId, maxDomainId); |
| 320 | ASSERT(encryptDomainId >= minDomainId && encryptDomainId <= maxDomainId); |
| 321 | |
| 322 | if (updateBaseCipher) { |
| 323 | // simulate baseCipherId getting refreshed/updated |
| 324 | updateLatestBaseCipher(encryptDomainId, &baseCipher[0], &baseCipherLen, &nextBaseCipherId); |
| 325 | cipherKeyCache->insertCipherKey(encryptDomainId, nextBaseCipherId, &baseCipher[0], baseCipherLen); |
| 326 | } |
| 327 | |
| 328 | auto start = std::chrono::high_resolution_clock::now(); |
| 329 | Reference<BlobCipherKey> cipherKey = cipherKeyCache->getLatestCipherKey(encryptDomainId); |
| 330 | // Each client working with their own version of encryptHeaderCipherKey, avoid using getLatest() |
| 331 | Reference<BlobCipherKey> headerCipherKey = |
| 332 | cipherKeyCache->getCipherKey(ENCRYPT_HEADER_DOMAIN_ID, headerBaseCipherId, headerRandomSalt); |
| 333 | auto end = std::chrono::high_resolution_clock::now(); |
| 334 | metrics->updateKeyDerivationTime(std::chrono::duration<double, std::nano>(end - start).count()); |
| 335 | |
| 336 | // Validate sanity of "getLatestCipher", especially when baseCipher gets updated |
| 337 | if (updateBaseCipher) { |
| 338 | ASSERT_EQ(cipherKey->getBaseCipherId(), nextBaseCipherId); |
| 339 | ASSERT_EQ(cipherKey->getBaseCipherLen(), baseCipherLen); |
| 340 | ASSERT_EQ(memcmp(cipherKey->rawBaseCipher(), baseCipher, baseCipherLen), 0); |
| 341 | } |
| 342 | |
| 343 | int dataLen = isFixedSizePayload() ? pageSize : deterministicRandom()->randomInt(100, maxBufSize); |
| 344 | deterministicRandom()->randomBytes(buff.get(), dataLen); |
| 345 | |
| 346 | // Encrypt the payload - generates BlobCipherEncryptHeader to assist decryption later |
| 347 | BlobCipherEncryptHeader header; |
| 348 | const EncryptAuthTokenMode authMode = deterministicRandom()->randomInt(0, 100) < 50 |
| 349 | ? ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE |
| 350 | : ENCRYPT_HEADER_AUTH_TOKEN_MODE_MULTI; |
| 351 | try { |
| 352 | Reference<EncryptBuf> encrypted = |
| 353 | doEncryption(cipherKey, headerCipherKey, buff.get(), dataLen, authMode, &header); |
| 354 | |
| 355 | // Decrypt the payload - parses the BlobCipherEncryptHeader, fetch corresponding cipherKey and |
| 356 | // decrypt |
| 357 | doDecryption(encrypted, dataLen, header, buff.get(), cipherKey); |
| 358 | } catch (Error& e) { |
| 359 | TraceEvent("Failed") |
| 360 | .detail("DomainId", encryptDomainId) |
| 361 | .detail("BaseCipherId", cipherKey->getBaseCipherId()) |
nothing calls this directly
no test coverage detected