Beispiel #1
0
std::vector<RTSS_Share>
RTSS_Share::split(byte M, byte N,
                  const byte S[], u16bit S_len,
                  const byte identifier[16],
                  RandomNumberGenerator& rng)
   {
   if(M == 0 || N == 0 || M > N)
      throw Encoding_Error("RTSS_Share::split: M == 0 or N == 0 or M > N");

   SHA_256 hash; // always use SHA-256 when generating shares

   std::vector<RTSS_Share> shares(N);

   // Create RTSS header in each share
   for(byte i = 0; i != N; ++i)
      {
      shares[i].m_contents += std::make_pair(identifier, 16);
      shares[i].m_contents += rtss_hash_id(hash.name());
      shares[i].m_contents += M;
      shares[i].m_contents += get_byte(0, S_len);
      shares[i].m_contents += get_byte(1, S_len);
      }

   // Choose sequential values for X starting from 1
   for(byte i = 0; i != N; ++i)
      shares[i].m_contents.push_back(i+1);

   // secret = S || H(S)
   secure_vector<byte> secret(S, S + S_len);
   secret += hash.process(S, S_len);

   for(size_t i = 0; i != secret.size(); ++i)
      {
      std::vector<byte> coefficients(M-1);
      rng.randomize(coefficients.data(), coefficients.size());

      for(byte j = 0; j != N; ++j)
         {
         const byte X = j + 1;

         byte sum = secret[i];
         byte X_i = X;

         for(size_t k = 0; k != coefficients.size(); ++k)
            {
            sum ^= gfp_mul(X_i, coefficients[k]);
            X_i  = gfp_mul(X_i, X);
            }

         shares[j].m_contents.push_back(sum);
         }
      }

   return shares;
   }
Beispiel #2
0
secure_vector<byte>
RTSS_Share::reconstruct(const std::vector<RTSS_Share>& shares)
   {
   const size_t RTSS_HEADER_SIZE = 20;

   for(size_t i = 0; i != shares.size(); ++i)
      {
      if(shares[i].size() != shares[0].size())
         throw Decoding_Error("Different sized RTSS shares detected");
      if(shares[i].share_id() == 0)
         throw Decoding_Error("Invalid (id = 0) RTSS share detected");
      if(shares[i].size() < RTSS_HEADER_SIZE)
         throw Decoding_Error("Missing or malformed RTSS header");

      if(!same_mem(&shares[0].m_contents[0],
                   &shares[i].m_contents[0], RTSS_HEADER_SIZE))
         throw Decoding_Error("Different RTSS headers detected");
      }

   if(shares.size() < shares[0].m_contents[17])
      throw Decoding_Error("Insufficient shares to do TSS reconstruction");

   u16bit secret_len = make_u16bit(shares[0].m_contents[18],
                                   shares[0].m_contents[19]);

   byte hash_id = shares[0].m_contents[16];

   std::unique_ptr<HashFunction> hash(get_rtss_hash_by_id(hash_id));

   if(shares[0].size() != secret_len + hash->output_length() + RTSS_HEADER_SIZE + 1)
      throw Decoding_Error("Bad RTSS length field in header");

   std::vector<byte> V(shares.size());
   secure_vector<byte> secret;

   for(size_t i = RTSS_HEADER_SIZE + 1; i != shares[0].size(); ++i)
      {
      for(size_t j = 0; j != V.size(); ++j)
         V[j] = shares[j].m_contents[i];

      byte r = 0;
      for(size_t k = 0; k != shares.size(); ++k)
         {
         // L_i function:
         byte r2 = 1;
         for(size_t l = 0; l != shares.size(); ++l)
            {
            if(k == l)
               continue;

            byte share_k = shares[k].share_id();
            byte share_l = shares[l].share_id();

            if(share_k == share_l)
               throw Decoding_Error("Duplicate shares found in RTSS recovery");

            byte div = RTSS_EXP[(255 +
                                 RTSS_LOG[share_l] -
                                 RTSS_LOG[share_k ^ share_l]) % 255];

            r2 = gfp_mul(r2, div);
            }

         r ^= gfp_mul(V[k], r2);
         }
      secret.push_back(r);
      }

   if(secret.size() != secret_len + hash->output_length())
      throw Decoding_Error("Bad length in RTSS output");

   hash->update(secret.data(), secret_len);
   secure_vector<byte> hash_check = hash->final();

   if(!same_mem(hash_check.data(),
                &secret[secret_len], hash->output_length()))
      throw Decoding_Error("RTSS hash check failed");

   return secure_vector<byte>(secret.cbegin(), secret.cbegin() + secret_len);
   }
Beispiel #3
0
secure_vector<uint8_t>
RTSS_Share::reconstruct(const std::vector<RTSS_Share>& shares)
   {
   if(shares.size() <= 1)
      throw Decoding_Error("Insufficient shares to do TSS reconstruction");

   for(size_t i = 0; i != shares.size(); ++i)
      {
      if(shares[i].size() < RTSS_HEADER_SIZE + 1)
         throw Decoding_Error("Missing or malformed RTSS header");

      if(shares[i].share_id() == 0)
         throw Decoding_Error("Invalid (id = 0) RTSS share detected");

      if(i > 0)
         {
         if(shares[i].size() != shares[0].size())
            throw Decoding_Error("Different sized RTSS shares detected");

         if(!same_mem(&shares[0].m_contents[0],
                      &shares[i].m_contents[0], RTSS_HEADER_SIZE))
            throw Decoding_Error("Different RTSS headers detected");
         }
      }

   const uint8_t N = shares[0].m_contents[17];

   if(shares.size() < N)
      throw Decoding_Error("Insufficient shares to do TSS reconstruction");

   const uint16_t share_len = make_uint16(shares[0].m_contents[18],
                                          shares[0].m_contents[19]);

   const uint8_t hash_id = shares[0].m_contents[16];
   std::unique_ptr<HashFunction> hash(get_rtss_hash_by_id(hash_id));
   const size_t hash_len = (hash ? hash->output_length() : 0);

   if(shares[0].size() != RTSS_HEADER_SIZE + share_len)
      {
      /*
      * This second (laxer) check accomodates a bug in TSS that was
      * fixed in 2.9.0 - previous versions used the length of the
      * *secret* here, instead of the length of the *share*, which is
      * precisely 1 + hash_len longer.
      */
      if(shares[0].size() <= RTSS_HEADER_SIZE + 1 + hash_len)
         throw Decoding_Error("Bad RTSS length field in header");
      }

   std::vector<uint8_t> V(shares.size());
   secure_vector<uint8_t> recovered;

   for(size_t i = RTSS_HEADER_SIZE + 1; i != shares[0].size(); ++i)
      {
      for(size_t j = 0; j != V.size(); ++j)
         V[j] = shares[j].m_contents[i];

      uint8_t r = 0;
      for(size_t k = 0; k != shares.size(); ++k)
         {
         // L_i function:
         uint8_t r2 = 1;
         for(size_t l = 0; l != shares.size(); ++l)
            {
            if(k == l)
               continue;

            uint8_t share_k = shares[k].share_id();
            uint8_t share_l = shares[l].share_id();

            if(share_k == share_l)
               throw Decoding_Error("Duplicate shares found in RTSS recovery");

            uint8_t div = RTSS_EXP[(255 +
                                 RTSS_LOG[share_l] -
                                 RTSS_LOG[share_k ^ share_l]) % 255];

            r2 = gfp_mul(r2, div);
            }

         r ^= gfp_mul(V[k], r2);
         }
      recovered.push_back(r);
      }

   if(hash)
      {
      if(recovered.size() < hash->output_length())
         throw Decoding_Error("RTSS recovered value too short to be valid");

      const size_t secret_len = recovered.size() - hash->output_length();

      hash->update(recovered.data(), secret_len);
      secure_vector<uint8_t> hash_check = hash->final();

      if(!constant_time_compare(hash_check.data(),
                                &recovered[secret_len],
                                hash->output_length()))
         {
         throw Decoding_Error("RTSS hash check failed");
         }

      // remove the trailing hash value
      recovered.resize(secret_len);
      }

   return recovered;
   }
Beispiel #4
0
std::vector<RTSS_Share>
RTSS_Share::split(uint8_t M, uint8_t N,
                  const uint8_t S[], uint16_t S_len,
                  const std::vector<uint8_t>& identifier,
                  const std::string& hash_fn,
                  RandomNumberGenerator& rng)
   {
   if(M <= 1 || N <= 1 || M > N || N >= 255)
      throw Invalid_Argument("RTSS_Share::split: Invalid N or M");

   if(identifier.size() > 16)
      throw Invalid_Argument("RTSS_Share::split Invalid identifier size");

   const uint8_t hash_id = rtss_hash_id(hash_fn);

   std::unique_ptr<HashFunction> hash;
   if(hash_id > 0)
      hash = HashFunction::create_or_throw(hash_fn);

   // secret = S || H(S)
   secure_vector<uint8_t> secret(S, S + S_len);
   if(hash)
      secret += hash->process(S, S_len);

   if(secret.size() >= 0xFFFE)
      throw Encoding_Error("RTSS_Share::split secret too large for TSS format");

   // +1 byte for the share ID
   const uint16_t share_len = static_cast<uint16_t>(secret.size() + 1);

   secure_vector<uint8_t> share_header(RTSS_HEADER_SIZE);
   copy_mem(&share_header[0], identifier.data(), identifier.size());
   share_header[16] = hash_id;
   share_header[17] = M;
   share_header[18] = get_byte(0, share_len);
   share_header[19] = get_byte(1, share_len);

   // Create RTSS header in each share
   std::vector<RTSS_Share> shares(N);

   for(uint8_t i = 0; i != N; ++i)
      {
      shares[i].m_contents.reserve(share_header.size() + share_len);
      shares[i].m_contents = share_header;
      }

   // Choose sequential values for X starting from 1
   for(uint8_t i = 0; i != N; ++i)
      shares[i].m_contents.push_back(i+1);

   for(size_t i = 0; i != secret.size(); ++i)
      {
      std::vector<uint8_t> coefficients(M-1);
      rng.randomize(coefficients.data(), coefficients.size());

      for(uint8_t j = 0; j != N; ++j)
         {
         const uint8_t X = j + 1;

         uint8_t sum = secret[i];
         uint8_t X_i = X;

         for(size_t k = 0; k != coefficients.size(); ++k)
            {
            sum ^= gfp_mul(X_i, coefficients[k]);
            X_i  = gfp_mul(X_i, X);
            }

         shares[j].m_contents.push_back(sum);
         }
      }

   return shares;
   }