void LoginAdminClient::PostCreateAccount() { FortunaOutput *csprng = FortunaFactory::ii->Create(); if (!csprng) { WARN("AdminClient") << "Out of memory: Unable to create CSPRNG"; on_disconnect(); return; } u8 create_request[8+32]; csprng->Generate(create_request, 8); GeneratePasswordHash(_username, create_request, 8, _password.c_str(), _password_hash, 32); memcpy(create_request + 8, _password_hash, 32); WriteReliable(STREAM_1, LS_CREATE_ACCOUNT, create_request, sizeof(create_request)); delete csprng; }
// Generates an unbiased random key in the range 1 < key < q void KeyAgreementCommon::GenerateKey(TunnelTLS *tls, Leg *key) { BigTwistedEdwards *math = tls->Math(); FortunaOutput *csprng = tls->CSPRNG(); do { csprng->Generate(key, KeyBytes); // Turn off the high bit(s) to speed up unbiased key generation // NOTE: Only works for the values of q above #if defined(CAT_DETERMINISTIC_KEY_GENERATION) key[KeyLegs-1] &= ~(CAT_LEG_MSB | (CAT_LEG_MSB >> 1)); #else key[KeyLegs-1] &= ~CAT_LEG_MSB; #endif } while (!math->Less(key, math->GetCurveQ()) || !math->GreaterX(key, 1)); }
bool KeyAgreementResponder::ProcessChallenge(TunnelTLS *tls, const u8 *initiator_challenge, int challenge_bytes, u8 *responder_answer, int answer_bytes, Skein *key_hash) { CAT_DEBUG_ENFORCE(tls && tls->Valid() && challenge_bytes == KeyBytes*2 && answer_bytes == KeyBytes*4); BigTwistedEdwards *math = tls->Math(); FortunaOutput *csprng = tls->CSPRNG(); Leg *A = math->Get(0); Leg *S = math->Get(8); Leg *T = math->Get(12); Leg *hA = math->Get(16); // Unpack the initiator's A into registers if (!math->LoadVerifyAffineXY(initiator_challenge, initiator_challenge + KeyBytes, A)) return false; // Verify the point is not the additive identity (should never happen unless being attacked) if (math->IsAffineIdentity(A)) return false; // hA = h * A for small subgroup attack resistance math->PtDoubleZ1(A, hA); math->PtEDouble(hA, hA); #if defined(CAT_NO_ATOMIC_RESPONDER) bool time_to_rekey = false; m_thread_id_mutex.Enter(); // Check if it is time to rekey if (ChallengeCount++ == 100) time_to_rekey = true; m_thread_id_mutex.Leave(); if (time_to_rekey) Rekey(math, csprng); #else // CAT_NO_ATOMIC_RESPONDER // Check if it is time to rekey if (Atomic::Add(&ChallengeCount, 1) == 100) Rekey(tls); #endif // CAT_NO_ATOMIC_RESPONDER // Copy the current endian neutral Y to the responder answer u32 ThisY = ActiveY; memcpy(responder_answer, Y_neutral[ThisY], KeyBytes*2); do { // random n-bit number r csprng->Generate(responder_answer + KeyBytes*2, KeyBytes); // S = H(A,B,Y,r) if (!key_hash->BeginKey(KeyBits)) return false; key_hash->Crunch(initiator_challenge, KeyBytes*2); // A key_hash->Crunch(B_neutral, KeyBytes*2); // B key_hash->Crunch(responder_answer, KeyBytes*3); // Y,r key_hash->End(); key_hash->Generate(S, KeyBytes); math->Load(S, KeyBytes, S); // Repeat while S is small } while (math->LessX(S, 1000)); // T = S*y + b (mod q) math->MulMod(S, y[ThisY], math->GetCurveQ(), T); // Should use Barrett reduction here if (math->Add(T, b, T)) math->Subtract(T, math->GetCurveQ(), T); while (!math->Less(T, math->GetCurveQ())) math->Subtract(T, math->GetCurveQ(), T); // T = AffineX(T * hA) math->PtMultiply(hA, T, 0, S); math->SaveAffineX(S, T); // k = H(d,T) if (!key_hash->BeginKDF()) return false; key_hash->Crunch(T, KeyBytes); key_hash->End(); // Generate responder proof of key Skein mac; if (!mac.SetKey(key_hash) || !mac.BeginMAC()) return false; mac.CrunchString("shfolder.dll"); mac.End(); mac.Generate(responder_answer + KeyBytes*3, KeyBytes); return true; }