Botan 3.11.1
Crypto and TLS for C&
Botan::RTSS_Share Class Referencefinal

#include <tss.h>

Public Member Functions

const secure_vector< uint8_t > & data () const
bool initialized () const
 RTSS_Share ()=default
 RTSS_Share (const uint8_t data[], size_t len)
 RTSS_Share (std::string_view hex_input)
uint8_t share_id () const
size_t size () const
std::string to_string () const

Static Public Member Functions

static secure_vector< uint8_t > reconstruct (const std::vector< RTSS_Share > &shares)
static std::vector< RTSS_Sharesplit (uint8_t M, uint8_t N, const uint8_t secret[], uint16_t secret_len, const std::vector< uint8_t > &identifier, std::string_view hash_fn, RandomNumberGenerator &rng)
static std::vector< RTSS_Sharesplit (uint8_t M, uint8_t N, const uint8_t secret[], uint16_t secret_len, const uint8_t identifier[16], RandomNumberGenerator &rng)

Detailed Description

A split secret, using the format from draft-mcgrew-tss-03

Definition at line 22 of file tss.h.

Constructor & Destructor Documentation

◆ RTSS_Share() [1/3]

Botan::RTSS_Share::RTSS_Share ( )
default

References data(), and RTSS_Share().

Referenced by RTSS_Share().

◆ RTSS_Share() [2/3]

Botan::RTSS_Share::RTSS_Share ( std::string_view hex_input)
explicit
Parameters
hex_inputthe share encoded in hexadecimal

Definition at line 85 of file tss.cpp.

85 {
86 m_contents = hex_decode_locked(hex_input);
87}
secure_vector< uint8_t > hex_decode_locked(const char input[], size_t input_length, bool ignore_ws)
Definition hex.cpp:135

References Botan::hex_decode_locked().

◆ RTSS_Share() [3/3]

Botan::RTSS_Share::RTSS_Share ( const uint8_t data[],
size_t len )
Parameters
datathe shared data
lenthe length of data

Definition at line 89 of file tss.cpp.

89 {
90 m_contents.assign(bin, bin + len);
91}

Member Function Documentation

◆ data()

const secure_vector< uint8_t > & Botan::RTSS_Share::data ( ) const
inline
Returns
binary representation

Definition at line 77 of file tss.h.

77{ return m_contents; }

Referenced by RTSS_Share().

◆ initialized()

bool Botan::RTSS_Share::initialized ( ) const
inline
Returns
if this TSS share was initialized or not

Definition at line 97 of file tss.h.

97{ return (!m_contents.empty()); }

Referenced by share_id().

◆ reconstruct()

secure_vector< uint8_t > Botan::RTSS_Share::reconstruct ( const std::vector< RTSS_Share > & shares)
static
Parameters
sharesthe list of shares

Definition at line 191 of file tss.cpp.

