SRP-6a. Secure authentication over an insecure channel

Brother

Professional
Messages
2,565
Reputation
3
Reaction score
363
Points
83
e2f3ca0f53ae7f4fe8c840549b008bd6.png


How do I authenticate a user without passing the password to the server? Is it possible to check that the user entered the correct password without passing the password to the server. Yes, this is possible thanks to zero knowledge proof.

Secure authentication consists of 2 factors - you need to provide a reliable channel between the client and the server and ensure that the authentication data is stored correctly on the server side. And despite the fact that the topic of storing passwords has long been crawled up and down, we constantly come across news about another leak of user data. Even large companies are often different (100 million VK user accounts leaked, LinkedIn users data leaked, Dropbox forcibly resets passwords after disclosing user credentials)

As for the secure channel, this is solved using HTTPS. However, in some cases, an MITM attack is possible. For example, a user might ignore a browser warning if someone is trying to spoof certificates, or it might be an employer looking to spy on their employees. These two problems can be solved by using the Secure Remote Password Protocol (SRP) .

The algorithm of work is similar to the Diffie-Hellman algorithm and allows you to authenticate the user on the server without transmitting the password in clear text, thus making sure that the user knows his password. On the server, the data is stored in a format that is not equivalent to the user's open password, so if the database leaks, it will not be possible to retrieve the password itself. And since Since the password is not transmitted over the communication channel at all, then a secure channel is not required. Zero knowledge proof is implemented.

Let's consider the basic principle of operation.

New User Registration​

First, you need to determine the constants necessary in the calculations:

g - generator

N is a safe prime N = 2q + 1 , where q is also a prime

Without going into mathematical details, the values of these numbers can be selected from RFC5054. A appendix. For a 1024-bit group, these values are as follows:

Code:
g = 2
N = EEAF0AB9 ADB38DD6 9C33F80A FA8FC5E8 60726187 75FF3C0B 9EA2314C 9C256576 D674DF74 96EA81D3 383B4813 D692C6E0 E0D5D8E2 50B98BE4 8E495C1D 6089DAD1 5DC7D7B4 6154D6B6 CE8EF4AD 69B15D49 82559B29 7BCF1885 C529F566 660E57EC 68EDBC3C 05726CC0 2FD4CBF4 976EAA9A FD5138FE 8376435B 9FC61D2F C0EB06E3

The user enters login I and password p , then the salt s is generated on the client side , the secret key x and the verifier v are calculated using the hash function H (for example SHA-256):

x = H ( s , p )

v = g x

And below Here, taken modulo exponentiation of N . The value of x can be calculated differently, for example x = H (s | H (I | ":" | p)) . Including the login in the formula for calculating x will avoid checking on the server whether 2 users have the same password in the event of a server hacking when the user tries to log in.

Then the client sends the values I , v , s to the server , and the server saves the values to the database. Here one problem is solved - if the database is stolen, it will not be possible to recover the password from the values of v and s .

User login​

The entrance is carried out in several stages

Step 1​

The user enters login I and password p . The client generates a random integer a , calculates the public value A :

a = random ()

A = ga


The I and A values are sent to the server.

The server checks that the value A ! = 0. By the login of the user I, the values s (salt) and v (verifier) saved during registration are fetched from the database. Next, a random integer b is generated and the public value B is calculated:

b = random ()

B = kv + gb
, where k = H (N, g)

The B and s values are passed to the client.

Step 2​

The client checks that B ! = 0 and calculates the values of the random encoding parameter u and the session key SC :

x = H ( s , p )

u = H ( A , B )

S C = ( B - kg x) ( a + ux )

Similarly, on its side, the server calculates its SS session key :

SS = (Avu) b


At this stage, the values of SC and SS are equal, which can be proved as follows:

S C = ( B - kg x) ( a + ux ) = ( kv + g b - kg x) ( a + ux ) = ( kg x - kg x + g b) (a + ux) = ( g b) ( a + ux )

SS = (Avu) b = ( g a v u) b = ( g a ( g x) u) b = ( ga + ux) b = (gb) (a + ux)

