1 // Copyright 2016 The Fuchsia Authors 2 // 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file or at 5 // https://opensource.org/licenses/MIT 6 7 #pragma once 8 9 #include <stddef.h> 10 #include <stdint.h> 11 12 #include <fbl/atomic.h> 13 #include <fbl/mutex.h> 14 #include <kernel/event.h> 15 #include <kernel/spinlock.h> 16 #include <zircon/thread_annotations.h> 17 18 namespace crypto { 19 20 typedef unsigned __int128 uint128_t; 21 22 // This exposes a (optionally-)thread-safe cryptographically secure PRNG. 23 // This PRNG must be seeded with at least 256 bits of "real" entropy before 24 // being used for cryptographic applications. 25 class PRNG { 26 public: 27 // Tag object for constructing a non-thread-safe version. 28 struct NonThreadSafeTag {}; 29 30 // Construct a thread-safe instance of the PRNG with the byte array at 31 // |data| as the initial seed. |size| is the length of |data| in bytes. 32 PRNG(const void* data, size_t size); 33 34 // Construct a non-thread-safe instance of the PRNG with the byte array at 35 // |data| as the initial seed. |size| is the length of |data| in bytes. 36 PRNG(const void* data, size_t size, NonThreadSafeTag); 37 38 ~PRNG(); 39 40 // Re-seed the PRNG by mixing-in new entropy. |size| is in bytes. |data| 41 // should be high-quality entropy, i.e. each bit should have equal 42 // probability of being 0 or 1. |size| MUST NOT be greater than kMaxEntropy. 43 void AddEntropy(const void* data, size_t size) TA_EXCL(mutex_) 44 TA_EXCL(spinlock_); 45 46 // Get pseudo-random output of |size| bytes. Blocks until at least 47 // kMinEntropy bytes of entropy have been added to this PRNG. |size| MUST 48 // NOT be greater than kMaxDrawLen. Identical PRNGs are only guaranteed to 49 // produce identical output when given identical inputs. 50 void Draw(void* out, size_t size) TA_EXCL(spinlock_); 51 52 // Return an integer in the range [0, exclusive_upper_bound) chosen 53 // uniformly at random. This is a wrapper for Draw(), and so has the same 54 // caveats. 55 uint64_t RandInt(uint64_t exclusive_upper_bound) TA_EXCL(spinlock_); 56 57 // Transitions the PRNG to thread-safe mode. This asserts that the 58 // instance is not yet thread-safe. 59 void BecomeThreadSafe(); 60 61 // Inspect if this PRNG is thread-safe. 62 bool is_thread_safe() const; 63 64 // The minimum amount of entropy (in bytes) the generator requires before 65 // Draw will return data. 66 static constexpr uint64_t kMinEntropy = 32; 67 68 // The maximum amount of entropy (in bytes) that can be submitted to 69 // AddEntropy. Anything above this will panic. 70 static constexpr uint64_t kMaxEntropy = 1ULL << 30; 71 72 // The maximum amount of pseudorandom data (in bytes) that can be drawn in 73 // one call to Draw. This the limit imposed by the maximum number of bytes 74 // that can be generated with a single key/nonce pair. Each request to Draw 75 // uses a different key/nonce pair. Anything above this will panic. 76 static constexpr uint64_t kMaxDrawLen = 1ULL << 38; 77 78 private: 79 PRNG(const PRNG&) = delete; 80 PRNG& operator=(const PRNG&) = delete; 81 82 // Synchronizes calls to |AddEntropy|. 83 fbl::Mutex mutex_; 84 85 // Controls access to |key_| |and nonce_|. 86 SpinLock spinlock_; 87 88 // ChaCha20 key and nonce as described in RFC 7539. The key length is 89 // enforced by a static assertion in the constructor. 90 uint8_t key_[32] TA_GUARDED(spinlock_); 91 uint128_t nonce_ TA_GUARDED(spinlock_); 92 93 // Events used to signal when calls to |Draw| may proceed, if 94 // |BecomeThreadSafe| has been called. 95 event_t ready_; 96 97 // Number of bytes of entropy added so far. 98 fbl::atomic<size_t> accumulated_; 99 }; 100 101 } // namespace crypto 102