/* * Copyright 2018 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FCP_SECAGG_SHARED_AES_CTR_PRNG_H_ #define FCP_SECAGG_SHARED_AES_CTR_PRNG_H_ #include #include #include "fcp/secagg/shared/aes_key.h" #include "fcp/secagg/shared/prng.h" #include "openssl/evp.h" namespace fcp { namespace secagg { // A cryptographically strong Deterministic Pseudorandom Number Generator based // on AES-CTR in OpenSSL. The seed must be supplied by the user. // // This code is used for the very specific purpose of generating *reproduceable* // numbers which appear pseudorandom to any party not in possession of the input // seed. DO NOT use AesCtrPrng in any situation where real randomness would be // useful, because it uses no entropy at all and will always produce the same // numbers if given the same seed. // // A single instance of AesCtrPrng can generate up to 2^36 bytes of // pseudorandom output. If more than 2^36 bytes of output are needed, multiple // instances of AesCtrPrng with different seeds should be used. // // This class is not thread-safe. class AesCtrPrng : public SecureBatchPrng { public: // This class should only be instantiated via AesCtrPrngFactory. friend class AesCtrPrngFactory; ~AesCtrPrng() override; // Returns a new pseudorandom number of the specified size, generating new // pseudorandom bytes as needed. uint8_t Rand8() override; uint64_t Rand64() override; // Fills the provided buffer with pseudorandom bytes. Returns the number of // bytes that has been generated, which can be smaller than the requested // buffer_size if it exceeds the maximum buffer size returned by // GetMaxBufferSize(). int RandBuffer(uint8_t* buffer, int buffer_size) override; // Get the maximum size of a buffer that can be filled by RandBuffer() in a // single call. size_t GetMaxBufferSize() const override { return kCacheSize; } private: static constexpr size_t kIvSize = 16; // IV size, in bytes // Constructs the PRNG with the given seed, and an IV of all zeroes. // This is ONLY secure if the seed is never used more than once. explicit AesCtrPrng(const AesKey& seed); // Number of AES blocks in the cache. // The number of blocks is optimized to make kCacheSize to be a multiple // of any possible number of bytes in a SecAgg output (i.e. 1 to 8). static constexpr size_t kBatchSize = 3 * 5 * 7; // Block size, in bytes static constexpr size_t kBlockSize = 16; // Size of our cache, in bytes. We cache blocks to save leftover bytes. static constexpr int kCacheSize = kBatchSize * kBlockSize; // For security, we don't want to generate more than 2^32-1 blocks. static constexpr size_t kMaxBlocks = 0xFFFFFFFF; // Fills the selected cache with deterministic pseudorandomly generated bytes. // After this, the associated next_byte_pos counter must be set to 0. void GenerateBytes(uint8_t* cache, int cache_size); // Cache used by both Rand8() and Rand64() uint8_t cache_[kCacheSize]; size_t next_byte_pos_; // This is used to generate bytes. static constexpr uint8_t kAllZeroes[kCacheSize] = {0}; EVP_CIPHER_CTX* ctx_; size_t blocks_generated_; }; } // namespace secagg } // namespace fcp #endif // FCP_SECAGG_SHARED_AES_CTR_PRNG_H_