Add SRP-6a SHA-256 example

Full exchange (enrollment through mutual proof verification) using
SHA-256 and the RFC 5054 2048-bit group.
pull/610/head
Anthony 2026-07-24 15:18:48 -04:00 committed by Anthony Hu
parent 96fb285077
commit 6398f4552f
4 changed files with 274 additions and 3 deletions

View File

@ -4,7 +4,7 @@ CFLAGS=-Wall -I$(WOLFSSL_INSTALL_DIR)/include -g
#LIBS= -lwolfssl -lm
LIBS= -L$(WOLFSSL_INSTALL_DIR)/lib -lwolfssl -lm
all: srp srp_gen
all: srp srp_gen srp_sha256
srp.o: srp.c srp_params.h srp_store.h
$(CC) -c -o $@ srp.c $(CFLAGS)
@ -12,18 +12,25 @@ srp.o: srp.c srp_params.h srp_store.h
srp_gen.o: srp_gen.c srp_params.h
$(CC) -c -o $@ srp_gen.c $(CFLAGS)
srp_sha256.o: srp_sha256.c srp_params_2048.h
$(CC) -c -o $@ srp_sha256.c $(CFLAGS)
srp: srp.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
srp_gen: srp_gen.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
srp_sha256: srp_sha256.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
.PHONY: clean check
clean:
rm -f *.der *.x963 *.o srp srp_gen
rm -f *.der *.x963 *.o srp srp_gen srp_sha256
check: srp srp_gen
check: srp srp_gen srp_sha256
out=$$(./srp wolfssl password) && printf '%s' "$$out" | grep -q 'Client verified server proof'
out=$$(./srp_gen wolfssl password) && printf '%s' "$$out" | grep -qF 'static const byte verifier['
out=$$(./srp_sha256) && printf '%s' "$$out" | grep -q 'Session keys match'
@echo "PASS: pk-srp checks"

View File

@ -20,3 +20,10 @@ make
```
srp_sha256.c runs a complete SRP-6a exchange (enrollment through mutual proof
verification) using SHA-256 and the RFC 5054 2048-bit group:
```
./srp_sha256
```

View File

@ -0,0 +1,55 @@
/* srp_params_2048.h
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef SRP_PARAMS_2048_H
#define SRP_PARAMS_2048_H
/* 2048-bit group from RFC 5054 Appendix A. */
static const byte srp_n_2048[] = {
0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B, 0xF1, 0x66, 0xDE, 0x5E,
0x13, 0x89, 0x58, 0x2F, 0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07,
0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50, 0xA3, 0x73, 0x29, 0xCB,
0xB4, 0xA0, 0x99, 0xED, 0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D,
0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D, 0xCD, 0x7F, 0x48, 0xA9,
0xDA, 0x04, 0xFD, 0x50, 0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0,
0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3, 0x66, 0x1A, 0x05, 0xFB,
0xD5, 0xFA, 0xAA, 0xE8, 0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8,
0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA, 0xA8, 0x0D, 0x74, 0x0A,
0xDB, 0xF4, 0xFF, 0x74, 0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7,
0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B, 0xCA, 0x97, 0xB4, 0x3A,
0x23, 0xFB, 0x80, 0x16, 0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81,
0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A, 0x5B, 0x9D, 0x32, 0xE6,
0x88, 0xF8, 0x77, 0x48, 0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D,
0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA, 0x03, 0x2C, 0xFB, 0xDB,
0xF5, 0x2F, 0xB3, 0x78, 0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6,
0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29, 0x9C, 0xCC, 0x04, 0x1C,
0x7B, 0xC3, 0x08, 0xD8, 0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82,
0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6, 0x94, 0xB5, 0xC8, 0x03,
0xD8, 0x9F, 0x7A, 0xE4, 0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75,
0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, 0x0F, 0xA7, 0x11, 0x1F,
0x9E, 0x4A, 0xFF, 0x73
};
static const byte srp_g_2048[] = {
0x02
};
#endif /* SRP_PARAMS_2048_H */

202
pk/srp/srp_sha256.c 100644
View File

@ -0,0 +1,202 @@
/* srp_sha256.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* Example of a full SRP-6a exchange using SHA-256 and the RFC 5054 2048-bit
* group. Both sides run in this one program:
*
* enrollment: client derives a verifier from the password; server stores
* (username, salt, verifier) and never sees the password.
* login: both sides exchange public keys, compute the session key,
* and prove knowledge of it to each other. */
#include <stdio.h>
#include <string.h>
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/srp.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#ifdef WOLFCRYPT_HAVE_SRP
#include "srp_params_2048.h"
#define SALT_SZ 16
#define KEY_BUF_SZ 256
#define PROOF_SZ 64
static void print_hex(const char* label, const byte* data, word32 len)
{
word32 i;
printf("%s: ", label);
for (i = 0; i < len; i++)
printf("%02x", data[i]);
printf("\n");
}
int main(void)
{
int ret;
WC_RNG rng;
int rngInit = 0;
Srp cli;
Srp srv;
int cliInit = 0;
int srvInit = 0;
byte salt[SALT_SZ];
byte verifier[KEY_BUF_SZ];
word32 verifierSz = (word32)sizeof(verifier);
byte clientPub[KEY_BUF_SZ];
word32 clientPubSz = (word32)sizeof(clientPub);
byte serverPub[KEY_BUF_SZ];
word32 serverPubSz = (word32)sizeof(serverPub);
byte proof[PROOF_SZ];
word32 proofSz = (word32)sizeof(proof);
const char* username = "alice";
const char* password = "password123";
ret = wc_InitRng(&rng);
if (ret != 0) {
printf("wc_InitRng failed %d\n", ret);
goto exit;
}
rngInit = 1;
/* Enrollment: random salt, then a client-side object derives the
* verifier the server will store. */
ret = wc_RNG_GenerateBlock(&rng, salt, sizeof(salt));
if (ret != 0)
goto exit;
ret = wc_SrpInit(&cli, SRP_TYPE_SHA256, SRP_CLIENT_SIDE);
if (ret != 0)
goto exit;
cliInit = 1;
ret = wc_SrpSetUsername(&cli, (const byte*)username,
(word32)strlen(username));
if (ret == 0)
ret = wc_SrpSetParams(&cli, srp_n_2048, sizeof(srp_n_2048),
srp_g_2048, sizeof(srp_g_2048), salt,
sizeof(salt));
if (ret == 0)
ret = wc_SrpSetPassword(&cli, (const byte*)password,
(word32)strlen(password));
if (ret == 0)
ret = wc_SrpGetVerifier(&cli, verifier, &verifierSz);
if (ret != 0) {
printf("verifier generation failed %d\n", ret);
goto exit;
}
printf("Enrolled user '%s' (verifier %u bytes)\n", username, verifierSz);
/* Login: client computes its public key A. The enrollment object is
* reused; a real client would build a fresh one the same way. */
ret = wc_SrpGetPublic(&cli, clientPub, &clientPubSz);
if (ret != 0) {
printf("client wc_SrpGetPublic failed %d\n", ret);
goto exit;
}
/* Server loads the stored verifier and computes its public key B. */
ret = wc_SrpInit(&srv, SRP_TYPE_SHA256, SRP_SERVER_SIDE);
if (ret != 0)
goto exit;
srvInit = 1;
ret = wc_SrpSetUsername(&srv, (const byte*)username,
(word32)strlen(username));
if (ret == 0)
ret = wc_SrpSetParams(&srv, srp_n_2048, sizeof(srp_n_2048),
srp_g_2048, sizeof(srp_g_2048), salt,
sizeof(salt));
if (ret == 0)
ret = wc_SrpSetVerifier(&srv, verifier, verifierSz);
if (ret == 0)
ret = wc_SrpGetPublic(&srv, serverPub, &serverPubSz);
if (ret != 0) {
printf("server setup failed %d\n", ret);
goto exit;
}
/* Both sides derive the session key from the two public keys. */
ret = wc_SrpComputeKey(&cli, clientPub, clientPubSz, serverPub,
serverPubSz);
if (ret == 0)
ret = wc_SrpComputeKey(&srv, clientPub, clientPubSz, serverPub,
serverPubSz);
if (ret != 0) {
printf("wc_SrpComputeKey failed %d\n", ret);
goto exit;
}
/* Client proves first; only then does the server prove back. */
ret = wc_SrpGetProof(&cli, proof, &proofSz);
if (ret == 0)
ret = wc_SrpVerifyPeersProof(&srv, proof, proofSz);
if (ret != 0) {
printf("server rejected client proof %d\n", ret);
goto exit;
}
printf("Server verified client proof\n");
proofSz = (word32)sizeof(proof);
ret = wc_SrpGetProof(&srv, proof, &proofSz);
if (ret == 0)
ret = wc_SrpVerifyPeersProof(&cli, proof, proofSz);
if (ret != 0) {
printf("client rejected server proof %d\n", ret);
goto exit;
}
printf("Client verified server proof\n");
if (cli.keySz != srv.keySz ||
memcmp(cli.key, srv.key, cli.keySz) != 0) {
printf("Session keys differ!\n");
ret = -1;
goto exit;
}
print_hex("session key", cli.key, cli.keySz);
printf("Session keys match\n");
ret = 0;
exit:
if (srvInit)
wc_SrpTerm(&srv);
if (cliInit)
wc_SrpTerm(&cli);
if (rngInit)
wc_FreeRng(&rng);
return ret == 0 ? 0 : 1;
}
#else
int main(void)
{
printf("Please build wolfSSL with ./configure --enable-srp\n");
return 0;
}
#endif /* WOLFCRYPT_HAVE_SRP */