Skip to content

Instantly share code, notes, and snippets.

@Sc00bz
Last active January 15, 2023 11:38
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sc00bz/9d5c8e98143f68377e17dc82c5955f2b to your computer and use it in GitHub Desktop.
Save Sc00bz/9d5c8e98143f68377e17dc82c5955f2b to your computer and use it in GitHub Desktop.
PAKE API

PAKE API

Goal

The goal of this API is to make it easy to use and misuse resistant. The bulk of the code using this API can be reused. With the only difference being the start() call and getting the server secret at the end when registering. When registering, the server passes a null/empty secret to start() since it doesn't have one yet. Also start() might not return a message. This is fine. It just means the other party sends the first message.

Pseudocode API

PAKE_USER_CLIENT
PAKE_USER_SERVER
PAKE_USER_A
PAKE_USER_B
PAKE_USER_AB

PAKE_MODE_USE
PAKE_MODE_REGISTER
PAKE_MODE_ONLY_BLIND_SALT
PAKE_MODE_USE_AFTER_BLIND_SALT

PAKE_STATUS_FLAG_ERROR
PAKE_STATUS_FLAG_KEY_AVAILABLE
PAKE_STATUS_FLAG_SERVER_SECRET_AVAILABLE
PAKE_STATUS_FLAG_VERIFIED_OTHER
PAKE_STATUS_FLAG_FINISHED

message, status = start(myId, otherId, secret, pakeUser[, pakeMode = PAKE_MODE_USE])
message, status = receiveMessage(message)
key             = getKey()
serverSecret    = getServerSecret()

// optional
status          = getStatus()
size            = getMaxMessageSize()
size            = getKeySize()
size            = getServerSecretSize()

PAKE_USER_*

PAKE_USER_CLIENT and PAKE_USER_SERVER are for augmented PAKEs (aPAKE). PAKE_USER_A, PAKE_USER_B, and PAKE_USER_AB are for PAKEs. PAKE_USER_AB is for a PAKE that doesn't need to be told which user it is.

PAKE_MODE_*

PAKE_MODE_REGISTER is for generating the server secret for aPAKEs. Some aPAKEs will just be one message from the client to the server. An aPAKE with blind salt will take three messages. Unless it is implemented where the client uses the blind salt directly, but this probably shouldn't be done that way.

PAKE_MODE_ONLY_BLIND_SALT and PAKE_MODE_USE_AFTER_BLIND_SALT are for recovering a secret salt. PAKE_MODE_ONLY_BLIND_SALT is used first then PAKE_MODE_USE_AFTER_BLIND_SALT is used after the short salt ("guessing salt") brute force has finished or while brute forcing if guessing order is randomized. For more info see my blog post on recovering a secret salt.

PAKE_STATUS_FLAG_*

PAKE_STATUS_FLAG_KEY_AVAILABLE means you can call getKey() and encrypt data to the other party. In some cases PAKE_STATUS_FLAG_KEY_AVAILABLE will be set but PAKE_STATUS_FLAG_VERIFIED_OTHER and PAKE_STATUS_FLAG_FINISHED are not set. PAKE_STATUS_FLAG_SERVER_SECRET_AVAILABLE means you can call getServerSecret(). PAKE_STATUS_FLAG_VERIFIED_OTHER means you have checked the other party's verifier and it's correct. PAKE_STATUS_FLAG_FINISHED means you shouldn't receive any more messages. PAKE_STATUS_FLAG_ERROR happens if the other party's verifier failed, invalid message/data, or some other error.

start()

start() in some cases will not return a message. This is fine. It just means the other party sends the first message. The main reason for returning the status is the case of registering as a client and there is only one message from the client to the server. Thus the status after calling start() is PAKE_STATUS_FLAG_FINISHED. An error status can also be returned if say getting random failed.

message, status = start("carol", "steve", "password", PAKE_USER_CLIENT)
if (message)
	send(message)

receiveMessage()

When a message is received you pass it to receiveMessage() and it may return a message to send to the other party. The returned status tells you the state of the PAKE. Implementations of this function might choose to also take the secret. This is to prevent dynamic allocation and copying the secret in start() when acting as the client in an aPAKE or either party in a PAKE. But this should only be done if you need to be compatible with an existing PAKE implementation. To avoid dynamic allocation the API implementer can use H(id1, id2, secret) as the secret.

message, status = receiveMessage(message)
if (message)
	send(message)
if ((status & (PAKE_STATUS_FLAG_FINISHED | PAKE_STATUS_FLAG_ERROR)) != 0)
	return status

Optional functions

getStatus() doesn't need to be implemented since the status is returned in start() and receiveMessage(), but it might be nice to have for some developers depending on how they choose to implement using this API. Depending on language and implementation getMaxMessageSize(), getKeySize(), and getServerSecretSize() might not be needed or are just constants of similar names.

Pseudocode using the API

genericPake(message, status[, firstMessage])
{
	if (message)
		send(message)

	while ((status & (PAKE_STATUS_FLAG_FINISHED | PAKE_STATUS_FLAG_ERROR)) == 0)
	{
		// Note on connection close or timeout, `message`
		// should be empty so receiveMessage() will error
		message = recv()

		message, status = receiveMessage(message)
		if (message)
			send(message)

		// send encrypted `firstMessage`
		if (firstMessage && (status & PAKE_STATUS_FLAG_KEY_AVAILABLE) != 0)
		{
			key = getKey()
			send(encrypt(key, firstMessage))
			firstMessage = null
		}
	}

	// send encrypted `firstMessage`
	if (firstMessage && (status & PAKE_STATUS_FLAG_KEY_AVAILABLE) != 0)
	{
		key = getKey()
		send(encrypt(key, firstMessage))
	}

	return status & PAKE_STATUS_FLAG_ERROR
}

// Using an aPAKE as a client and sending an encrypted message as soon as key is available
message, status = start("carol", "steve", "password", PAKE_USER_CLIENT)
error = genericPake(message, status, "attack at dawn")
if (error == 0)
	...

// Registering with an aPAKE as a server
message, status = start("steve", "carol", null, PAKE_USER_SERVER, PAKE_MODE_REGISTER)
error = genericPake(message, status)
if (error == 0)
{
	serverSecret = getServerSecret()
	...
}

// Using a PAKE as user A (Alice)
message, status = start("alice", "bob", "password", PAKE_USER_A)
error = genericPake(message, status)
if (error == 0)
	...

License

This API is distributed under the terms of CC0. Assuming APIs can be copyrighted even though they shouldn't be copyrightable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment