To improve data security, developers can encrypt users' media streams during the real-time engagement. Agora supports built-in encryption and customized encryption, and the differences between two encryption schemes are as follows:
You can choose an encryption schema according to your needs.
The following diagram describes the encrypted data transmission process:
Before enabling the encryption, ensure that you have implemented the basic real-time communication functions in your project. For details, see Start a Video Call or Start Live Interactive Video Streaming.
Before joining a channel, call enableEncryption
to enable the built-in encryption, and set the encryption mode and encryption key.
To implement the customized encryption, use IPacketObserver
class and registerPacketObserver
in C++ as follows:
Before joining a channel, call registerPacketObserver
to register the packet observer, so that you can receive events during audio or video packet transmission.
virtual int registerPacketObserver(IPacketObserver* observer);
Implement an IPacketObserver
class.
class IPacketObserver
{
public:
struct Packet
{
// Buffer address of the sent or received data.
const unsigned char* buffer;
// Buffer size of the sent or received data.
unsigned int size;
};
// Occurs when the local user sends an audio packet.
// The SDK triggers this callback before the audio packet is sent to the remote user.
// @param packet See Packet.
// @return
// - true: The audio packet is sent successfully.
// - false: The audio packet is discarded.
virtual bool onSendAudioPacket(Packet& packet) = 0;
// Occurs when the local user sends a video packet.
// The SDK triggers this callback before the video packet is sent to the remote user.
// @param packet See Packet.
// @return
// - true: The video packet is sent successfully.
// - false: The video packet is discarded.
virtual bool onSendVideoPacket(Packet& packet) = 0;
// Occurs when the local user receives an audio packet.
// The SDK triggers this callback before the audio packet of the remote user is received.
// @param packet See Packet.
// @return
// - true: The audio packet is sent successfully.
// - false: The audio packet is discarded.
virtual bool onReceiveAudioPacket(Packet& packet) = 0;
// Occurs when the local user receives a video packet.
// The SDK triggers this callback before the video packet of the remote user is received.
// @param packet See Packet.
// @return
// - true: The video packet is sent successfully.
// - false: The video packet is discarded.
virtual bool onReceiveVideoPacket(Packet& packet) = 0;
};
Inherit the IPacketObserver
class and use your customized encryption algorithm on your app.
class AgoraRTCPacketObserver : public agora::rtc::IPacketObserver
{
public:
EVP_CIPHER_CTX *ctx_audio_send;
EVP_CIPHER_CTX *ctx_audio_receive;
EVP_CIPHER_CTX *ctx_video_send;
EVP_CIPHER_CTX *ctx_video_receive;
AgoraRTCPacketObserver()
{
__android_log_print(ANDROID_LOG_INFO, "agoraencryption", "AgoraRTCPacketObserver0");
m_txAudioBuffer.resize(1024);
m_rxAudioBuffer.resize(1024);
m_txVideoBuffer.resize(1024);
m_rxVideoBuffer.resize(1024);
__android_log_print(ANDROID_LOG_INFO, "agoraencryption", "AgoraRTCPacketObserver1");
}
virtual bool onSendAudioPacket(Packet& packet)
{
int outlen;
// Encrypts the packet.
unsigned char outbuf[1024];
EVP_EncryptInit_ex(ctx_audio_send, EVP_aes_256_gcm(), NULL, NULL, NULL);
EVP_CIPHER_CTX_ctrl(ctx_audio_send, EVP_CTRL_GCM_SET_IVLEN, sizeof(gcm_iv), NULL);
EVP_EncryptInit_ex(ctx_audio_send, NULL, NULL, gcm_key, gcm_iv);
EVP_EncryptUpdate(ctx_audio_send, outbuf, &outlen, packet.buffer, packet.size);
// Sends the buffer and size of the encrypted data to the SDK.
packet.buffer = outbuf;
packet.size = outlen;
return true;
}
virtual bool onSendVideoPacket(Packet& packet)
{
int outlen;
// Encrypts the packet.
unsigned char outbuf[1024];
EVP_EncryptInit_ex(ctx_video_send, EVP_aes_256_gcm(), NULL, NULL, NULL);
EVP_CIPHER_CTX_ctrl(ctx_video_send, EVP_CTRL_GCM_SET_IVLEN, sizeof(gcm_iv), NULL);
EVP_EncryptInit_ex(ctx_video_send, NULL, NULL, gcm_key, gcm_iv);
EVP_EncryptUpdate(ctx_video_send, outbuf, &outlen, packet.buffer, packet.size);
// Sends the buffer and size of the encrypted data to the SDK.
packet.buffer = outbuf;
packet.size = outlen;
return true;
}
virtual bool onReceiveAudioPacket(Packet& packet)
{
int outlen;
// Decrypts the packet.
unsigned char outbuf[1024];
EVP_DecryptInit_ex(ctx_audio_receive, EVP_aes_256_gcm(), NULL, NULL, NULL);
EVP_CIPHER_CTX_ctrl(ctx_audio_receive, EVP_CTRL_GCM_SET_IVLEN, sizeof(gcm_iv), NULL);
EVP_DecryptInit_ex(ctx_audio_receive, NULL, NULL, gcm_key, gcm_iv);
EVP_DecryptUpdate(ctx_audio_receive, outbuf, &outlen, packet.buffer, packet.size);
// Sends the buffer and size of the decrypted data to the SDK.
packet.buffer = outbuf;
packet.size = outlen;
return true;
}
virtual bool onReceiveVideoPacket(Packet& packet)
{
int outlen;
// Decrypts the packet.
unsigned char outbuf[1024];
EVP_DecryptInit_ex(ctx_video_receive, EVP_aes_256_gcm(), NULL, NULL, NULL);
EVP_CIPHER_CTX_ctrl(ctx_video_receive, EVP_CTRL_GCM_SET_IVLEN, sizeof(gcm_iv), NULL);
EVP_DecryptInit_ex(ctx_video_receive, NULL, NULL, gcm_key, gcm_iv);
EVP_DecryptUpdate(ctx_video_receive, outbuf, &outlen, packet.buffer, packet.size);
// Sends the buffer and size of the decrypted data to the SDK.
packet.buffer = outbuf;
packet.size = outlen;
return true;
}
private:
// Sends the audio buffer.
std::vector<unsigned char> m_txAudioBuffer;
// Sends the video buffer.
std::vector<unsigned char> m_txVideoBuffer;
// Receives the audio buffer.
std::vector<unsigned char> m_rxAudioBuffer;
// Receives the video buffer.
std::vector<unsigned char> m_rxVideoBuffer;
};
Implement a Java wrapper. You can refer to the following example:
JNIEXPORT void JNICALL
Java_io_agora_api_streamencrypt_PacketProcessor_doRegisterProcessing
(JNIEnv *env, jobject obj)
{
__android_log_print(ANDROID_LOG_INFO, "agoraencryption", "doRegisterProcessing0");
if (!rtcEngine) return;
__android_log_print(ANDROID_LOG_INFO, "agoraencryption", "doRegisterProcessing1");
// Registers the packet observer.
int code = rtcEngine->registerPacketObserver(&s_packetObserver);
__android_log_print(ANDROID_LOG_INFO, "agoraencryption", "%d", code);
s_packetObserver.ctx_audio_send = EVP_CIPHER_CTX_new();
s_packetObserver.ctx_video_send = EVP_CIPHER_CTX_new();
s_packetObserver.ctx_audio_receive = EVP_CIPHER_CTX_new();
s_packetObserver.ctx_video_receive = EVP_CIPHER_CTX_new();
}
Call registerAgoraPacketObserver
implemented in step 4 to register the IPacketObserver
instance.
registerPacketObserver(nullptr)
method after leaving the channel.