Add MIKEY-SAKKE (ECCSI + SAKKE) example

Identity-based key exchange per RFC 6507-6509: KMS provisions user key
material, ECCSI signs the SAKKE-encapsulated SSV, receiver verifies
and derives the shared secret.
pull/610/head
Anthony 2026-07-24 15:18:48 -04:00 committed by Anthony Hu
parent 6398f4552f
commit 0aeba02dce
3 changed files with 353 additions and 0 deletions

View File

@ -0,0 +1,16 @@
CC=gcc
WOLFSSL_INSTALL_DIR=/usr/local
CFLAGS=-Wall -I$(WOLFSSL_INSTALL_DIR)/include
LIBS=-L$(WOLFSSL_INSTALL_DIR)/lib -lwolfssl -lm
mikey-sakke: mikey-sakke.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
.PHONY: clean check
clean:
rm -f *.o mikey-sakke
check: mikey-sakke
out=$$(./mikey-sakke) && printf '%s' "$$out" | grep -q 'Shared Secret Values match'
@echo "PASS: pk-mikey-sakke checks"

View File

@ -0,0 +1,44 @@
# wolfSSL MIKEY-SAKKE Example
Demonstrates the identity-based crypto behind MIKEY-SAKKE (Multimedia
Internet KEYing with Sakai-Kasahara Key Encryption, RFC 6509), the key
exchange used by secure-voice systems such as 3GPP Mission Critical Push To
Talk:
* ECCSI (Elliptic Curve-based Certificateless Signatures for Identity-based
encryption, RFC 6507) - identity-based signatures (`wc_*Eccsi*`)
* SAKKE (Sakai-Kasahara Key Encryption, RFC 6508) - identity-based key
encapsulation (`wc_*Sakke*`)
In identity-based crypto there are no per-user certificates: a user's public
key is their identity string (phone number, email). A Key Management Service
(KMS) holds master secrets and provisions each user's private material out of
band.
The example runs the whole flow in one program:
1. KMS creates master ECCSI and SAKKE keys.
2. KMS provisions Alice's ECCSI signing pair - Secret Signing Key (SSK) and
Public Validation Token (PVT) - for her identity, and Bob's SAKKE
Receiver Secret Key (RSK) for his.
3. Alice generates a 128-bit Shared Secret Value, encapsulates it to Bob's
identity, and ECCSI-signs the payload.
4. Bob verifies the signature against Alice's identity, derives the SSV with
his RSK, and both sides end up with the same session key.
## Building wolfSSL
```
./configure --enable-eccsi --enable-sakke
make
sudo make install
```
## Building and running the example
```
make
./mikey-sakke
```
Expected output ends with `Shared Secret Values match`.

View File

@ -0,0 +1,293 @@
/* mikey-sakke.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 the MIKEY-SAKKE identity-based key exchange (RFC 6507-6509):
* ECCSI signatures plus SAKKE key encapsulation.
*
* In identity-based crypto there are no per-user certificates: a user's
* public key IS their identity (e.g. a phone number or email). A Key
* Management Service (KMS) holds master secrets and provisions each user's
* key material out of band.
*
* Roles in this example:
* KMS: makes master ECCSI/SAKKE keys, provisions Alice's ECCSI signing
* pair (SSK, PVT) and Bob's SAKKE Receiver Secret Key (RSK).
* Alice: generates a Shared Secret Value (SSV), encapsulates it to Bob's
* identity, and signs the payload with ECCSI (RFC 6509 pattern).
* Bob: verifies Alice's ECCSI signature and derives the SSV with his
* RSK. Both then hold the same SSV for use as a session key. */
#include <stdio.h>
#include <string.h>
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/eccsi.h>
#include <wolfssl/wolfcrypt/sakke.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#if defined(WOLFCRYPT_HAVE_ECCSI) && defined(WOLFCRYPT_HAVE_SAKKE)
#define SSV_SZ 16
#define AUTH_SZ 257
#define ECCSI_SIG_SZ 129
#define PUB_KEY_SZ (32 * 2)
static const byte aliceId[] = "alice@example.com";
static const byte bobId[] = "bob@example.com";
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;
EccsiKey kmsEccsi; /* KMS master signing key */
EccsiKey userEccsi; /* Alice/Bob view: KMS public key only */
int kmsEccsiInit = 0;
int userEccsiInit = 0;
SakkeKey kmsSakke; /* KMS master encryption key */
SakkeKey userSakke; /* Alice/Bob view: KMS public key only */
int kmsSakkeInit = 0;
int userSakkeInit = 0;
mp_int ssk;
int sskInit = 0;
ecc_point* pvt = NULL;
ecc_point* rsk = NULL;
byte kpak[PUB_KEY_SZ]; /* KMS ECCSI public key */
word32 kpakSz = (word32)sizeof(kpak);
byte zpub[PUB_KEY_SZ * 4 + 1]; /* KMS SAKKE public key */
word32 zpubSz = (word32)sizeof(zpub);
byte hashId[WC_MAX_DIGEST_SIZE];
byte hashIdSz = 0;
byte ssv[SSV_SZ]; /* plaintext SSV (Alice's copy) */
word16 ssvSz = SSV_SZ;
byte payload[SSV_SZ + AUTH_SZ]; /* encapsulated SSV || auth */
word16 authSz = 0;
byte sig[ECCSI_SIG_SZ];
word32 sigSz = (word32)sizeof(sig);
int verified = 0;
ret = wc_InitRng(&rng);
if (ret != 0) {
printf("wc_InitRng failed %d\n", ret);
goto exit;
}
rngInit = 1;
/* --- KMS setup: master keys and per-user provisioning. --- */
ret = wc_InitEccsiKey(&kmsEccsi, NULL, INVALID_DEVID);
if (ret != 0)
goto exit;
kmsEccsiInit = 1;
ret = wc_MakeEccsiKey(&kmsEccsi, &rng);
if (ret != 0) {
printf("wc_MakeEccsiKey failed %d\n", ret);
goto exit;
}
ret = wc_InitSakkeKey(&kmsSakke, NULL, INVALID_DEVID);
if (ret != 0)
goto exit;
kmsSakkeInit = 1;
ret = wc_MakeSakkeKey(&kmsSakke, &rng);
if (ret != 0) {
printf("wc_MakeSakkeKey failed %d\n", ret);
goto exit;
}
printf("KMS: master ECCSI and SAKKE keys made\n");
/* Alice's ECCSI signing pair for her identity. */
ret = mp_init(&ssk);
if (ret != 0)
goto exit;
sskInit = 1;
pvt = wc_ecc_new_point();
rsk = wc_ecc_new_point();
if (pvt == NULL || rsk == NULL) {
ret = MEMORY_E;
goto exit;
}
ret = wc_MakeEccsiPair(&kmsEccsi, &rng, WC_HASH_TYPE_SHA256, aliceId,
(word32)sizeof(aliceId) - 1, &ssk, pvt);
if (ret != 0) {
printf("wc_MakeEccsiPair failed %d\n", ret);
goto exit;
}
printf("KMS: provisioned ECCSI pair for '%s'\n", (const char*)aliceId);
/* Bob's SAKKE RSK for his identity. */
ret = wc_MakeSakkeRsk(&kmsSakke, bobId, (word16)sizeof(bobId) - 1, rsk);
if (ret != 0) {
printf("wc_MakeSakkeRsk failed %d\n", ret);
goto exit;
}
printf("KMS: provisioned SAKKE RSK for '%s'\n", (const char*)bobId);
/* Users get only the KMS public keys. */
ret = wc_ExportEccsiPublicKey(&kmsEccsi, kpak, &kpakSz, 1);
if (ret == 0)
ret = wc_ExportSakkePublicKey(&kmsSakke, zpub, &zpubSz, 1);
if (ret != 0) {
printf("KMS public key export failed %d\n", ret);
goto exit;
}
ret = wc_InitEccsiKey(&userEccsi, NULL, INVALID_DEVID);
if (ret != 0)
goto exit;
userEccsiInit = 1;
ret = wc_ImportEccsiPublicKey(&userEccsi, kpak, kpakSz, 1);
if (ret != 0) {
printf("wc_ImportEccsiPublicKey failed %d\n", ret);
goto exit;
}
ret = wc_InitSakkeKey(&userSakke, NULL, INVALID_DEVID);
if (ret != 0)
goto exit;
userSakkeInit = 1;
ret = wc_ImportSakkePublicKey(&userSakke, zpub, zpubSz, 1);
if (ret != 0) {
printf("wc_ImportSakkePublicKey failed %d\n", ret);
goto exit;
}
/* --- Alice: encapsulate a fresh SSV to Bob's identity. --- */
ret = wc_SetSakkeIdentity(&userSakke, bobId, (word16)sizeof(bobId) - 1);
if (ret != 0)
goto exit;
authSz = AUTH_SZ;
ret = wc_GenerateSakkeSSV(&userSakke, &rng, ssv, &ssvSz);
if (ret != 0) {
printf("wc_GenerateSakkeSSV failed %d\n", ret);
goto exit;
}
print_hex("Alice: SSV", ssv, SSV_SZ);
/* Encapsulation masks the SSV in place; keep Alice's plaintext copy. */
memcpy(payload, ssv, SSV_SZ);
ret = wc_MakeSakkeEncapsulatedSSV(&userSakke, WC_HASH_TYPE_SHA256,
payload, SSV_SZ, payload + SSV_SZ,
&authSz);
if (ret != 0) {
printf("wc_MakeSakkeEncapsulatedSSV failed %d\n", ret);
goto exit;
}
printf("Alice: SSV encapsulated to '%s' (%u byte auth)\n",
(const char*)bobId, authSz);
/* Alice signs the whole payload with her identity's ECCSI pair. */
ret = wc_HashEccsiId(&userEccsi, WC_HASH_TYPE_SHA256, aliceId,
(word32)sizeof(aliceId) - 1, pvt, hashId, &hashIdSz);
if (ret == 0)
ret = wc_SetEccsiHash(&userEccsi, hashId, hashIdSz);
if (ret == 0)
ret = wc_SetEccsiPair(&userEccsi, &ssk, pvt);
if (ret == 0)
ret = wc_SignEccsiHash(&userEccsi, &rng, WC_HASH_TYPE_SHA256,
payload, SSV_SZ + authSz, sig, &sigSz);
if (ret != 0) {
printf("ECCSI signing failed %d\n", ret);
goto exit;
}
printf("Alice: payload signed with ECCSI (%u byte signature)\n", sigSz);
/* --- Bob: verify Alice's signature, then derive the SSV. --- */
ret = wc_HashEccsiId(&userEccsi, WC_HASH_TYPE_SHA256, aliceId,
(word32)sizeof(aliceId) - 1, pvt, hashId, &hashIdSz);
if (ret == 0)
ret = wc_SetEccsiHash(&userEccsi, hashId, hashIdSz);
if (ret == 0)
ret = wc_VerifyEccsiHash(&userEccsi, WC_HASH_TYPE_SHA256, payload,
SSV_SZ + authSz, sig, sigSz, &verified);
if (ret != 0 || !verified) {
printf("ECCSI verify failed: ret %d verified %d\n", ret, verified);
ret = -1;
goto exit;
}
printf("Bob: ECCSI signature from '%s' verified\n",
(const char*)aliceId);
/* Derivation unmasks the SSV in place and validates it against auth. */
ret = wc_SetSakkeRsk(&userSakke, rsk, NULL, 0);
if (ret == 0)
ret = wc_DeriveSakkeSSV(&userSakke, WC_HASH_TYPE_SHA256, payload,
SSV_SZ, payload + SSV_SZ, authSz);
if (ret != 0) {
printf("wc_DeriveSakkeSSV failed %d\n", ret);
goto exit;
}
print_hex("Bob: SSV", payload, SSV_SZ);
if (memcmp(ssv, payload, SSV_SZ) != 0) {
printf("SSVs differ!\n");
ret = -1;
goto exit;
}
printf("Shared Secret Values match\n");
ret = 0;
exit:
if (ret != 0)
printf("error %d: %s\n", ret, wc_GetErrorString(ret));
if (rsk != NULL)
wc_ecc_forcezero_point(rsk);
if (pvt != NULL)
wc_ecc_del_point(pvt);
if (rsk != NULL)
wc_ecc_del_point(rsk);
if (sskInit)
mp_forcezero(&ssk);
if (userSakkeInit)
wc_FreeSakkeKey(&userSakke);
if (kmsSakkeInit)
wc_FreeSakkeKey(&kmsSakke);
if (userEccsiInit)
wc_FreeEccsiKey(&userEccsi);
if (kmsEccsiInit)
wc_FreeEccsiKey(&kmsEccsi);
if (rngInit)
wc_FreeRng(&rng);
return ret == 0 ? 0 : 1;
}
#else
int main(void)
{
printf("Please build wolfSSL with ./configure --enable-eccsi "
"--enable-sakke\n");
return 0;
}
#endif /* WOLFCRYPT_HAVE_ECCSI && WOLFCRYPT_HAVE_SAKKE */