xref: /aosp_15_r20/external/federated-compute/fcp/base/random_token.h (revision 14675a029014e728ec732f129a32e299b2da0601)
1 /*
2  * Copyright 2019 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef FCP_BASE_RANDOM_TOKEN_H_
18 #define FCP_BASE_RANDOM_TOKEN_H_
19 
20 #include <stdint.h>
21 
22 #include <array>
23 #include <string>
24 #include <utility>
25 
26 #include "absl/types/span.h"
27 
28 namespace fcp {
29 
30 enum { kRandomTokenSizeInBytes = 16 };
31 
32 /**
33  * A RandomToken is a unique and "unguessable" value, thus usable as a
34  * 'password-capability' (even in an adversarial / network context). Each is
35  * comprised of 128 random bits, sourced from a CSRNG.
36  *
37  * The current implementation uses BoringSSL's RAND_bytes. Unless someone calls
38  * RAND_enable_fork_unsafe_buffering, it should be well-behaved even under
39  * fork(); i.e. tokens should not collide with those generated by new child
40  * processes.
41  */
42 class RandomToken {
43  public:
44   /**
45    * Generates a new token. This sources bits from a CSRNG. The returned token
46    * can be assumed to have the desired properties (unique and unguessable) -
47    * unlike one that was deserialized from an untrusted source.
48    */
49   static RandomToken Generate();
50 
51   /**
52    * Deserializes a token, serialized with ToBytes() or ToString().
53    * Note that tokens from untrusted sources might not have been generated
54    * correctly, so should not be assumed unique and unguessable.
55    *
56    * Precondition: bytes.size() == kRandomTokenSizeInBytes
57    */
58   static RandomToken FromBytes(absl::Span<char const> bytes);
59 
60   /**
61    * Serializes a token, to something usable by FromBytes().
62    */
63   std::array<char, kRandomTokenSizeInBytes> ToBytes() const;
64 
65   /**
66    * Serializes a token, to an std::string usable by FromBytes().
67    *
68    * Postcondition: returned_string.size() == kRandomTokenSizeInBytes.
69    */
70   std::string ToString() const;
71 
72   /**
73    * Returns a hex-string representation (suitable for log output etc.)
74    */
75   std::string ToPrintableString() const;
76 
77   constexpr bool operator==(RandomToken other) const {
78     return words_[0] == other.words_[0] && words_[1] == other.words_[1];
79   }
80 
81   constexpr bool operator!=(RandomToken other) const {
82     return !(*this == other);
83   }
84 
85   template <typename H>
AbslHashValue(H h,RandomToken t)86   friend H AbslHashValue(H h, RandomToken t) {
87     return H::combine(std::move(h), t.words_[0], t.words_[1]);
88   }
89 
90  private:
RandomToken(uint64_t a,uint64_t b)91   explicit constexpr RandomToken(uint64_t a, uint64_t b) : words_{a, b} {}
92 
93   // It would have been nice to write char bytes[16], with alignas(16).
94   // Surprisingly, even current compilers were found prone to unrolling
95   // byte-by-byte comparison loops etc. This representation yields very compact
96   // code.
97   uint64_t words_[2];
98 };
99 
100 static_assert(sizeof(RandomToken) == kRandomTokenSizeInBytes,
101               "Incorrect RandomToken size");
102 
103 }  // namespace fcp
104 
105 #endif  // FCP_BASE_RANDOM_TOKEN_H_
106