Commit a6abf3e3 authored by johan's avatar johan

Add the SRTP and SAS derivation

parent 0f8f594e
......@@ -26,6 +26,23 @@
typedef struct bzrtpContext_struct bzrtpContext_t;
#include <stdint.h>
/**
* Some defines used internally by zrtp but also needed by client to interpretate the cipher block and auth tag algorithms used by srtp */
#define ZRTP_UNSET_ALGO 0x00
#define ZRTP_CIPHER_AES1 0x21
#define ZRTP_CIPHER_AES2 0x22
#define ZRTP_CIPHER_AES3 0x23
#define ZRTP_CIPHER_2FS1 0x24
#define ZRTP_CIPHER_2FS2 0x25
#define ZRTP_CIPHER_2FS3 0x26
#define ZRTP_AUTHTAG_HS32 0x31
#define ZRTP_AUTHTAG_HS80 0x32
#define ZRTP_AUTHTAG_SK32 0x33
#define ZRTP_AUTHTAG_SK64 0x34
/**
* brief The data structure containing the keys and algorithms to be used by srtp */
typedef struct bzrtpSrtpSecrets_struct {
......@@ -37,6 +54,10 @@ typedef struct bzrtpSrtpSecrets_struct {
uint8_t peerSrtpKeyLength; /**< The length in byte of the key */
uint8_t *peerSrtpSalt; /**< The salt used by local part to decrypt */
uint8_t peerSrtpSaltLength; /**< The length in byte of the salt */
uint8_t cipherAlgo; /**< The cipher block algorithm used by srtp */
uint8_t cipherKeyLength; /**< The key length in bytes for the cipher block algorithm used by srtp */
uint8_t authTagAlgo; /**< srtp authentication tag algorithm agreed on after Hello packet exchange */
char *sas; /* a null terminated char containing the Short Authentication String */
} bzrtpSrtpSecrets_t;
#define ZRTP_MAGIC_COOKIE 0x5a525450
......
......@@ -33,6 +33,7 @@
#define CRYPTOWRAPPER_H
#include <stdint.h>
#include "bzrtp/bzrtp.h"
/* define different types of crypto functions */
#define ZRTP_HASH_TYPE 0x01
......@@ -42,24 +43,15 @@
#define ZRTP_SAS_TYPE 0x10
/* map the differents algorithm (some may not be available) to integer */
#define ZRTP_UNSET_ALGO 0x00
#define ZRTP_HASH_S256 0x11
#define ZRTP_HASH_S384 0x12
#define ZRTP_HASH_N256 0x13
#define ZRTP_HASH_N384 0x14
#define ZRTP_CIPHER_AES1 0x21
#define ZRTP_CIPHER_AES2 0x22
#define ZRTP_CIPHER_AES3 0x23
#define ZRTP_CIPHER_2FS1 0x24
#define ZRTP_CIPHER_2FS2 0x25
#define ZRTP_CIPHER_2FS3 0x26
#define ZRTP_AUTHTAG_HS32 0x31
#define ZRTP_AUTHTAG_HS80 0x32
#define ZRTP_AUTHTAG_SK32 0x33
#define ZRTP_AUTHTAG_SK64 0x34
/*
* Cipher block and Auth Tag algo are used by SRTP, so the client will need their defines
* which are in bzrtp.h */
/* WARNING : it is very important to keep the key agreement defined in that order
* as it is used to easily sort them from faster(DH2k) to slower(EC52)
......
......@@ -457,6 +457,20 @@ int bzrtp_initChannelContext(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t
zrtpChannelContext->zrtpkeyi = NULL;
zrtpChannelContext->zrtpkeyr = NULL;
/* initialise srtpSecrets structure */
zrtpChannelContext->srtpSecrets.selfSrtpKey = NULL;
zrtpChannelContext->srtpSecrets.selfSrtpSalt = NULL;
zrtpChannelContext->srtpSecrets.peerSrtpKey = NULL;
zrtpChannelContext->srtpSecrets.peerSrtpSalt = NULL;
zrtpChannelContext->srtpSecrets.selfSrtpKeyLength = 0;
zrtpChannelContext->srtpSecrets.selfSrtpSaltLength = 0;
zrtpChannelContext->srtpSecrets.peerSrtpKeyLength = 0;
zrtpChannelContext->srtpSecrets.peerSrtpSaltLength = 0;
zrtpChannelContext->srtpSecrets.cipherAlgo = ZRTP_UNSET_ALGO;
zrtpChannelContext->srtpSecrets.cipherKeyLength = 0;
zrtpChannelContext->srtpSecrets.authTagAlgo = ZRTP_UNSET_ALGO;
zrtpChannelContext->srtpSecrets.sas = NULL;
return 0;
}
......
......@@ -77,6 +77,8 @@ int bzrtp_keyDerivationFunction(uint8_t *key, uint16_t keyLength,
/* call the hmac function */
hmacFunction(key, keyLength, input, inputLength, hmacLength, output);
free(input);
return 0;
}
......
......@@ -39,6 +39,7 @@ int bzrtp_responseToHelloMessage(bzrtpContext_t *zrtpContext, bzrtpChannelContex
int bzrtp_computeS0DHMMode(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext);
int bzrtp_computeS0MultiStreamMode(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext);
int bzrtp_deriveKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext);
int bzrtp_deriveSrtpKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext);
/*
* @brief This is the initial state
......@@ -1080,6 +1081,12 @@ int state_confirmation_responderSendingConfirm1(bzrtpEvent_t event) {
/* packet is valid, set the sequence Number in channel context */
zrtpChannelContext->peerSequenceNumber = zrtpPacket->sequenceNumber;
/* compute SAS and srtp secrets */
retval = bzrtp_deriveSrtpKeysFromS0(zrtpContext, zrtpChannelContext);
if (retval!=0) {
return retval;
}
/* create and send a conf2ACK packet */
bzrtpPacket_t *conf2ACKPacket = bzrtp_createZrtpPacket(zrtpContext, zrtpChannelContext, MSGTYPE_CONF2ACK, &retval);
if (retval!=0) {
......@@ -1163,13 +1170,18 @@ int state_confirmation_initiatorSendingConfirm2(bzrtpEvent_t event) {
/* save it so we can send it again if needed */
zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID] = confirm2Packet;
/* now send the confirm1 message */
/* now send the confirm2 message */
retval = zrtpContext->zrtpCallbacks.bzrtp_sendData(zrtpChannelContext->clientData, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->packetString, zrtpChannelContext->selfPackets[CONFIRM_MESSAGE_STORE_ID]->messageLength+ZRTP_PACKET_OVERHEAD);
if (retval != 0) {
return retval;
}
zrtpChannelContext->selfSequenceNumber++;
/* compute SAS and SRTP secrets as responder may directly send SRTP packets and non conf2ACK */
retval = bzrtp_deriveSrtpKeysFromS0(zrtpContext, zrtpChannelContext);
if (retval!=0) {
return retval;
}
/* it is the first call to this state function, so we must set the timer for retransmissions */
zrtpChannelContext->timer.status = BZRTP_TIMER_ON;
zrtpChannelContext->timer.firingTime = zrtpContext->timeReference + NON_HELLO_BASE_RETRANSMISSION_STEP;
......@@ -1807,30 +1819,87 @@ int bzrtp_deriveKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *z
return retval;
}
/* STATE MACHINE */
#ifdef PIPO
/* State type and variable, notice that it's a function pointer. */
typedef void (*State)(int);
State state;
/* A couple of state functions. */
void state_xyz(int event) { /*...*/ }
void state_init(int event) {
if (event == E_GO_TO_xyz) {
/* State transition done simply by changing the state to another function. */
state = state_xyz;
}
}
/**
* @brief This function is called after confirm1 is received by initiator or confirm2 by responder
* Keys computed are: srtp self and peer keys and salt, SAS(if mode is not multistream).
* The whole bzrtpSrtpSecrets_t structure is ready after this call
*
* param[in] zrtpContext The context we are operation on
* param[in/out] zrtpChannelContext The channel context we are operation on(contains s0 and will get the computed keys)
*
* return 0 on success, error code otherwise
*
*/
int bzrtp_deriveSrtpKeysFromS0(bzrtpContext_t *zrtpContext, bzrtpChannelContext_t *zrtpChannelContext) {
int retval = 0;
/* allocate memory */
uint8_t *srtpkeyi = (uint8_t *)malloc(zrtpChannelContext->cipherKeyLength*sizeof(uint8_t));
uint8_t *srtpkeyr = (uint8_t *)malloc(zrtpChannelContext->cipherKeyLength*sizeof(uint8_t));
uint8_t *srtpsalti = (uint8_t *)malloc(14*sizeof(uint8_t));/* salt length is defined to be 112 bits(14 bytes) in rfc section 4.5.3 */
uint8_t *srtpsaltr = (uint8_t *)malloc(14*sizeof(uint8_t));/* salt length is defined to be 112 bits(14 bytes) in rfc section 4.5.3 */
/* compute keys and salts according to rfc section 4.5.3 */
/* srtpkeyi = KDF(s0, "Initiator SRTP master key", KDF_Context, negotiated AES key length) */
retval = bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Initiator SRTP master key", 25, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpChannelContext->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, srtpkeyi);
/* srtpsalti = KDF(s0, "Initiator SRTP master salt", KDF_Context, 112) */
retval += bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Initiator SRTP master salt", 26, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, 14, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, srtpsalti);
/* srtpkeyr = KDF(s0, "Responder SRTP master key", KDF_Context, negotiated AES key length) */
retval += bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Responder SRTP master key", 25, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, zrtpChannelContext->cipherKeyLength, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, srtpkeyr);
/* srtpsaltr = KDF(s0, "Responder SRTP master salt", KDF_Context, 112) */
retval += bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength, (uint8_t *)"Responder SRTP master salt", 26, zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength, 14, (void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction, srtpsaltr);
if (retval!=0) {
free(srtpkeyi);
free(srtpkeyr);
free(srtpsalti);
free(srtpsaltr);
return retval;
}
/* Associate responder or initiator to self or peer. Self is used to locally encrypt and peer to decrypt */
if (zrtpChannelContext->role == INITIATOR) { /* we use keyi to encrypt and keyr to decrypt */
zrtpChannelContext->srtpSecrets.selfSrtpKey = srtpkeyi;
zrtpChannelContext->srtpSecrets.selfSrtpSalt = srtpsalti;
zrtpChannelContext->srtpSecrets.peerSrtpKey = srtpkeyr;
zrtpChannelContext->srtpSecrets.peerSrtpSalt = srtpsaltr;
} else { /* we use keyr to encrypt and keyi to decrypt */
zrtpChannelContext->srtpSecrets.selfSrtpKey = srtpkeyr;
zrtpChannelContext->srtpSecrets.selfSrtpSalt = srtpsaltr;
zrtpChannelContext->srtpSecrets.peerSrtpKey = srtpkeyi;
zrtpChannelContext->srtpSecrets.peerSrtpSalt = srtpsalti;
}
/* main contains the event loop here: */
int main() {
int e;
/* Initial state. */
state = state_init;
/* Receive event, dispatch it, repeat... No 'switch'! */
while ((e = wait_for_event()) != E_END) {
state(e);
}
return 0;
/* Set the lenght in secrets structure */
zrtpChannelContext->srtpSecrets.selfSrtpKeyLength = zrtpChannelContext->cipherKeyLength;
zrtpChannelContext->srtpSecrets.selfSrtpSaltLength = 14; /* salt length is defined to be 112 bits(14 bytes) in rfc section 4.5.3 */
zrtpChannelContext->srtpSecrets.peerSrtpKeyLength = zrtpChannelContext->cipherKeyLength;
zrtpChannelContext->srtpSecrets.peerSrtpSaltLength = 14; /* salt length is defined to be 112 bits(14 bytes) in rfc section 4.5.3 */
/* Set the used algo in secrets structure */
zrtpChannelContext->srtpSecrets.cipherAlgo = zrtpChannelContext->cipherAlgo;
zrtpChannelContext->srtpSecrets.cipherKeyLength = zrtpChannelContext->cipherKeyLength;
zrtpChannelContext->srtpSecrets.authTagAlgo = zrtpChannelContext->authTagAlgo;
/* compute the SAS according to rfc section 4.5.2 sashash = KDF(s0, "SAS", KDF_Context, 256) */
if (zrtpChannelContext->keyAgreementAlgo != ZRTP_KEYAGREEMENT_Mult) { /* only when not in Multistream mode */
uint8_t sasHash[32]; /* length of hash is 256 bits -> 32 bytes */
retval = bzrtp_keyDerivationFunction(zrtpChannelContext->s0, zrtpChannelContext->hashLength,
(uint8_t *)"SAS", 3,
zrtpChannelContext->KDFContext, zrtpChannelContext->KDFContextLength,
32,
(void (*)(uint8_t *, uint8_t, uint8_t *, uint32_t, uint8_t, uint8_t *))zrtpChannelContext->hmacFunction,
sasHash);
if (retval!=0) {
return retval;
}
/* now get it into a char according to the selected algo */
uint32_t sasValue = ((uint32_t)sasHash[0]<<24) | ((uint32_t)sasHash[1]<<16) | ((uint32_t)sasHash[2]<<8) | ((uint32_t)(sasHash[3]));
zrtpChannelContext->srtpSecrets.sas = malloc(5); /*this shall take in account the selected representation algo for SAS */
zrtpChannelContext->sasFunction(sasValue, zrtpChannelContext->srtpSecrets.sas);
zrtpChannelContext->srtpSecrets.sas[4] = '\0'; /* the sas function doesn't add the termination */
}
return 0;
}
#endif
......@@ -1546,7 +1546,7 @@ void test_stateMachine() {
printf ("Bob starts return %x\n", retval);
/* now start infinite loop until we reach secure state */
while ((getCurrentTimeInMs()-initialTime<7000)){
while ((getCurrentTimeInMs()-initialTime<3000)){
int i;
/* first check the message queue */
for (i=0; i<aliceQueueIndex; i++) {
......
......@@ -205,6 +205,15 @@ void dumpContext(char *title, bzrtpContext_t *zrtpContext) {
if (channelContext->s0 != NULL) {
printHex(" s0", channelContext->s0, channelContext->hashLength);
}
if(channelContext->srtpSecrets.sas != NULL) {
printf(" sas : %s\n", channelContext->srtpSecrets.sas);
}
if (channelContext->srtpSecrets.selfSrtpKey != NULL) {
printHex(" selfsrtp key", channelContext->srtpSecrets.selfSrtpKey, channelContext->srtpSecrets.selfSrtpKeyLength);
printHex(" selfsrtp salt", channelContext->srtpSecrets.selfSrtpSalt, channelContext->srtpSecrets.selfSrtpSaltLength);
printHex(" peersrtp key", channelContext->srtpSecrets.peerSrtpKey, channelContext->srtpSecrets.peerSrtpKeyLength);
printHex(" peersrtp salt", channelContext->srtpSecrets.peerSrtpSalt, channelContext->srtpSecrets.peerSrtpSaltLength);
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment