Skip to main content
  • 产品
  • Evaluate our Software
  • 下载
  • Free Utilities
  • 购买
  • 支持
  • 关于我们
  • Search
    • Contact Us
    • Forum
    • Knowledge Base
    • Newsletter
    • RSS
  •   工作机会
  •   视频
  •   永续性
  • emCrypt
  • End-to-End Encryption
  • Technology
  • Examples

Secure communication with End-to-End encryption
Example applications

Contact us
Downloads
Documentation
SEGGER emCrypt
  1. 1.Example Application
  2. 2.End-to-End Encryption with emCrypt
  3. 3.Source Listing
  4. 4.Further Use

emCrypt includes all algorithms, functions and cryptography primitives to implement various security schemes and protocols. emSSL (SSL and TLS) and emSSH are most advanced protocols, using emCrypt as its foundation.

This application demonstrates how to easily enable end-to-end encrypted communication between two clients which may be directly connected or communicate via a server. The source code is a reference for authenticated and encrypted peer-to-peer communication in less than 300 lines of code.

Example Application

The Secure Communication Example demonstrates the use authentication and end-to-end encryption using a password.

emcrypt securecomm server

Secure Communication Server

emcrypt securecomm client

Secure Communication Client

emcrypt securecomm wireshark

Encrypted Communication on the wire

When the first instance of the application is started, it runs as the "server", waiting for a connection. When a second instance is started, it runs as the "client" and connects to the server.
In both cases the password needs to be entered, and it has to be the same for server and client.

When the client connects to the server, the server challenges the client to make sure it uses the same password, to authenticate it. Once the client is authenticated, server and client can compute the session key used to encrypt further communication. Now data can be sent from client to server and vice-versa.

Note: The application is built to open a connection on localhost. Both instances have to run on the same host. This is only done to make it easily usable without any firewall configuration. The example can be reused to open connections to any host or even be tunneled via a server both clients connect to.

End-to-End Encryption with emCrypt

For the end-to-end encryption this example uses the password-based encryption scheme (PBES2) and a symmetric key algorithm on two different keystreams to establish a secured full-duplex communication channel.

AES is chosen as the symmetric key algorithm.
It is used as a stream cipher in Output Feedback (OFB) mode or Counter with CBC-MAC (CCM) mode to encrypt each communication stream individually rather than each message.
While OFB mode only encrypts the stream, CCM mode also adds an authentication tag to each message, which ensures that the message has not been altered in transport.

Due to the symmetric key algorithm, both peers need to share the same keys, which are based on a password known to both sides.

To authenticate the client the Challenge Handshake Authentication Protocol (CHAP) is used.
CHAP makes sure that the peer knows the shared secret (the password) without transmitting it.

The session keys and keystreams are derived from the password and a random value using Password Based Key Derivation Function (PBKDF2), which makes sure that a new set of keys is used for each connection.

AES, PBKDF2, and SHA256 (used for CHAP), are available as part of emCrypt with ready-to-use APIs.
With these functions, end-to-end encryption can easily be implemented in any application.

No Encryption mode

Output Feedback (OFB) mode

CBC-MAC (CCM) mode

Source Listing

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

File        : MAIN_SERVER.c
Purpose     : Demonstrate how to setup a server/ client with E2EE using emCrypt.
*/

/*********************************************************************
*
*       #include section
*
**********************************************************************
*/

#include "CRYPTO.h"
#include "SYS.h"
#include <stdio.h>
#include <stdlib.h>

/*********************************************************************
*
*       Defines, fixed
*
**********************************************************************
*/
#define MODE_NONE 0
#define MODE_OFB  1
#define MODE_CCM  2

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
#define AES_MODE  MODE_OFB


#define COPYRIGHT_STRING      "emCrypt Communication Sample, (c) 2019 SEGGER Microcontroller GmbH."
#define DEFAULT_PASSWORD      "Secret"    // Default password
#define SERVER_LISTENER_PORT  (19099)     // TCP/IP port that server listens to
#define MAX_MSG_LEN           (2048)      // Maximum size (bytes) for a message. This includes a terminating \0.
#define MAX_MSG_OVERHEAD      (128)       // Maximum overhead from the encryption algorithm which is sent in addition th the message.
#define SERVER_CONN_ACCEPT    (0x00)      // Value sent by server on success
#define SERVER_CONN_DENY      (0xFF)      // Value sent by server on fail
#define TAG_LEN               16          // TagLen must be 4, 6, 8, 10, 12, 14, or 16.
#define IV_LEN                8           // Length of IV for CCM Mode. Must be between 7 and 13

/*********************************************************************
*
*       Local types
*
**********************************************************************
*/
typedef struct {
  CRYPTO_AES_CONTEXT CipherContext;
#if AES_MODE == MODE_OFB
  U8 aBlock[CRYPTO_AES_BLOCK_SIZE];
  unsigned Index;
#elif AES_MODE == MODE_CCM
  U8* pIV;
#endif
} KEYSTREAM;

typedef struct {
  U8  abPassword[32];
  U32 PasswordLen;
  U8  abSalt[16];
  U32 SaltLen;
  struct {
    U8 aToClientKey[CRYPTO_AES256_KEY_SIZE];
    U8 aToClientIV[CRYPTO_AES_BLOCK_SIZE];
    U8 aToServerKey[CRYPTO_AES256_KEY_SIZE];
    U8 aToServerIV[CRYPTO_AES_BLOCK_SIZE];
  } Session;
  // 
  KEYSTREAM ToClientKeystream;
  KEYSTREAM ToServerKeystream;
} CONNECTION_STATE;

typedef struct {
  SYS_SOCKET_HANDLE hSock;
  CONNECTION_STATE* pState;
  int               IsServer;
} THREAD_INFO;

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/

static volatile int _ErrorOccurred;  // Used by threads to determine if an error occurred

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/

/*********************************************************************
*
*       _DeriveKey()
*
*  Function description
*    Derive session keys.
*
*  Parameters
*    pState - Pointer to connection state.
*/
static void _DeriveKey(CONNECTION_STATE *pState) {
  //
  // Derive session data from "shared secret"
  //
  CRYPTO_PBKDF2_HMAC_SHA256_Calc(pState->abSalt, pState->SaltLen,
                                 pState->abPassword, pState->PasswordLen,
                                 10000,
                                 (U8 *)&pState->Session, sizeof(pState->Session));
  
  CRYPTO_AES_InitEncrypt(&pState->ToClientKeystream.CipherContext, pState->Session.aToClientKey, sizeof(pState->Session.aToClientKey));
  CRYPTO_AES_InitEncrypt(&pState->ToServerKeystream.CipherContext, pState->Session.aToServerKey, sizeof(pState->Session.aToServerKey));
#if AES_MODE == MODE_OFB
  CRYPTO_AES_Encrypt(&pState->ToClientKeystream.CipherContext, pState->ToClientKeystream.aBlock, pState->Session.aToClientIV);
  CRYPTO_AES_Encrypt(&pState->ToServerKeystream.CipherContext, pState->ToServerKeystream.aBlock, pState->Session.aToServerIV);
  pState->ToClientKeystream.Index = 0;
  pState->ToServerKeystream.Index = 0;
#elif AES_MODE == MODE_CCM
  pState->ToClientKeystream.pIV = pState->Session.aToClientIV;
  pState->ToServerKeystream.pIV = pState->Session.aToServerIV;
#endif

}

/*********************************************************************
*
*       _Encrypt()
*
*  Function description
*    Encrypt plain data.
*
*  Parameters
*    pState   - Pointer to connection state.
*    pSrc     - Source buffer.
*    pDest    - Destination buffer.
*    NumBytes - Length of buffers in bytes.
* 
*  Return Value
*    >= 0: Number of bytes to be sent.
*/
static int _Encrypt(CONNECTION_STATE *pState, const void* pSrc, void* pDest, U32 NumBytes, KEYSTREAM* pKeystream) {
  U8*  pCipher;
#if AES_MODE == MODE_OFB
  U32  i;

  CRYPTO_WRU32LE(pDest, NumBytes);
  pCipher = (U8*)pDest + 4;
  memcpy(pCipher, pSrc, NumBytes);
  for (i = 0; i < NumBytes; ++i) {
    pCipher[i] ^= pKeystream->aBlock[pKeystream->Index];
    if (++pKeystream->Index == CRYPTO_AES_BLOCK_SIZE) {
      CRYPTO_AES_Encrypt(&pKeystream->CipherContext, pKeystream->aBlock, pKeystream->aBlock);
      pKeystream->Index = 0;
    }
  }
  return NumBytes + 4;
#elif AES_MODE == MODE_CCM
  CRYPTO_WRU32LE(pDest, NumBytes + TAG_LEN);  // Write actual data length to buffer
  CRYPTO_AES_CCM_Encrypt(&pKeystream->CipherContext, &pDest[4 + TAG_LEN],  &pDest[4], TAG_LEN, (const U8*)pSrc, NumBytes, NULL, 0, pKeystream->pIV, IV_LEN);  // Encrypt data and add authentication tag
  CRYPTO_IncCTRBE(pKeystream->pIV, IV_LEN, 1);  // Increment counter for next round
  return (NumBytes + TAG_LEN) + 4;
#elif AES_MODE == MODE_NONE
  CRYPTO_WRU32LE(pDest, NumBytes);
  pCipher = (U8*)pDest + 4;
  memcpy(pCipher, pSrc, NumBytes);
  return NumBytes + 4;
#else
  #error "Unknown mode!"
#endif
}


/*********************************************************************
*
*       _Decrypt()
*
*  Function description
*    Decrypt encrypted data.
*
*  Parameters
*    pState   - Pointer to connection state.
*    pSrc     - Source buffer.
*    pDest    - Destination buffer.
*    NumBytes - Length of buffers in bytes.
*
*  Return Value
*   == 0: OK. (in CCM Mode: Calculated tag and given tag are identical).
*   != 0: Error (in CCM Mode: Calculated tag and given tag are not identical).
*/
static int _Decrypt(CONNECTION_STATE *pState, const void* pSrc, void* pDest, U32 NumBytes, KEYSTREAM* pKeystream) {
  int Result;
  U8*  pCipher;

#if AES_MODE == MODE_OFB
  U32  i;

  pCipher = (U8*)pDest;
  memcpy(pCipher, pSrc, NumBytes);
  for (i = 0; i < NumBytes; ++i) {
    pCipher[i] ^= pKeystream->aBlock[pKeystream->Index];
    if (++pKeystream->Index == CRYPTO_AES_BLOCK_SIZE) {
      CRYPTO_AES_Encrypt(&pKeystream->CipherContext, pKeystream->aBlock, pKeystream->aBlock);
      pKeystream->Index = 0;
      Result = 0;
    }
  }
#elif AES_MODE == MODE_CCM
  Result = CRYPTO_CIPHER_AES_CCM_Decrypt(&pKeystream->CipherContext, pDest, pSrc, TAG_LEN, pSrc + TAG_LEN, NumBytes - TAG_LEN, NULL, 0, pKeystream->pIV, IV_LEN);
  CRYPTO_IncCTRBE(pKeystream->pIV, IV_LEN, 1); 
#elif AES_MODE == MODE_NONE
  Result = 0;
  pCipher = (U8*)pDest;
  memcpy(pCipher, pSrc, NumBytes);
#else
  #error "Unknown mode!"
#endif

return Result;
}

/*********************************************************************
*
*       _SendThread()
*
*  Function description
*    Thread that is responsible for handling data to send from the server to the client.
*/
static SYS_THREAD_PROC_EX_TYPE _SendThread(void* p) {
  int Result;
  int r;
  U32 Len;
  char acIn [MAX_MSG_LEN];
  U8   abOut[MAX_MSG_LEN + MAX_MSG_OVERHEAD];
  THREAD_INFO* pInfo;
  KEYSTREAM* pKeystream;
  
  Result = 0;
  pInfo = (THREAD_INFO*)p;
  //
  // Set keystream to use for sending.
  //
  if (pInfo->IsServer == 1) {
    pKeystream = &pInfo->pState->ToClientKeystream;
  } else {
    pKeystream = &pInfo->pState->ToServerKeystream;
  }

  do {
    SYS_ConsoleGetString("", acIn, MAX_MSG_LEN);
    Len = strlen(acIn) + 1;  // Include terminating \0
    Len = _Encrypt(pInfo->pState, acIn, abOut, Len, pKeystream);
    r = SYS_SOCKET_Send(pInfo->hSock, abOut, Len);
    if (r != Len) {  // Failed to send data? => Done
      printf("ERROR: Failed to send data to client\n");
      Result = -1;
      _ErrorOccurred = 1;
      break;
    }
  } while (_ErrorOccurred == 0);

  return (SYS_THREAD_PROC_EX_R_TYPE)0;
}

/*********************************************************************
*
*       _RecvThread()
*
*  Function description
*    Thread that is responsible for handling data to receive by the server from the client.
*/
static SYS_THREAD_PROC_EX_TYPE _RecvThread(void* p) {
  int Result;
  int r;
  U32 Len;
  U8  abIn [MAX_MSG_LEN + MAX_MSG_OVERHEAD];
  U8  abOut[MAX_MSG_LEN];
  THREAD_INFO* pInfo;
  KEYSTREAM* pKeystream;

  Result = 0;
  pInfo = (THREAD_INFO*)p;

  if (pInfo->IsServer == 1) {
    pKeystream = &pInfo->pState->ToServerKeystream;
  } else {
    pKeystream = &pInfo->pState->ToClientKeystream;
  }

  do {
    r = SYS_SOCKET_IsReadable(pInfo->hSock, 100);  // Poll for data every 100 ms
    if (r == 0) {  // Nothing to read yet? => Try again.
      continue;
    }
    r = SYS_SOCKET_Receive(pInfo->hSock, abIn, 4);
    if (r <= 0) {
      printf("ERROR: Failed to receive data length from client\n");
      Result = -1;
      _ErrorOccurred = 1;
      break;
    }
    Len = CRYPTO_RDU32LE(&abIn[0]);
    r = SYS_SOCKET_Receive(pInfo->hSock, &abIn[4], Len);
    if (r <= 0) {
      printf("ERROR: Failed to receive data from client\n");
      Result = -1;
      _ErrorOccurred = 1;
      break;
    }
    _Decrypt(pInfo->pState, &abIn[4], abOut, Len, pKeystream);
    printf("%s\n", abOut);
  } while (_ErrorOccurred == 0);
  return (SYS_THREAD_PROC_EX_R_TYPE)0;
}

/*********************************************************************
*
*       _RunServer()
*
*  Function description
*    Runs server
*
*  Parameters
*    hSock    Opened TCP socket listening on SERVER_LISTENER_PORT
*
*/
static int _RunServer(SYS_SOCKET_HANDLE hSockListen) {
  U32      HashLen;
  U32      TmpLen;
  int      Result;
  int      r;
  char     acPass[32];
  const char* sPass;
  SYS_SOCKET_HANDLE hSockClient;
  U8       abTmp[256];  // Must be large enough to fit password + salt
  U8       abHash[32];
  U8       abClient[32];
  U8       Stat;
  CONNECTION_STATE* pState;
  THREAD_INFO* pThreadInfo;
  //
  // Start with title
  //
  Result      = 0;
  pState      = NULL;
  pThreadInfo = NULL;
  hSockClient = SYS_SOCKET_INVALID_HANDLE;
  printf("\n\n");
  printf(COPYRIGHT_STRING "\n");
  printf("Operating in server mode\n");
#if AES_MODE == MODE_OFB
  printf("The AES OFB encryption mode is used.\n");
#elif AES_MODE == MODE_CCM
  printf("The AES CCM encryption mode is used.\n");
#elif AES_MODE == MODE_NONE
  printf("No encryption mode is used.\n");
#else 
  #error "Unknown mode!"
#endif
  printf("\n\n");
  //
  // Generate random 16 byte salt
  //
  pState = (CONNECTION_STATE*)malloc(sizeof(CONNECTION_STATE));
  if (pState == NULL) {
    printf("ERROR: Insufficient memory.\n");
    Result = -1;
    goto Done;
  }
  memset(pState, 0, sizeof(CONNECTION_STATE));
  CRYPTO_Init();
  pState->SaltLen = sizeof(pState->abSalt);
  CRYPTO_RNG_Get(pState->abSalt, pState->SaltLen);
  //
  // Ask user for password to use
  //
  printf("Set the password (Default = \"%s\") ", DEFAULT_PASSWORD);
  SYS_ConsoleGetString("> ", acPass, sizeof(acPass));
  sPass = (acPass[0]) ? &acPass[0] : DEFAULT_PASSWORD;
  //
  // Append password to salt and generate hash
  // The resulting hash is the result of the challenge used by CHAP to authenticate a client.
  //
  pState->PasswordLen = strlen(sPass);
  memcpy(pState->abPassword, sPass, pState->PasswordLen + 1);
  HashLen = sizeof(abHash);
  memcpy(&abTmp[0], pState->abSalt, pState->SaltLen);
  memcpy(&abTmp[pState->SaltLen], pState->abPassword, pState->PasswordLen);
  TmpLen = pState->PasswordLen + pState->SaltLen;
  CRYPTO_SHA256_Calc(abHash, HashLen, abTmp, TmpLen);
  //
  // Wait for localhost client to connect
  //
  printf("Waiting for client to connect (Port = %d)...", SERVER_LISTENER_PORT);
  hSockClient = SYS_SOCKET_Accept(hSockListen);
  if (hSockListen == SYS_SOCKET_INVALID_HANDLE) {  // Failed to open socket?  => Done
    printf("ERROR: An error occurred while waiting for a client to connect.\n");
    Result = -1;
    goto Done;
  }
  printf("OK\n");
  //
  // After a client has connected, send challenge to client and wait for it to "solve" the challenge.
  //
  // <Direction>    <NumBytes>    <Explanation>
  // S -> C         16            Salt (Challenge)
  // C -> S         32            Hash (Result)
  // S -> C         1             Server status
  //
  SYS_SOCKET_SetBlocking(hSockClient);  // Make sure socket operations are blocking
  r = SYS_SOCKET_Send(hSockClient, pState->abSalt, pState->SaltLen);
  if (r != pState->SaltLen) {  // Failed to send challenge? => Done
    printf("ERROR: An error occurred while sending data to the client.\n");
    Result = -1;
    goto Done;
  }
  r = SYS_SOCKET_Receive(hSockClient, abClient, HashLen);
  if (r != HashLen) {  // Failed to receive data? => Done
    printf("ERROR: An error occurred while receiving data from the client.\n");
    Result = -1;
    goto Done;
  }
  r = memcmp(abClient, abHash, HashLen);                    // Compare client's response with expected hash value
  Stat = (r == 0) ? SERVER_CONN_ACCEPT : SERVER_CONN_DENY;
  SYS_SOCKET_Send(hSockClient, &Stat, 1);                   // Tell client if connection was accepted or denied
  if (r != 0) {                                             // Client's response is not correct? => Done
    printf("ERROR: Client failed to register (Incorrect password?).\n");
    Result = -1;
    goto Done;
  }
  //
  // After a successful authentication, E2EE communication between server and client can begin.
  // For that, a key is derived from the password and salt.
  //
  _DeriveKey(pState);
  pThreadInfo = (THREAD_INFO*)malloc(sizeof(THREAD_INFO));
  if (pThreadInfo == NULL) {
    printf("ERROR: Insufficient memory.\n");
    Result = -1;
    goto Done;
  }
  pThreadInfo->hSock  = hSockClient;
  pThreadInfo->pState = pState;
  pThreadInfo->IsServer = 1;
  SYS_SOCKET_SetNonBlocking(hSockClient);
  printf("\n========== Secure connection established. ==========\n========== Type anything and press <Enter> to send. ==========\n\n");
  SYS_CreateThreadEx(_SendThread, pThreadInfo, NULL, "Sender thread",   0);
  SYS_CreateThreadEx(_RecvThread, pThreadInfo, NULL, "Receiver thread", 0);
  //
  // From here on, the other threads handle further communication
  //
  while(_ErrorOccurred == 0);
  SYS_Sleep(100);            // If one thread reported an error, the other might still access some resources. Give the other thread enought time to terminate.
Done:
  //
  // Clean-up
  //
  if (hSockClient != SYS_SOCKET_INVALID_HANDLE) {
    SYS_SOCKET_Close(hSockClient);
  }
  if (hSockListen != SYS_SOCKET_INVALID_HANDLE) {
    SYS_SOCKET_Close(hSockListen);
  }
  if (pState) {
    free(pState);
  }
  if (pThreadInfo) {
    free(pThreadInfo);
  }
  return Result;
}

/*********************************************************************
*
*       _RunClient()
*
*  Function description
*    Runs client
*
*  Parameters
*    hSock    Opened TCP socket
*/
static int _RunClient(SYS_SOCKET_HANDLE hSock) {
  int   Result;
  int   r;
  U32   TmpLen;
  U32   HashLen;
  U8    abTmp[256];           // Must be large enough to fit password + salt
  U8    abHash[32];
  U8    Stat;
  char  acPass[32];
  const char* sPass;
  CONNECTION_STATE* pState;
  THREAD_INFO* pThreadInfo;
  //
  // Start with title
  //
  Result      = 0;
  pState      = NULL;
  pThreadInfo = NULL;
  printf("\n\n");
  printf(COPYRIGHT_STRING "\n");
  printf("Operating in client mode\n");
#if AES_MODE == MODE_OFB
  printf("The AES OFB encryption mode is used.\n");
#elif AES_MODE == MODE_CCM
  printf("The AES CCM encryption mode is used.\n");
#elif AES_MODE == MODE_NONE
  printf("No encryption mode is used.\n");
#else 
  #error "Unknown mode!"
#endif
  printf("\n\n");
  //
  // Connect to server
  //
  printf("Connecting to server...");
  SYS_SOCKET_SetBlocking(hSock);
  r = SYS_SOCKET_Connect(hSock, SYS_SOCKET_IP_ADDR_LOCALHOST, SERVER_LISTENER_PORT);
  if (r != 0) {  // Failed to connect? => Done
    printf("ERROR: Failed to connect to server.\n");
    Result = -1;
    goto Done;
  }
  printf("OK\n");
  //
  // Prompt user for password.
  // The password is needed for solving the server's challenge correctly
  //
  pState = (CONNECTION_STATE*)malloc(sizeof(CONNECTION_STATE));
  if (pState == NULL) {
    printf("ERROR: Insufficient memory.\n");
    Result = -1;
    goto Done;
  }
  memset(pState, 0, sizeof(CONNECTION_STATE));
  printf("Please enter the password (Default: \"%s\") ", DEFAULT_PASSWORD);
  SYS_ConsoleGetString("> ", acPass, sizeof(acPass));
  sPass = (acPass[0]) ? &acPass[0] : DEFAULT_PASSWORD;
  pState->PasswordLen = strlen(sPass);
  memcpy(pState->abPassword, sPass, pState->PasswordLen + 1);
  //
  // Receive and solve challenge from server
  // <Direction>    <NumBytes>    <Explanation>
  // S -> C         16            Salt (Challenge)
  //
  pState->SaltLen = sizeof(pState->abSalt);
  r = SYS_SOCKET_Receive(hSock, pState->abSalt, pState->SaltLen);
  if (r != pState->SaltLen) {
    printf("ERROR: Failed to receive data from server.\n");
    Result = -1;
    goto Done;
  }
  memcpy(&abTmp[0], pState->abSalt, pState->SaltLen);
  memcpy(&abTmp[pState->SaltLen], pState->abPassword, pState->PasswordLen);
  TmpLen = pState->PasswordLen + pState->SaltLen;
  HashLen = sizeof(abHash);
  CRYPTO_Init();
  CRYPTO_SHA256_Calc(abHash, HashLen, abTmp, TmpLen);
  //
  // Register at server using result of challenge
  // <Direction>    <NumBytes>    <Explanation>
  // C -> S         32            Hash (Result)
  // S -> C         1             Server status
  //
  r = SYS_SOCKET_Send(hSock, abHash, HashLen);
  if (r != HashLen) {
    printf("ERROR: Failed to send data to server.\n");
    Result = -1;
    goto Done;
  }
  r = SYS_SOCKET_Receive(hSock, &Stat, 1);  // Get status of connection
  if (r != 1) {
    printf("ERROR: Failed to receive data to server.\n");
    Result = -1;
    goto Done;
  }
  if (Stat != SERVER_CONN_ACCEPT) {
    printf("ERROR: Server denied connection (Incorrect password?).\n");
    Result = -1;
    goto Done;
  }
  //
  // After a successful authentication, E2EE communication between server and client can begin.
  // For that, a key is derived from the password and salt.
  //
  _DeriveKey(pState);
  pThreadInfo = (THREAD_INFO*)malloc(sizeof(THREAD_INFO));
  if (pThreadInfo == NULL) {
    printf("ERROR: Insufficient memory.\n");
    Result = -1;
    goto Done;
  }
  pThreadInfo->hSock  = hSock;
  pThreadInfo->pState = pState;
  pThreadInfo->IsServer = 0;
  SYS_SOCKET_SetNonBlocking(hSock);
  printf("\n========== Secure connection established. ==========\n========== Type anything and press <Enter> to send. ==========\n\n");
  SYS_CreateThreadEx(_SendThread, pThreadInfo, NULL, "Sender thread",   0);
  SYS_CreateThreadEx(_RecvThread, pThreadInfo, NULL, "Receiver thread", 0);
  //
  // From here on, the other threads handle further communication
  //
  while(_ErrorOccurred == 0);
  SYS_Sleep(100);            // If one thread reported an error, the other might still access some resources. Give the other thread enought time to terminate.
Done:
  //
  // Clean-up
  //
  if (hSock != SYS_SOCKET_INVALID_HANDLE) {
    SYS_SOCKET_Close(hSock);
  }
  if (pState) {
    free(pState);
  }
  if (pThreadInfo) {
    free(pThreadInfo);
  }
  return Result;
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
 
/*********************************************************************
*
*       main()
*
*  Function description
*    Main entry point for application.
*/
int main(void) {
  int Result;
  int r;
  SYS_SOCKET_HANDLE hSock;
  //
  // Determine if this is the server or client side
  //
  Result = 0;
  hSock  = SYS_SOCKET_OpenTCP();
  if (hSock == SYS_SOCKET_INVALID_HANDLE) {  // Failed to open socket?  => Done
    printf("ERROR: Failed to open TCP socket.\n");
    Result = -1;
    goto Done;
  }
  r = SYS_SOCKET_ListenAtTCPAddr(hSock, SYS_SOCKET_IP_ADDR_LOCALHOST, SERVER_LISTENER_PORT, 1);
  if (r == 0) {                  // We are able to listen at server listener port? => Run server
    Result = _RunServer(hSock);  // Blocking until server stops
  } else {                       // We cannot listen at server listener port? => Server must already be running so run client.
    Result = _RunClient(hSock);  // Blocking until client stops
  }
Done:
  return Result;
}

/*************************** End of file ****************************/

Further Use

The example demonstrates a simple use case of authentication and end-to-end encryption.

Key Agreement

In the example, the data used for authentication, the password and the salt, are used to generate the key for the encrypted communication, using PBKDF2. Other key agreement mechanisms, such as Diffie-Hellman Key Exchange (DH or ECDH) could be used to get an encryption key that is not associated with the authentication parameters.

全球总部

德国: SEGGER Microcontroller GmbH

地址: Ecolab-Allee 5
40789 Monheim am Rhein, Germany
电邮: info@segger.com
电话: +49-2173-99312-0
传真: +49-2173-99312-28

网点分布

中国:哲戈微系统科技(上海)有限公司

地址: 中国上海市闵行区秀涟路133号
大虹桥国际A 栋218室
邮编201199
电邮: china@segger.com
电话: +86-133-619-907-60

通过ISO 9001认证

ISO 9001

30多年的嵌入式行业经验

First-class embedded software tools since 1992
  • 版本说明
  • 免责声明
  • 隐私策略
  • 沪ICP备2022005181号
  • 沪公网安备 31011202014525号
© 2025 SEGGER - 版权所有.

您即将离开 segger.cn 而访问境外网站,是否继续?