媒体流加密
更新时间: 2024/09/18 16:26:13
在金融行业等对用户隐私数据要求较高的行业场景中,往往需要额外采用媒体流加密方式保障用户数据在网络传输过程中的安全性、保障用户的信息安全和数据安全。网易云信在默认加密算法的基础上,提供了内置国密加密和自定义加密方案,进一步保障数据安全。
功能介绍
媒体流加密指在音视频流传输过程中对音视频数据进行加密,网易云信提供以下两种加密方式。
- 内置国密加密:使用 NERTC SDK 预置的国密加密模式给媒体流加密。
- 自定义加密:通过 NERTC SDK 提供的数据包观测器来自定义媒体流的加密模式。网易云信服务器可以对自定义加密后的媒体流进行传输,加解密均在客户端完成。
注意事项
- 您只可选择 SDK 内置的国密加密算法或自定义加密算法,两种加密算法不可同时使用,否则会报错
ENGINE_ERROR_INVALID_STATE(30005)
。 - 同一房间内,所有调用
enableEncrytion
方法开启媒体流加密的用户必须使用相同的加密模式、密钥等,否则加入房间时会报错kNERtcErrEncryptNotSuitable(30113)
。
内置加密的注意事项:
- 安全起见,若您选择 SDK 内置加密算法,建议每次启用媒体流加密时都更换新的密钥。
自定义加密的注意事项:
-
密钥等参数均由您自己的服务器进行分发。
-
若您选择自定义加密,请在创建房间前注册自定义加密对象,该房间的属性为“自定义加密房间”。后续用户必须也启用自定义加密才可成功加入,否则加入房间时会报错
kNERtcErrEncryptNotSuitable(30113)
。 -
加入“自定义加密房间”的双方若使用了不同的自定义加密算法,会强行进行加解密,会导致视频画面绿屏,音频机械音。
-
若要在某个 RTC 音视频通话房间中启用自定义加密,则必须保证加入房间的用户,使用 v4.6.53 及以上版本的 SDK(V5.3 版本不支持),且仅限 iOS、Android、Windows、macOS 和 Web 五个端,不支持小程序、Sip、Linux等其他平台客户端加入“自定义加密房间”。
-
使用了自定义加密的 RTC 音视频通话房间,不支持使用云端录制、云端播放、旁路推流等媒体服务,不支持安全通服务,不支持服务端本地录制服务。
开通媒体流加密
-
登录网易云信控制台。
-
在首页单击指定应用名称。
-
在产品总览区域,单击音视频通话 2.0 产品选项卡中的功能配置。
-
单击高级功能页签,单击 音视频媒体流加密 的开关按钮,开启媒体流加密。
-
单击确定。
内置加密
功能原理
启用内置国密加密的实现步骤:
- 您的服务端生成密钥和盐并加密传输给客户端。
- 用户 A 采集音视频流之后,通过
enableEncryption
启用加密并传入加密模式、密钥和盐,SDK 会用您选择的加密算法对音视频流进行加密,并将加密后的音视频流传输到网易云信音视频服务。 - 网易云信音视频服务中转加密的音视频流。
- 用户 B 收到音视频流之后,通过
enableEncryption
传入相同的加密模式、密钥和盐,SDK 会使用同样的加密算法和密钥对媒体流解密,并解码与渲染。
配置步骤
- 在您的服务端生成密钥。参考以下命令通过 OpenSSL 随机生成 String 型、16 字节的密钥。
// 随机生成一个 string 型、16 字节的密钥,并将该密钥传入 enableEncryption 的 config 参数。
openssl rand -hex 16
dba643c8ba6b6dc738df43d9fd624293b4b12d87a60f518253bd10ba98c48453
- 客户端从服务端获取 String 型密钥,并在加入房间前调用
enableEncryption
方法开启媒体流加密功能,设置媒体加密模式为kNERtcGMCryptoSM4ECB
,并在config
的key
参数中传入密钥。
- 加密模式目前仅支持国密 SM4 对称加密算法。
- 密钥由服务端生成,格式为 String 类型的字符串。
示例代码
bool encryptEnabled = true;
NSString* key = @"Your encrypt key";
nertc::NERtcEncryptionConfig config;
config.mode = nertc::kNERtcGMCryptoSM4ECB
memset(config.key, '\0', kNERtcEncryptByteLength);
memcpy(config.key, [key UTF8String], MIN(kNERtcEncryptByteLength, strlen([key UTF8String])));
nertc::IRtcEngineEx * rtcEngine = (nertc::IRtcEngineEx*)createNERtcEngine();
rtcEngine->enableEncryption(encryptEnabled, config);
自定义加密
功能原理
启用自定义加密的实现步骤:
- 您的服务端生成密钥并加密传输给客户端。
- 用户 A 采集音视频流之后,借助返回的音视频数据的缓存地址等信息启用自定义加密,SDK 会将加密后的音视频流传输到网易云信音视频服务。
- 网易云信音视频服务中转加密的音视频流。
- 用户 B 收到音视频流之后,借助返回的音视频数据的缓存地址等信息启用自定义解密,选择和用户 A 相同的加密算法对媒体流解密,SDK 会将解密后的媒体流进行解码与渲染。
配置步骤
您可以通过 enableEncryption
方法的 INERtcPacketObserver
类,进行监听自定义加密回调,实现自定义加密功能。参考步骤如下:
- 在初始化后加入房间前,调用
enableEncryption
方法开启媒体流加密功能,设置媒体加密模式为NERtcEncryptionModeCustom
, 在observer
参数中注册数据包观测器,监听数据包采集回调。 - 遵循
NERtcEnginePacketObserver
协议实现INERtcPacketObserver
自定义加密观察对象类,帮助您通过回调的音视频包相关参数进行自定义加密处理。 - 加入房间后通过
onSendAudioPacket
和onSendVideoPacket
回调的packet
参数进行自定义加密,或通过onReceiveAudioPacket
和onReceiveVideoPacket
回调的packet
参数进行自定义解密。 - 若您想取消自定义加密,请在离开房间后调用
enableEncryption
方法,指定config
中mode
为NERtcEncryptionModeCustom
, 并将enable
参数设置为false
。
示例代码
//step1:准备如下自定义加解密类,需要遵循NERtcEnginePacketObserver协议。
class NRTCEngineMediaPacketObserver : public nertc::INERtcPacketObserver
virtual bool onSendAudioPacket(nertc::NERtcMediaPacket &packet) override;
virtual bool onSendVideoPacket(nertc::NERtcMediaPacket &packet) override;
virtual bool onReceiveAudioPacket(nertc::NERtcMediaPacket &packet) override;
virtual bool onReceiveVideoPacket(nertc::NERtcMediaPacket &packet) override;
}
//发送视频包回调
bool NRTCEngine::onSendVideoPacket(nertc::NERtcMediaPacket &packet) {
//TODO 自定义加密处理
return true; //是否保留该包,YES为保留,NO为丢弃
}
//接收音频包回调
bool NRTCEngine::onReceiveAudioPacket(nertc::NERtcMediaPacket &packet) {
//TODO 自定义解密处理
return true; //是否保留该包,YES为保留,NO为丢弃
}
//接收视频包回调
bool NRTCEngine::onReceiveVideoPacket(nertc::NERtcMediaPacket &packet) {
//TODO 自定义解密处理
return true; //是否保留该包,YES为保留,NO为丢弃
}
//发送音频包回调
bool NRTCEngine::onSendAudioPacket(nertc::NERtcMediaPacket &packet) {
//TODO 自定义加密处理
return true; //是否保留该包,YES为保留,NO为丢弃
}
//step2:初始化引擎。
NRTCEngine nrtc_engine_;
nrtc_engine_.rtc_engine_ = (IRtcEngineEx *)createNERtcEngine();
memset(&nrtc_engine_.rtc_engine_context_, 0, sizeof(nertc::NERtcEngineContext));
nrtc_engine_.rtc_engine_context_.app_key = app_key_.c_str();
nrtc_engine_.rtc_engine_context_.log_dir_path = log_dir_path_.c_str();
nrtc_engine_.rtc_engine_context_.log_level = rtc_parameter_.log_level;
nrtc_engine_.rtc_engine_context_.log_file_max_size_KBytes = log_file_max_size_KBytes;
nrtc_engine_.rtc_engine_context_.event_handler = this;
nrtc_engine_.rtc_engine_context_.server_config = serverAddress;
nrtc_engine_.rtc_engine_->initialize(nrtc_engine_.rtc_engine_context_);
ediaStatsObserver,public nertc ::INERtcPacketObserver,{ int size = packet.size; int size = packet.size; int size = packet.size; int size = packet.size;
//step3:设置打开初始化加密
_mediaPacketObserver = new NRTCEngineMediaPacketObserver();
nertc::NERtcEncryptionConfig config;
config.mode = NERtcEncryptionModeCustom;
config.observer = _mediaPacketObserver;//注册观测器
nrtc_engine_->enableEncryption(true, config);
//step4:入会
nrtc_engine_.rtc_engine_->joinChannel(token, room_name, cur_my_uid_);