关于Http Live Streaming的详细技术规范,请参考互联网工程小组的draft-pantos-http-live-streaming-05 specification。
在Wowza Stream Engine 4内部使用AES-128加密时,所有的内容切片和密钥都是由Wowza Stream Engine 4提供给播放器的。 此外,还有一个在Wowza外部使用AES-128加密的方法,在这个方式下,密钥是由一个外部的WEB服务器提供给播放器的。要了解更多,请阅读如何在Wowza外部采用AES-128对HLS的TS流进行加密。
要配置一个面向iOS设备提供hls流媒体的应用。请阅读Wowza Streaming Engine 4快速上手。
下面的模块是一个如何在内部采用AES-128对HLS的TS流进行加密的框架。下面的方法控制着加密流程:
- The onHTTPCupertinoEncryptionKeyRequest 方法用于对获取密钥的请求进行访问控制。这个方法内的代码还没有完全写完,需要补充一些保护密钥的业务逻辑。你可以在这里添加一些诸如检查URL查询参数、cookies或者其它request中的参数来控制对密钥的访问。
- The onHTTPCupertinoEncryptionKeyCreateLive 方法是在实时流每次开始推送(或拉)时被调用(就一次)。在这里你可以控制用于加密的密钥。你可以看到在这个方法中我们用共享密钥、当前流的上下文环境(应用名、应用实例名以及stream name)的组合创建了一个唯一的MD5摘要字符串。这将保证生成的密钥是唯一的。
- The onHTTPCupertinoEncryptionKeyCreateVOD 方法在每一个VOD连接请求时被调用。在这里,我们用共享密钥、sessoin id和当前流的上下文环境(应用名、应用实例名以及stream name)的组合为每一个session创建了密钥。
package com.wowza.wms.plugin.collection.module; import com.wowza.util.*; import com.wowza.wms.http.*; import com.wowza.wms.httpstreamer.cupertinostreaming.httpstreamer.*; import com.wowza.wms.module.*; import com.wowza.wms.application.*; public class ModuleEncryptionHandlerCupertinoStreaming extends ModuleBase { public void onHTTPCupertinoEncryptionKeyRequest(HTTPStreamerSessionCupertino httpCupertinoStreamingSession, IHTTPRequest req, IHTTPResponse resp) { boolean isGood = true; String ipAddress = httpCupertinoStreamingSession.getIpAddress(); String queryStr = req.getQueryString(); String referrer = httpCupertinoStreamingSession.getReferrer(); String cookieStr = httpCupertinoStreamingSession.getCookieStr(); String userAgent = httpCupertinoStreamingSession.getUserAgent(); String sessionId = httpCupertinoStreamingSession.getSessionId(); IApplicationInstance appInstance = httpCupertinoStreamingSession.getAppInstance(); String streamName = httpCupertinoStreamingSession.getStreamName(); // reject encryption key requests that are not delivered over SSL //if (!req.isSecure()) // isGood = false; getLogger().info("ModuleEncryptionHandlerCupertinoStreaming.onHTTPCupertinoEncryptionKeyRequest["+appInstance.getContextStr()+"/"+httpCupertinoStreamingSession.getStreamName()+"]: accept:"+isGood); if (!isGood) httpCupertinoStreamingSession.rejectSession(); } public void onHTTPCupertinoEncryptionKeyCreateLive(IApplicationInstance appInstance, String streamName, byte[] encKey) { String mySharedSecret = appInstance.getProperties().getPropertyStr("cupertinoEncryptionSharedSecret", ""); String hashStr = mySharedSecret+":"+appInstance.getApplication().getName()+":"+appInstance.getName()+":"+streamName; byte[] tmpBytes = MD5DigestUtils.generateHashBytes(hashStr); if (tmpBytes != null) System.arraycopy(tmpBytes, 0, encKey, 0, encKey.length); getLogger().info("ModuleEncryptionHandlerCupertinoStreaming.onHTTPCupertinoEncryptionKeyCreateLive["+appInstance.getContextStr()+"/"+streamName+"]: *"+BufferUtils.encodeHexString(encKey).substring(28)); } public void onHTTPCupertinoEncryptionKeyCreateVOD(HTTPStreamerSessionCupertino httpCupertinoStreamingSession, byte[] encKey) { String ipAddress = httpCupertinoStreamingSession.getIpAddress(); String queryStr = httpCupertinoStreamingSession.getQueryStr(); String referrer = httpCupertinoStreamingSession.getReferrer(); String cookieStr = httpCupertinoStreamingSession.getCookieStr(); String userAgent = httpCupertinoStreamingSession.getUserAgent(); IApplicationInstance appInstance = httpCupertinoStreamingSession.getAppInstance(); String streamName = httpCupertinoStreamingSession.getStreamName(); String sessionId = httpCupertinoStreamingSession.getSessionId(); String mySharedSecret = appInstance.getProperties().getPropertyStr("cupertinoEncryptionSharedSecret", ""); String hashStr = mySharedSecret+":"+(httpCupertinoStreamingSession.isHTTPOrigin() ? "" : sessionId+":")+appInstance.getApplication().getName()+":"+appInstance.getName()+":"+httpCupertinoStreamingSession.getStreamName(); byte[] tmpBytes = MD5DigestUtils.generateHashBytes(hashStr); if (tmpBytes != null) System.arraycopy(tmpBytes, 0, encKey, 0, encKey.length); getLogger().info("ModuleEncryptionHandlerCupertinoStreaming.onHTTPCupertinoEncryptionKeyCreateVOD["+appInstance.getContextStr()+"/"+httpCupertinoStreamingSession.getStreamName()+"]: *"+BufferUtils.encodeHexString(encKey).substring(28)); } }一个编译好的版本已经被包含在Wowza 模块集合中。下载并解开压缩包,将包中的/lib/wms-plugin-collection.jar 文件拷贝到Wowza Media Server 的安装路径的[install-dir]/lib中,然后重启服务器。
注意: 这个模块仅仅是对HLS流进行加密。如果你需要更好的控制整个Session,你就必须自己完成代码并使用Wowza IDE编译它。
接下来, 在[install-dir]/conf/[application]/Application.xml文件中的<Modules>列表的最后添加下面的模块:
<Module> <Name>ModuleEncryptionHandlerCupertinoStreaming</Name> <Description>ModuleEncryptionHandlerCupertinoStreaming</Description> <Class>com.wowza.wms.plugin.collection.module.ModuleEncryptionHandlerCupertinoStreaming</Class> </Module>将下面的属性添加到[install-dir]/conf/[application]/Application.xml文件最下面的的应用级别的<Properties>中:
<Property> <Name>cupertinoEncryptionBaseURL</Name> <Value>http://[wowza-ip-address]:1935</Value> </Property> <Property> <Name>cupertinoEncryptionSharedSecret</Name> <Value>[enckeysharedsecret]</Value> </Property> <Property> <Name>cupertinoEncryptionLiveRepeaterSharedSecret</Name> <Value>[mysharedsecret]</Value> </Property>将下面的属性添加到 [install-dir]/conf/[application]/Application.xml文件的HTTPStreamer/Properties中:
<Property> <Name>cupertinoEnableOnEncKey</Name> <Value>true</Value> <Type>Boolean</Type> </Property>
- cupertinoEncryptionBaseURL 是获取密钥的请求的base-URL。如果你配置使用SSL连接,请确定在URL中保留端口号(:1935), 并将URL的前缀从http://修改为https://, 另外最好使用域名而不是IP地址来指定Wowza Media Server。
- cupertinoEncryptionSharedSecret: 是共享密钥,它被用于采用Hash算法生成唯一加密密钥时的输入。上面的例子展示了它是被如何使用的。这个例子中的共享密钥为 1ghtY6D3Wgn.
- cupertinoEncryptionLiveRepeaterSharedSecret:是采用中心/边缘架构(origin/edge)时,将加密要由中心服务器向边缘服务器传递时采用的共享密钥。当配置边缘服务器提供直播服务时,请确定在边缘服务器上将cupertinoEncryptionLiveRepeaterSharedSecret 设置为相同的值。这个例子中这个值为3Er5sWl09xfE).
- cupertinoEnableOnEncKey 打开Wowza的内部加密密码传送功能。
如果你在Wowza nDVR使用这个机制,要设置的属性参数略有不同。请在[install-dir]/conf/[application]/Application.xml文件的DVR <Properties>中添加以下属性:
<Property> <Name>cupertinoEncryptionBaseURL</Name> <Value>http://[wowza-ip-address]:1935</Value> </Property> <Property> <Name>cupertinoEncryptionSharedSecret</Name> <Value>[enckeysharedsecret]</Value> </Property> <!-- This shared secret is for origin-edge and should be on both origin edge --> <Property> <Name>dvrEncryptionSharedSecret</Name> <Type>String</Type> <Value>[originedgesharedsecret]</Value> </Property>在[install-dir]/conf/[application]/Application.xml文件的HTTPStreamer/Properties中添加下面的属性:
<Property> <Name>cupertinoEnableOnEncKey</Name> <Value>true</Value> <Type>Boolean</Type> </Property>
注意: 关于对AES加密的测试,请阅读如何测试Apple HLS流媒体的AES加密功能。
注意: 对于加密密钥的传送,最好在[install-dir]/conf/VHost.xml文件的<HostPort>中配置使用SSL加密。这将保护加密要在传输中不被拦截。请阅读Wowza技术文档中的Wowza Streaming Engine用户使用手册了解更多关于SSL的配置。如果你配置在服务端口上使用SSL加密,请确定去掉if (!req.isSecure())的注释,并在onHTTPCupertinoEncryptionKeyRequest方法中检查以确定使用了SSL加密传输。