# Secure channel encryption (/en/realtime-media/video/build/secure-and-protect-channels/media-stream-encryption/windows)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

Media stream encryption refers to encrypting audio and video streams in an app using a unique [key](https://en.wikipedia.org/wiki/Public_key_certificate) and [salt](https://en.wikipedia.org/wiki/Salt_\(cryptography\)) controlled by the app developer. Encryption ensures that only the authorized users in a channel see and hear each other. Video SDK provides built-in encryption methods that you can use to guarantee data confidentiality during transmission.

This article describes how to integrate Agora built-in media stream encryption into your app.

## Understand the tech [#understand-the-tech]

The following figure illustrates the process of data transfer with media stream encryption enabled.

**Data transfer process**

![EncryptMediaStream](https://assets-docs.agora.io/images/video-sdk/encrypt_media_streams_dataTransferProcess-web.svg)

## Prerequisites [#prerequisites]

Ensure that you have implemented the [SDK quickstart](/en/realtime-media/video/get-started-sdk) in your project.

## Implement media stream encryption [#implement-media-stream-encryption]

      
  
      
  
      
  
      
    To add built-in media stream encryption to your app, refer to the following steps:

    1. Generate a key and salt on your server

       * To generate a random 32-byte hexadecimal key on your server as a string, refer to the following `OpenSSL` command:

         ```shell
         # Generate a 32-byte hexadecimal key
         openssl rand -hex 32
         ```

       * To generate a random Base64-encoded, 32-byte salt on your server, refer to the following `OpenSSL` command:

         ```shell
         # Generate a Base64-encoded, 32-byte salt
         openssl rand -base64 32
         ```

    2. Implement client-side logic

       1. Get the String key and Base64-encoded salt from the server.

       2. Convert salt from Base64 to `uint8_t`.

       3. Before joining the channel, call `enableEncryption` to set the `AES_128_GCM2` or `AES_256_GCM2` encryption mode, and pass the key and salt to the SDK.

       <CalloutContainer type="warning">
         <CalloutTitle>
           note
         </CalloutTitle>

         <CalloutDescription>
           * All users in a channel must use the same encryption mode, key, and salt. Discrepancies may lead to unexpected behavior, such as black screens or audio loss.
           * To ensure security, best practice is to use a new key and salt each time you enable media stream encryption.
         </CalloutDescription>
       </CalloutContainer>

       To implement this logic, refer to the following code:

       ```cpp
       #include <boost/algorithm/string/trim.hpp>
       #include <boost/archive/iterators/base64_from_binary.hpp>
       #include <boost/archive/iterators/binary_from_base64.hpp>
       #include <boost/archive/iterators/transform_width.hpp>
       #include <boost/range/algorithm/copy.hpp>

       namespace detail {
           using Base64FromBinary = boost::archive::iterators::base64_from_binary<
               boost::archive::iterators::transform_width<const char*, 6, 8>>;

           using BinaryFromBase64 = boost::archive::iterators::transform_width<
               boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
               8, 6>;
       }

       void decodeBase64(const std::string& encoded, std::vector<uint8_t>& out) {
           auto unpadded = encoded;
           const auto num_padded = std::count(begin(encoded), end(encoded), '=');
           std::replace(begin(unpadded), end(unpadded), '=', 'A');

           std::string decoded{
               detail::BinaryFromBase64{begin(unpadded)},
               detail::BinaryFromBase64{begin(unpadded) + unpadded.length()}};

           decoded.erase(end(decoded) - num_padded, end(decoded));
           std::copy(begin(decoded), end(decoded), out.begin());
       }

       int enableEncryption() {
           std::string secret;
           std::string kdfSaltBase64;
           std::vector<uint8_t> kdfSalt(32, 0);
           if (!getSecretAndSaltFromSever(secret, kdfSaltBase64)) return -1;
           if (rtcEngine) {
               decodeBase64(kdfSaltBase64, kdfSalt);
               agora::rtc::EncryptionConfig config;
               config.encryptionMode = AES_128_GCM2;
               config.encryptionKey = secret.c_str();
               memcpy(config.encryptionKdfSalt, kdfSalt.data(), sizeof(config.encryptionKdfSalt));
               return rtcEngine->enableEncryption(true, config);
           }
           return -1;
       }
       ```

    ### Development considerations [#development-considerations-3]

    The media stream encryption feature is supported in both communication and live broadcasting use-cases. However, in the live broadcasting use-case, Agora does not support pushing the encrypted media stream to CDN.

    ### API reference [#api-reference-3]

    * [`enableEncryption`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengine.html#api_irtcengine_enableencryption)
    * [`EncryptionConfig`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_encryptionconfig.html)

    
  
      
  
      
  
      
  
      
  
      
  