We got the same session key values on both sides without passing the verifier value. And the data that was transmitted is not enough to identify sensitive user data. This is the resistance of the protocol to eavesdropping and MITM attacks.

It remains to prove to each other that their key values are the same. To do this, it is necessary to calculate the M1 value on the client side and transmit it to the server. One of the calculation options:

M1 = H (A | B | SC)

Having received this value, the server calculates its value, since has all the parameters for this, and compares with the received one. Authentication completed.

Step 3 (optional)​

Required if mutual authentication is required. In this case, the server calculates the value of M2 and sends to the client:

M2 = H (A | M1 | SS)

Now the client calculates the value of M2 and verifies it with the received one. If they match, then the server can be trusted.

To minimize the number of requests to the server, let's group the calculations differently, then the process of interaction with the server can be represented by the following sequence diagram.

1cb2f0324ae1e02d56cff21fbfbde4c9.png

Implementation​

There are implementations for different programming languages. Let's look at an example of using the Nimbus SRP library for Java.

build.gradle:

Code:
implementation 'com.nimbusds: srp6a: 2.1.0'

Let's decide on the main parameters that must be the same on the client and server. For the sake of simplicity, we will not use too long values. In this case, let's choose the size N 256 bits, the SHA-1 encryption algorithm:

Code:
SRP6CryptoParams config = SRP6CryptoParams.getInstance (256, "SHA-1");

New User Registration:​

Code:
String login = "login";
String password = "password";

SRP6VerifierGenerator verifierGenerator = new SRP6VerifierGenerator(config);
BigInteger salt = new BigInteger(verifierGenerator.generateRandomSalt(16));
BigInteger verifier = verifierGenerator.generateVerifier(salt, password);

System.out.println("s: " + salt.toString(16));
System.out.println("v: " + verifier.toString(16));

execution result:

Code:
s: 293409259efcfa2aadd5a31a74d352f7
v: dba5a6de78e29592c945d5db33ea7f6d791fab0d64d8779be1aa58744628d27f

User login​

Customer. Step 1. Entering User Authentication Information

Code:
SRP6ClientSession clientSession = new SRP6ClientSession();
clientSession.step1(login, password);

Server. Step 1. Searching for a user in the database, calculating B

Code:
SRP6ServerSession serverSession = new SRP6ServerSession(config);
BigInteger B = serverSession.step1(login, salt, verifier);

System.out.println("s: " + salt.toString(16));
System.out.println("B: " + B.toString(16));

execution result:

Code:
s: 293409259efcfa2aadd5a31a74d352f7
B: dc9503a51480feb35ab1b250910576f0c4b64c9e6360da1d0adbae54d14391a5

Customer. Step 2. Calculate A and M1

Code:
SRP6ClientCredentials credentials = clientSession.step2(config, salt, B);
BigInteger A = credentials.A;
BigInteger M1 = credentials.M1;

System.out.println("A: " + A.toString(16));
System.out.println("M1: " + M1.toString(16));
System.out.println("Client session key: " + clientSession.getSessionKey().toString(16));

execution result:

Code:
A: 102a6b1605134f3da773b425cc5f214e0cc8b5375d12c187a6bda2b1aa7e30bd5
M1: 23b2e91d518c2a790bd0a13a6b259e29685b69fc
Client session key: 469c19e75c97e956d8b3080014f0eb876eef414181cfe288341aba6646e12c1e

Server. Step 2. Calculate M2

Code:
BigInteger M2 = serverSession.step2(A, M1);

System.out.println("M2: " + M2.toString(16));
System.out.println("Server session key: " + serverSession.getSessionKey().toString(16));

execution result:

Code:
M2: 9a0bf70c0881c99a35a48add34642f6168741060
Server session key: 469c19e75c97e956d8b3080014f0eb876eef414181cfe288341aba6646e12c1e

The M1 value calculated on the client side coincides with the same calculated on the server side, the values of the session keys also coincide. We made sure the user knows the password.

Output​

SRP is an excellent password authentication protocol, resistant to dictionary brute force, eavesdropping, spoofing. Authentication data is stored on the server in a form that does not allow retrieving the original password. Moreover, the algorithm can be used to encrypt the transmitted data.
 
Top