Beispiel #1
0
static void PollVMStat(Skein &pool)
{
	const char *PATH = "vmstat -s";

	fd_set fds;
	FD_ZERO(&fds);

	if (!access(PATH, F_OK)) return;

	FILE *fp = popen(PATH, "r");
	if (!fp) return;

	int fd = fileno(fp);
	if (fd < 0) return;

	FD_SET(fd, &fds);

	timeval tv;
	tv.tv_sec = 5;
	tv.tv_usec = 0;

	int r;
	while ((r = select(1 + fd, &fds, 0, 0, &tv)))
	{
		if (r == -1 || !FD_ISSET(fd, &fds)) break;

		static u8 buffer[4096];
		int count = read(fd, buffer, sizeof(buffer));

		if (count > 0) pool.Crunch(buffer, count);
		else break;
	}

	pclose(fp);
	FD_CLR(fd, &fds);
}
bool KeyAgreementResponder::VerifyInitiatorIdentity(TunnelTLS *tls,
													const u8 *responder_answer, int answer_bytes,
													const u8 *proof, int proof_bytes,
													u8 *public_key, int public_bytes)
{
	CAT_DEBUG_ENFORCE(tls && tls->Valid() && proof_bytes == KeyBytes*5 && answer_bytes == KeyBytes*4 && public_bytes == KeyBytes*2);

	BigTwistedEdwards *math = tls->Math();

	/*
		Format of identity buffer:

		256-bit security: [Initiator Public Key] (64) || [Initiator Random Number] (32) || [Signature] (64)
	*/

	// Copied from Verify() in KeyAgreementInitiator.cpp

	Leg *e = math->Get(0);
	Leg *s = math->Get(1);
	Leg *Kp = math->Get(2);
	Leg *ep = math->Get(6);
	Leg *I_public = math->Get(7);

	// Load e, s from proof
	math->Load(proof + KeyBytes * 3, KeyBytes, e);
	math->Load(proof + KeyBytes * 4, KeyBytes, s);

	// e = e (mod q), for checking if it is congruent to q
	while (!math->Less(e, math->GetCurveQ()))
		math->Subtract(e, math->GetCurveQ(), e);

	// Check e, s are in the range [1,q-1]
	if (math->IsZero(e) || math->IsZero(s) ||
		!math->Less(e, math->GetCurveQ()) ||
		!math->Less(s, math->GetCurveQ()))
	{
		return false;
	}

	// Unpack the initiator's public key
	if (!math->LoadVerifyAffineXY(proof, proof + KeyBytes, I_public))
		return false;

	// Verify public point is not identity element
	if (math->IsAffineIdentity(I_public))
		return false;

	// Precompute a table for multiplication
	Leg *I_MultPrecomp = math->PtMultiplyPrecompAlloc(8);
	if (!I_MultPrecomp) return false;
	math->PtUnpack(I_public);
	math->PtMultiplyPrecomp(I_public, 8, I_MultPrecomp);

	// K' = s*G + e*I_public
	math->PtSiMultiply(G_MultPrecomp, I_MultPrecomp, 8, s, 0, e, 0, Kp);
	math->SaveAffineX(Kp, Kp);

	AlignedAllocator::ref()->Delete(I_MultPrecomp);

	// e' = H(IRN || RRN || K')
	Skein H;
	if (!H.BeginKey(KeyBits)) return false;
	H.Crunch(proof + KeyBytes * 2, KeyBytes); // client random number
	H.Crunch(responder_answer + KeyBytes * 2, KeyBytes); // server random number
	H.Crunch(Kp, KeyBytes);
	H.End();
	H.Generate(ep, KeyBytes);

	// Verify that e' == e
	bool success = SecureEqual(proof + KeyBytes * 3, ep, KeyBytes);

	// On successful identity verification, copy the public key to the destination
	if (success) memcpy(public_key, proof, KeyBytes*2);

	return success;
}
bool KeyAgreementResponder::Sign(TunnelTLS *tls,
								 const u8 *message, int message_bytes,
								 u8 *signature, int signature_bytes)
{
	CAT_DEBUG_ENFORCE(tls && tls->Valid() && signature_bytes == KeyBytes*2 && message_bytes >= 0);

	BigTwistedEdwards *math = tls->Math();

    Leg *k = math->Get(0);
    Leg *K = math->Get(1);
    Leg *e = math->Get(5);
    Leg *s = math->Get(6);

	do {

		do {

			// k = ephemeral key
			GenerateKey(tls, k);

			// K = k * G
			math->PtMultiply(G_MultPrecomp, 8, k, 0, K);
			math->SaveAffineX(K, K);

			// e = H(M || K)
			Skein H;

			if (!H.BeginKey(KeyBits)) return false;
			H.Crunch(message, message_bytes);
			H.Crunch(K, KeyBytes);
			H.End();
			H.Generate(signature, KeyBytes);

			math->Load(signature, KeyBytes, e);

			// e = e (mod q), for checking if it is congruent to q
			while (!math->Less(e, math->GetCurveQ()))
				math->Subtract(e, math->GetCurveQ(), e);

		} while (math->IsZero(e));

		// s = b * e (mod q)
		math->MulMod(b, e, math->GetCurveQ(), s);

		// s = -s (mod q)
		if (!math->IsZero(s)) math->Subtract(math->GetCurveQ(), s, s);

		// s = s + k (mod q)
		if (math->Add(s, k, s))
			while (!math->Subtract(s, math->GetCurveQ(), s));
		while (!math->Less(s, math->GetCurveQ()))
			math->Subtract(s, math->GetCurveQ(), s);

	} while (math->IsZero(s));

	math->Save(s, signature + KeyBytes, KeyBytes);

	// Erase the ephemeral secret from memory
	math->CopyX(0, k);

	return true;
}
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;
}