Data Encryption

Introduction

The Agora Native SDK allows your application to encrypt audio and video packets in one of the following ways:

Method Procedure Platform
Agora Built-in Encryption [1] Using Agora Native SDK Built-in Encryption Android/iOS/Windows/Mac/Web
Developer Customized Encryption Implementing Your Customized Data Encryption Algorithm Android/iOS/Windows/Mac

Footnotes

[1]For the communication scenario: if you want to use Agora Recording Server to record the communication, use Agora Built-in Encryption, otherwise, the recording is not supported. For the live broadcast: if you want to use CDN to push stream, record and store the recordings, do not use the data encryption function.

Using Agora Native SDK Built-in Encryption

Agora Native SDKs support built-in encryption using the AES-128 or AES-256 encryption algorithm.

The following diagram depicts the built-in encryption/decryption process:

map to buried treasure

Scenario 1: Do Not Use Encryption

Platform Procedure Description
Android Delete the independent dynamic library libagora-crypto.so in the SDK package you have downloaded from the downloads page. It reduces the SDK package size.
iOS Delete the encryption module AgoraRtcCryptoLoader.framework and the independent static library libcrypto.a in the SDK package you have downloaded from the downloads page. It reduces the SDK package size.
Windows/Mac/Web Do not need to take any action described in this document. It does not include any independent library for encryption.

Scenario 2: Use Encryption (Do Not Care about SDK Package Size)

Android

In the Agora Native SDK for Android package that you have downloaded from the downloads page, it includes an independent dynamic library libagora-crypto.so in both arm64-v8a and armeabi-v7a folder under /libs for the App to load dynamically.

  1. Put the libagora-crypto.so in the specified path of your project the same as libagora-rtc-sdk-jni.so.
  2. Call setEncryptionSecret to enable the encryption function.
  3. Call setEncryptionMode to set the encryption mode to be used.

Your data will be encrypted starting from now! Disable the encryption module by removing libagora-crypto.so added in Step 1 if necessary.

See the following table to check the detailed API explanations:

Live Broadcast Communication
Live Broadcast API - Android Communication API - Android

iOS

In the Agora Native SDK for iOS package that you have downloaded from the downloads page, it includes:

  • AgoraRtcCryptoLoader.framework: it is an independent static framework working as the encryption module.
  • libcrypto.a: it is a standard OpenSSL encryption library which is compatible with OpenSSL 1.0.2 or later.

It supports two languages: Objective-C and Swift.

For Objective-C:

  1. Set the search path of the framework in Xcode, and then add AgoraRtcCryptoLoader.framework and libcrypto.a in the build phase.
  2. Call setEncryptionSecret to enable the encryption function.
  3. Call setEncryptionMode to set the encryption mode to be used.

Your data will be encrypted starting from now! Disable the encryption module by removing libcrypto.a and AgoraRtcCryptoLoader.framework added in Step 1 if necessary.

See the following table to check the detailed API explanations:

Live Broadcast Communication
Live Broadcast API - iOS Communication API - iOS

For Swift:

  1. Set the search path of the framework in Xcode, and then add AgoraRtcCryptoLoader.framework and libcrypto.a in the build phase.
  2. Add #import <AgoraRtcCryptoLoader/AgoraRtcCryptoLoader.h> in the bridging file.
  3. Declare an AgoraRtcCryptoLoader Object in the place where AgoraRtcEngine is initialized to load the encryption module when compiling the link.
  4. Call setEncryptionSecret to enable the encryption function.
  5. Call setEncryptionMode to set the encryption mode to be used.

Your data will be encrypted starting from now! Disable the encryption module by removing libcrypto.a and AgoraRtcCryptoLoader.framework added in Step 1 if necessary.

Windows/Mac/Web

In the Agora Native SDK for Windows, Mac or Web package that you have downloaded from the downloads page, it does not include any independent library or encryption module for encryption.

  1. Call the API setEncryptionSecret to enable the encryption function.
  2. Call the API setEncryptionMode to set the encryption mode to be used.

Your data will be encrypted starting from now!

See the following table to check the detailed API explanations:

Live Broadcast Communication

Scenario 3: Use Encryption (Care about SDK Package Size)

  • For Mac, Windows, and Web, the procedure is the same as Scenario 2: Use Encryption (Do Not Care about SDK Package Size).
  • For Android, if the application already used libcrypto.so, it can share one libcrypto.so since the SDK package includes one libagora-crypto.so as well.
  • For iOS, if the application already used one libcrypto.a, it can share one libcrypto.a since the SDK package includes one libcrypto.a as well.

The only difference between the library provided by Agora and the one already used by application itself is that the version of the one provided by Agora is specified as 1.0.2g.

Implementing Your Customized Data Encryption Algorithm

The Agora Native SDK allows your application to encrypt audio and video packets by implementing the customized data encryption algorithm of your application.

The following diagram below depicts the data encryption/decryption process:

map to buried treasure

These are the steps:

Registering a Packet Observer

Agora Native SDK allows your application to register a packet observer to receive events whenever an audio or video packet is transmitting.

Register a packet observer on your application using the following API:

virtual int registerPacketObserver(IPacketObserver* observer);

The observer must inherit from agora::rtc::IPacketObserver and be implemented in C++. The following is the definition of the IPacketObserver class:

class IPacketObserver
{
public:

        struct Packet
        {
                const unsigned char* buffer;
                unsigned int size;
        };
        /**
        * called by sdk before the audio packet is sent to other participants
        * @param [in,out] packet:
        *      buffer *buffer points the data to be sent
        *      size of buffer data to be sent
        * @return returns true to send out the packet, returns false to discard the packet
        */
        virtual bool onSendAudioPacket(Packet& packet) = 0;
        /**
        * called by sdk before the video packet is sent to other participants
        * @param [in,out] packet:
        *      buffer *buffer points the data to be sent
        *      size of buffer data to be sent
        * @return returns true to send out the packet, returns false to discard the packet
        */


virtual bool onSendVideoPacket(Packet& packet) = 0;
        /**
        * called by sdk when the audio packet is received from other participants
        * @param [in,out] packet
        *      buffer *buffer points the data to be sent
        *      size of buffer data to be sent
        * @return returns true to process the packet, returns false to discard the packet
        */
        virtual bool onReceiveAudioPacket(Packet& packet) = 0;
        /**
        * called by sdk when the video packet is received from other participants
        * @param [in,out] packet
        *      buffer *buffer points the data to be sent
        *      size of buffer data to be sent
        * @return returns true to process the packet, returns false to discard the packet
        */
        virtual bool onReceiveVideoPacket(Packet& packet) = 0;

Implementing a Customized Data Encryption Algorithm

Inherit from agora::rtc::IPacketObserver to implement the customized data encryption algorithm on your application. The following example uses XOR for data processing. For Agora Native SDK, sending and receiving packets are handled by the different threads, which is why encryption and decryption can use different buffers:

class AgoraPacketObserver : public agora::rtc::IPacketObserver
 {
 public:
     AgoraPacketObserver()
     {
         m_txAudioBuffer.resize(2048);
         m_rxAudioBuffer.resize(2048);
         m_txVideoBuffer.resize(2048);
         m_rxVideoBuffer.resize(2048);
     }
     virtual bool onSendAudioPacket(Packet& packet)
     {
         int i;
         //encrypt the packet
         const unsigned char* p = packet.buffer;
         const unsigned char* pe = packet.buffer+packet.size;


                  for (i = 0; p < pe && i < m_txAudioBuffer.size(); ++p, ++i)
         {
             m_txAudioBuffer[i] = *p ^ 0x55;
         }
         //assign new buffer and the length back to SDK
         packet.buffer = &m_txAudioBuffer[0];
         packet.size = i;
         return true;
     }

     virtual bool onSendVideoPacket(Packet& packet)
     {
         int i;
         //encrypt the packet
         const unsigned char* p = packet.buffer;
         const unsigned char* pe = packet.buffer+packet.size;
         for (i = 0; p < pe && i < m_txVideoBuffer.size(); ++p, ++i)
         {
             m_txVideoBuffer[i] = *p ^ 0x55;
         }
         //assign new buffer and the length back to SDK
         packet.buffer = &m_txVideoBuffer[0];
         packet.size = i;
         return true;
     }

     virtual bool onReceiveAudioPacket(Packet& packet)
     {
         int i = 0;
         //decrypt the packet
         const unsigned char* p = packet.buffer;
         const unsigned char* pe = packet.buffer+packet.size;
         for (i = 0; p < pe && i < m_rxAudioBuffer.size(); ++p, ++i)
         {
             m_rxAudioBuffer[i] = *p ^ 0x55;
         }
         //assign new buffer and the length back to SDK
         packet.buffer = &m_rxAudioBuffer[0];
         packet.size = i;
         return true;
     }

     virtual bool onReceiveVideoPacket(Packet& packet)
     {
         int i = 0;
         //decrypt the packet
         const unsigned char* p = packet.buffer;
         const unsigned char* pe = packet.buffer+packet.size;


                 for (i = 0; p < pe && i < m_rxVideoBuffer.size(); ++p, ++i)
         {
             m_rxVideoBuffer[i] = *p ^ 0x55;
         }
         //assign new buffer and the length back to SDK
         packet.buffer = &m_rxVideoBuffer[0];
         packet.size = i;
         return true;
     }

 private:
     std::vector<unsigned char> m_txAudioBuffer; //buffer for sending audio data
     std::vector<unsigned char> m_txVideoBuffer; //buffer for sending video data

     std::vector<unsigned char> m_rxAudioBuffer; //buffer for receiving audio data
     std::vector<unsigned char> m_rxVideoBuffer; //buffer for receiving video data
 };

Registering Instance

Android

  1. Implement a Java wrapper.

For example,

  JNIEXPORT jint JNICALL Java_io_agora_video_demo_RtcEngineEncryption_enableEncryption(JNIEnv *env, jclass clazz, jlong engineHandle)
{
   typedef jint (*PFN_registerAgoraPacketObserver)(void* engine, agora::rtc::IPacketObserver* observer);

   void* handle = dlopen("libagora-rtc-sdk-jni.so", RTLD_LAZY);
   if (!handle)
   {
      __android_log_print(ANDROID_LOG_ERROR, "agora encrypt demo",

"cannot find libagora-rtc-sdk-jni.so");
      return -1;
   }
   PFN_registerAgoraPacketObserver pfn = (PFN_registerAgoraPacketObserver)dlsym(handle, "registerAgoraPacketObserver");
   if (!pfn)
   {
      __android_log_print(ANDROID_LOG_ERROR, "aogra encrypt demo", "cannot find registerAgoraPacketObserver");
      return -2;
   }
   return pfn((void*)engineHandle, &s_packetObserver);
}

Java wrapper:
public class RtcEngineEncryption {
    static {
        System.loadLibrary("agora-encrypt-demo-jni");
    }
    public static native int enableEncryption(long rtcEngineHandle);
}
  1. Call registerAgoraPacketObserver to register the instance of agora::rtc::IPacketObserver class implemented by your application:

iOS/Windows/Mac

Call registerAgoraPacketObserver to register the instance of agora::rtc::IPacketObserver class implemented by your application.