191 {
192 if(shares.size() <= 1) {
193 throw Decoding_Error("Insufficient shares to do TSS reconstruction");
194 }
195
196 for(size_t i = 0; i != shares.size(); ++i) {
197 if(shares[i].size() < RTSS_HEADER_SIZE + 1) {
198 throw Decoding_Error("Missing or malformed RTSS header");
199 }
200
201 if(shares[i].share_id() == 0) {
202 throw Decoding_Error("Invalid (id = 0) RTSS share detected");
203 }
204
205 if(i > 0) {
206 if(shares[i].size() != shares[0].size()) {
207 throw Decoding_Error("Different sized RTSS shares detected");
208 }
209
210 if(!CT::is_equal(shares[0].m_contents.data(), shares[i].m_contents.data(), RTSS_HEADER_SIZE).as_bool()) {
211 throw Decoding_Error("Different RTSS headers detected");
212 }
213 }
214 }
215
216 const uint8_t N = shares[0].m_contents[17];
217
218 if(shares.size() < N) {
219 throw Decoding_Error("Insufficient shares to do TSS reconstruction");
220 }
221
222 const uint16_t share_len = make_uint16(shares[0].m_contents[18], shares[0].m_contents[19]);
223
224 const uint8_t hash_id = shares[0].m_contents[16];
225 auto hash = get_rtss_hash_by_id(hash_id);
226 const size_t hash_len = (hash ? hash->output_length() : 0);
227
228 if(shares[0].size() != RTSS_HEADER_SIZE + share_len) {
229 /*
230 * This second (laxer) check accommodates a bug in TSS that was
231 * fixed in 2.9.0 - previous versions used the length of the
232 * *secret* here, instead of the length of the *share*, which is
233 * precisely 1 + hash_len longer.
234 */
235 if(shares[0].size() <= RTSS_HEADER_SIZE + 1 + hash_len) {
236 throw Decoding_Error("Bad RTSS length field in header");
237 }
238 }
239
240 std::vector<uint8_t> V(shares.size());
241 secure_vector<uint8_t> recovered;
242
243 // Compute the Lagrange coefficients
244 std::vector<uint8_t> lagrange_coeffs(shares.size());
245 for(size_t k = 0; k != shares.size(); ++k) {
246 uint8_t coeff = 1;
247 for(size_t l = 0; l != shares.size(); ++l) {
248 if(k == l) {
249 continue;
250 }
251 const uint8_t share_k = shares[k].share_id();
252 const uint8_t share_l = shares[l].share_id();
253 if(share_k == share_l) {
254 throw Decoding_Error("Duplicate shares found in RTSS recovery");
255 }
256 // We already verified this earlier in the function
257 BOTAN_ASSERT_NOMSG(share_k > 0 && share_l > 0);
258 const uint8_t div = tss_gf_mul(share_l, tss_gf_inv(share_k ^ share_l));
259 coeff = tss_gf_mul(coeff, div);
260 }
261 lagrange_coeffs[k] = coeff;
262 }
263
264 for(size_t i = RTSS_HEADER_SIZE + 1; i != shares[0].size(); ++i) {
265 for(size_t j = 0; j != V.size(); ++j) {
266 V[j] = shares[j].m_contents[i];
267 }
268
269 /*
270 * Interpolation step
271 *
272 * This is effectively a multi-scalar multiplication (aka sum-of-products)
273 * where one of the inputs, namely the Lagrange coefficients, are public.
274 * If optimizing this function further was useful, this would be the place
275 * to start, for example by using Pippeneger's algorithm.
276 */
277 uint8_t r = 0;
278 for(size_t k = 0; k != shares.size(); ++k) {
279 r ^= tss_gf_mul(V[k], lagrange_coeffs[k]);
280 }
281 recovered.push_back(r);
282 }
283
284 if(hash) {
285 if(recovered.size() < hash->output_length()) {
286 throw Decoding_Error("RTSS recovered value too short to be valid");
287 }
288
289 const size_t secret_len = recovered.size() - hash->output_length();
290
291 hash->update(recovered.data(), secret_len);
292 secure_vector<uint8_t> hash_check = hash->final();
293
294 if(!CT::is_equal(hash_check.data(), &recovered[secret_len], hash->output_length()).as_bool()) {
295 throw Decoding_Error("RTSS hash check failed");
296 }
297
298 // remove the trailing hash value
299 recovered.resize(secret_len);
300 }
301
302 return recovered;
303}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
uint8_t share_id() const
Definition tss.cpp:93
size_t size() const
Definition tss.h:92
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:798
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
constexpr uint16_t make_uint16(uint8_t i0, uint8_t i1)
Definition loadstor.h:92

References BOTAN_ASSERT_NOMSG, Botan::CT::is_equal(), Botan::make_uint16(), share_id(), and size().

◆ share_id()

uint8_t Botan::RTSS_Share::share_id ( ) const
Returns
share identifier

Definition at line 93 of file tss.cpp.

93 {
94 if(!initialized()) {
95 throw Invalid_State("RTSS_Share::share_id not initialized");
96 }
97
98 if(m_contents.size() < RTSS_HEADER_SIZE + 1) {
99 throw Decoding_Error("RTSS_Share::share_id invalid share data");
100 }
101
102 return m_contents[20];
103}
bool initialized() const
Definition tss.h:97

References initialized().

Referenced by reconstruct().

◆ size()

size_t Botan::RTSS_Share::size ( ) const
inline
Returns
size of this share in bytes

Definition at line 92 of file tss.h.

92{ return m_contents.size(); }

Referenced by reconstruct().

◆ split() [1/2]

std::vector< RTSS_Share > Botan::RTSS_Share::split ( uint8_t M,
uint8_t N,
const uint8_t secret[],
uint16_t secret_len,
const std::vector< uint8_t > & identifier,
std::string_view hash_fn,
RandomNumberGenerator & rng )
static
Parameters
Mthe number of shares needed to reconstruct
Nthe number of shares generated
secretthe secret to split
secret_lenthe length of the secret
identifierthe share identifier
hash_fnthe hash function to use for a checksum ("None", "SHA-1", "SHA-256")
rngthe random number generator to use

Definition at line 114 of file tss.cpp.

120 {
121 if(M <= 1 || N <= 1 || M > N || N >= 255) {
122 throw Invalid_Argument("RTSS_Share::split: Invalid N or M");
123 }
124
125 if(identifier.size() > 16) {
126 throw Invalid_Argument("RTSS_Share::split Invalid identifier size");
127 }
128
129 const uint8_t hash_id = rtss_hash_id(hash_fn);
130
131 std::unique_ptr<HashFunction> hash;
132 if(hash_id > 0) {
133 hash = HashFunction::create_or_throw(hash_fn);
134 }
135
136 // secret = S || H(S)
137 secure_vector<uint8_t> secret(S, S + S_len);
138 if(hash) {
139 secret += hash->process(S, S_len);
140 }
141
142 if(secret.size() >= 0xFFFE) {
143 throw Encoding_Error("RTSS_Share::split secret too large for TSS format");
144 }
145
146 // +1 byte for the share ID
147 const uint16_t share_len = static_cast<uint16_t>(secret.size() + 1);
148
149 secure_vector<uint8_t> share_header(RTSS_HEADER_SIZE);
150 copy_mem(share_header.data(), identifier.data(), identifier.size());
151 share_header[16] = hash_id;
152 share_header[17] = M;
153 share_header[18] = get_byte<0>(share_len);
154 share_header[19] = get_byte<1>(share_len);
155
156 // Create RTSS header in each share
157 std::vector<RTSS_Share> shares(N);
158
159 for(uint8_t i = 0; i != N; ++i) {
160 shares[i].m_contents.reserve(share_header.size() + share_len);
161 shares[i].m_contents = share_header;
162 }
163
164 // Choose sequential values for X starting from 1
165 for(uint8_t i = 0; i != N; ++i) {
166 shares[i].m_contents.push_back(i + 1);
167 }
168
169 for(const uint8_t secret_byte : secret) {
170 std::vector<uint8_t> coefficients(M - 1);
171 rng.randomize(coefficients.data(), coefficients.size());
172
173 for(uint8_t j = 0; j != N; ++j) {
174 const uint8_t X = j + 1;
175
176 uint8_t sum = secret_byte;
177 uint8_t X_i = X;
178
179 for(const uint8_t cb : coefficients) {
180 sum ^= tss_gf_mul(X_i, cb);
181 X_i = tss_gf_mul(X_i, X);
182 }
183
184 shares[j].m_contents.push_back(sum);
185 }
186 }
187
188 return shares;
189}
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition hash.cpp:308
constexpr uint8_t get_byte(T input)
Definition loadstor.h:79
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144

References Botan::copy_mem(), Botan::HashFunction::create_or_throw(), Botan::get_byte(), and Botan::RandomNumberGenerator::randomize().

◆ split() [2/2]

std::vector< RTSS_Share > Botan::RTSS_Share::split ( uint8_t M,
uint8_t N,
const uint8_t secret[],
uint16_t secret_len,
const uint8_t identifier[16],
RandomNumberGenerator & rng )
static
Parameters
Mthe number of shares needed to reconstruct
Nthe number of shares generated
secretthe secret to split
secret_lenthe length of the secret
identifierthe 16 byte share identifier
rngthe random number generator to use

Definition at line 109 of file tss.cpp.

110 {
111 return RTSS_Share::split(M, N, S, S_len, std::vector<uint8_t>(identifier, identifier + 16), "SHA-256", rng);
112}
static std::vector< RTSS_Share > split(uint8_t M, uint8_t N, const uint8_t secret[], uint16_t secret_len, const uint8_t identifier[16], RandomNumberGenerator &rng)
Definition tss.cpp:109

References split().

Referenced by split().

◆ to_string()

std::string Botan::RTSS_Share::to_string ( ) const
Returns
hex representation

Definition at line 105 of file tss.cpp.

105 {
106 return hex_encode(m_contents.data(), m_contents.size());
107}
void hex_encode(char output[], const uint8_t input[], size_t input_length, bool uppercase)
Definition hex.cpp:34

References Botan::hex_encode().


The documentation for this class was generated from the following files: