Skip to main content
  • 产品
  • Evaluate our Software
  • 下载
  • Free Utilities
  • 购买
  • 芯片厂商
  • 支持
  • 关于我们
  • Search
  • 工作机会
  • 新闻简报
  • 联系我们
  • emCrypt
  • End-to-End Encryption

    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.

    • User manual
    • List of downloads
    • Update notification
    • Pricing
    • Support

    全球总部

    德国: 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 而访问境外网站,是否继续?