9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* [9fans] dp9ik draft
@ 2015-10-19 19:25 cinap_lenrek
  2015-10-19 19:55 ` cinap_lenrek
  2015-10-20  3:33 ` cinap_lenrek
  0 siblings, 2 replies; 3+ messages in thread
From: cinap_lenrek @ 2015-10-19 19:25 UTC (permalink / raw)
  To: 9fans

requesting comments and questions.

later versions of this draft may be found under:

http://felloff.net/usr/cinap_lenrel/newticket.txt

Abstract:

The goal of this crypto scheme is to replace DES in the Plan 9 authentication
and to augment the authentication server with an authenticated key exchange
to prevent offline dictionary attacks on the user's secret key. We propose a
new protocol named dp9ik (Diffie-Hellman Plan 9 Intermediate Key) as an
alternative to p9sk1 that uses the new authsrv capabilities and can be
negotiated in p9any.

Problem:

The user's secret key is derived from a low entropy password that is prone
to dictionary attacks. With the old authserver protocol, it is easy for an
attacker to just try to decrypt tickets with a dictionary of DES keys.
The dictionary can be precomputed once and will then work forever for
all users as the key is only dependent on the password.
Tickets contain known plaintext that makes it easy to check if decryption
with a guessed key was successfull. Also due to the small 56-bit DES key size
it is possible to bruteforce the key with modest computing resources.

To address the small key size of DES, we replace the DES cipher with 128-bit AES,
introducing a bigger 128-bit key called the aeskey that is derived using an
expensive pbkdf2 key derivation function. Ticket encryption is changed to use
128-bit AES-CBC with hmac_sha2_256 for message authentication.

We add an authenticated elliptic curve Diffie-Hellman key exchange (AuthPAK)
at the beginning of a authsrv session to generate randomized intermediate
keys (pakkey) that are used to encrypt/decrypt the tickets instead of using
the user's secret keys directly. The public keys are derived in a way that
to complete the exchange requires the knowledge of the user's secret leaving
the attacker with only one password guess per ticket request making offline
bruteforce impossible.

aeskey[16]:

The 128-bit aeskey is derived from the password using pbkdf2_hmac_sha1 [rfc2898],
with the salt string "Plan 9 key derivation" (not including terminating null)
and iteration count 9001.

In addition to deriving the pakhash (see below), the aeskey is also used
for encrypting the keyfs user database on the authentication server, tho
details on this is beyond the scope of this document.

The aeskey is be stored along with the old DES key in nvram and keyfs.

pakhash[32]:

The 256-bit pakhash is used as the basepoint G on curve25519 for the
elliptic curve Diffie-Hellman exchange. It is derived from the aeskey
and the user name (id) so that each user gets a unique pakhash
even when different users share the same password.

Curve25519 scalars and compressed curve points are represented as
32 byte arrays in little endian order.

info = "Plan 9 AuthPAK hash";
salt = sha2_256(user);
x = hkdf_hmac_sha2_256(salt, info, aeskey);
x[31] = 0x40 | (x[31] & 0x7f);	// set bits 254-255 to 01 to prevent timing attacks
pakhash = curve25519(x, 9);

This calculation only needs to be done once and is reused in all
authentication sessions of the same user. The pakhash can be stored instead
of the aeskey or precomputed by keyfs to avoid some computational costs on
the authentication server.

pakkey[32]:

With the pakhash, two parties generate a new curve25519 Diffie Hellman
shared secret Z in the following way:

mkkey(){
	// generate 32 random bytes
	x = random()

	// curve25519 secret keys are defined as:
	// n ∈ { 2²⁵⁴ + 8{0,1,2,3,...,2²⁵¹-1} }
	// - Use a fixed position for the leading 1 in the secret key.
	//   (timing attacks)
	// - Multiply the secret key by a small power of 2 to account for
	//   cofactors in the curve group and the twist group.
	//   (small subgroup attacks)
	x[0] &= ~7;
	x[31] = 0x40 | (x[31] & 0x7f);

	return x
}

G = pakhash			(base point)
xa = mkkey()			(secret key)
Ya = curve25519(xa, G)		(public key)

G = pakhash			(base point)
xb = mkkey()			(secret key)
Yb = curve25519(xb, G)		(public key)

Exchange the public keys Ya and Yb, then both sides calculate:

Z				(shared secret)
= curve25519(xb, Ya)
= curve25519(xa, Yb)
= curve25519(xb, curve25519(xa, G))
= curve25519(xa, curve25519(xb, G))

The shared secret Z is then hashed to get the final pakkey:

info = "Plan 9 AuthPAK key"
salt = sha2_256(Ya | Yb)
pakkey = hkdf_hmac_sha2_256(salt, info, Z)

Note that we use a hash of the concatenation of the public keys Ya|Yb
as the salt to the key derivation function so that any manipulation on
the public keys in the message exchange causes a pakkey mismatch.

Client and server both establish new pakkeys with the authentication
server before each ticket request.

Dp9ik and authsrv protocol:

Dp9ik is is mostly the same as p9sk1, but at the beginning there is
the new AuthPAK (type 19) message sent to the authentication server
to exchange curve25519 public keys YAs/YBs and YAc/YBc and derive the
pakkeys. Ks and Kc are replaced by the pakkeys Zs and Zc. When using
AuthPAK, aes encrypted tickets are used as described later.

The expression K{M} means that message M is encrypted with key K

CHc	clients challenge
CHs	servers challenge
YAs	servers->as AuthPAK public key
YBs	as->server AuthPAK public key
YAc	client->as AuthPAK public key
YBc	as->clinet AuthPAK public key
Zs	servers pakkey
Zc	clients pakkey
Kn	ticket key, as random nonce
RNs	servers random nonce
RNc	clients random nonce

/* ticket request (dp9ik) */
C->S	CHc

S->C*	AuthPAK, IDs, DN, CHs, -, -, YAs
C->A*	AuthPAK, IDs, DN, CHs, IDc, IDr, YAc, YAs
A->C*	YBc, YBs

C->A	AuthTreq, IDs, DN, CHs, IDc, IDr
A->C	Zc{AuthTc, CHs, IDc, IDr, Kn}, Zs{AuthTs, CHs, IDc, IDr, Kn}
C->S*	YBs, Zs{AuthTs, CHs, IDc, IDr, Kn}, Kn{AuthAc, CHs, RNc}
S->C	Kn{AuthAs, CHc, RNs}

The AuthPAK message is used in other authsrv protocols as well,
so we give two examples here:

/* password change */
C->A*	AuthPAK, IDc, DN, -, -, -, YAc
A->C*	YBc

C->A	AuthPass, IDc, DN, CHc, IDc, IDc
A->C	Zc{AuthTp, CHc, IDc, IDc, Kn}
C->A	Kn{AuthPass, old, new, changesecret, secret}
A->C	AuthOK or AuthErr, 64-byte error message

/* auth chal */
S->A*	AuthPAK, IDs, DN, -, -, -, YAs
A->S*	YBs

S->A	AuthChal, IDs, DN, CHs, IDs, IDc
A->S	AuthOK, challenge
S->A	response
A->S	AuthOK, Zs{AuthChal, IDs, DN, CHs, IDs, IDc, Kn}, Kn{AuthTs, CHs}

When using AuthPAK, tickets and authenticators are generated as follows:

info = "Plan 9 ticket encryption"
salt = ticket_type
(iv[16] | ek[16] | mk[32]) = hkdf_hmac_sha2_256(salt, info, pakkey)

/* ticket */
ticket_type[8] = "form1 Tc" / "form1 Ts" / ...
ticket_cipher[96] {
	ticket[96] {
		chal[8]			/* CHs: server challenge */
		cuid[28]		/* IDc: uid on client */
		suid[28]		/* IDr: uid on server */
		key[32]	= random()	/* Kn: client/server nonce */
	}
} = aes_cbc(iv, ek, ticket)
ticket_mac[32] =  hmac_sha2_256(mk, ticket_cipher)

Client/server can exchange authenticators as usual with the
random nonce from the ticket to derive encryption and mac
keys:

info = "Plan 9 ticket encryption"
salt = authent_type
(iv[16] | ek[16] | mk[32]) = hkdf_hmac_sha2_256(salt, info, ticket.key)

/* authenticator */
authent_type[8] = "form1 Ac" / "form1 As" / ...
authent_cipher[40] {
	authent[40] {
		chal[8]			/* CHx: client/server challenge */
		rand[32] = random()	/* RNy: client/server random */
	}
} = aes_cbc(iv, ek, authent)
authent_mac[32]	= hmac_sha2_256(mk, authent_cipher)

Instead of using ticket.key directly as the session secret, for dp9ik,
we derive a 2048-bit session secret by concatenating the random nonces
from the authenticators and hash them with the ticket key.

info = "Plan 9 session secret";
salt = RNc | RNs
secret[256] = hkdf_hmac_sha2_256(salt, info, ticket.key)

This simplifies the implementation of establishing encryption as the
new session secret is big enough to be used directly for TLS/SSL encryption,
saving the roundtrip of exchanging extra nonces to get encryption keys.

Integration and backwards-compatibility:

It is not hard to see that there is no security improvement as long as
the authentication server keeps sending out old DES encrypted tickets
for p9sk1 with the user's deskey. In fact, the DES key and the password
that it was derived from sould be considered compromized. However,
we think it is neccesary to allow both protocols to run side by side
for some grace period until all hostowner keys have been assigned new
AES keys and software has been updated.

Test vectors:

passtokey(password="password") =
aeskey = 15D13256344211E56C52F50C539DE223
authpak_hash(aeskey, user="user") =
pakhash = C260896F7F69E21C98DDEC21FE0E25367CB3889AC6BC5E9E685B3B756D69F207
xa = C0E8A9AE21FB4D2FE02F2DCB516B6B0BB6A00D3DD78F350E106BDD7C0E4D3C67
Ya = DEC8685819C8B115E13785CD6F281F32DBB08E1FEA9623BA21008091D29CC366
xb = A8F0BCFC3894942A2ECFD63E15AA75900BA1135CB0B322FE617CF951D4344C6E
Yb = F7AE88AF3E7374C123D42E9E045CDF05F54F308722535594B03FF42A1BD1A16E
Z = B49A33CB1CD0CFE44141E90AA4A79701AB6142C02433FFE77FE8A52C1AC53510
sha2_256(Ya|Yb) = BA82F621BAB1F50967642E992306FAFDE7BC172C25DC2E499668441941B15CE4
pakkey = DFC0AC4AA87D73C186AB7FB4841DAB6532E60BA1C9C7B52DE77A12745414A7B2

References:

[curve25519] D.J. Bernstein. Curve25519: new Diffie-Hellman speed records.
[rfc2898] PKCS #5 Password-Based Cryptography Specification (PBKDF2)
[rfc5869] HMAC-based Extract-and-Expand Key Derivation Function (HKDF)

--
cinap



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [9fans] dp9ik draft
  2015-10-19 19:25 [9fans] dp9ik draft cinap_lenrek
@ 2015-10-19 19:55 ` cinap_lenrek
  2015-10-20  3:33 ` cinap_lenrek
  1 sibling, 0 replies; 3+ messages in thread
From: cinap_lenrek @ 2015-10-19 19:55 UTC (permalink / raw)
  To: 9fans

sorry, typoed the url:

http://felloff.net/usr/cinap_lenrek/newticket.txt

--
cinap



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [9fans] dp9ik draft
  2015-10-19 19:25 [9fans] dp9ik draft cinap_lenrek
  2015-10-19 19:55 ` cinap_lenrek
@ 2015-10-20  3:33 ` cinap_lenrek
  1 sibling, 0 replies; 3+ messages in thread
From: cinap_lenrek @ 2015-10-20  3:33 UTC (permalink / raw)
  To: 9fans

Robert Ransom pointed out offlist that the pak crypto is flawed in this
draft so its back to the drawing board. please consider this version
of the draft retracted :-)

> If an attacker can find scalars s1 and s2 such that s1*H(p1) =
> s2*H(p2), then he can send s1*H(p1) as his public key, receive the
> other party's public key P and a message encrypted using the resulting
> shared secret key, then compute both possible shared secrets s1*P and
> s2*P and try each of them to decrypt the message.
>
> If H(p) = p*G, then s1*H(p1) = s1*p1*G = s1*(p1/p2)*p2*G =
> s1*(p1/p2)*H(p2) (with the divisions and multiplications computed in
> the ring of scalars).

--
cinap



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2015-10-20  3:33 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-19 19:25 [9fans] dp9ik draft cinap_lenrek
2015-10-19 19:55 ` cinap_lenrek
2015-10-20  3:33 ` cinap_lenrek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).