视频加密旨在通过对视频内容进行深度安全处理,确保视频数据不被非法获取和传播,可有效防止视频泄露和盗链问题,广泛用于在线教育及财经等对内容安全性要求高的领域。阿里云目前支持两种加密方式:阿里云私有加密(推荐)和HLS标准加密。本文介绍媒体处理HLS加密的原理和接入流程,帮助用户更好的理解和实施HLS加密,在保证视频安全的同时,实现流畅的在线播放体验。
使用场景
HLS标准数据加密适用于对视频进行保护的场景,可以防止非法下载和非法传播。
如果对安全有强需求,请开启工作流中的数据加密。详情参见 数据加密。
使用说明
HLS标准数据加密需要使用SubmitJobs接口。
工作流中不可使用HLS标准数据加密Base64方式。
标准加密技术原理请参考HLS标准加密。
示例代码依赖
MPS SDK详情参见 安装。
其他依赖:
<dependency> <groupId>com.aliyun</groupId> <artifactId>kms20160120</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.68.noneautotype</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.9</version> </dependency>
KMS方式加密(推荐)
加密转码
说明
如果您选择使用工作流来触发标准加密转码,您可以将文件重新上传至工作流指定的输入路径,或者通过使用AddMedia - 新增媒体来触发工作流。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import com.aliyun.tea.*;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class SubmitJobsForKMS {
/**
* <b>description</b> :
* <p>使用AK&SK初始化MPS账号Client</p>
* @return Client
*
* @throws Exception
*/
public static com.aliyun.mts20140618.Client createMTSClient() throws Exception {
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
config.endpoint = "mts.cn-shanghai.aliyuncs.com";
return new com.aliyun.mts20140618.Client(config);
}
/**
* <b>description</b> :
* <p>使用AK&SK初始化KMS账号Client</p>
* @return Client
*
* @throws Exception
*/
public static com.aliyun.kms20160120.Client createKMSClient() throws Exception {
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
config.endpoint = "kms.cn-shanghai.aliyuncs.com";
return new com.aliyun.kms20160120.Client(config);
}
/**
* 提交KMS加密转码
* @return
* @throws Exception
*/
public static void submitJobsForKMS() throws Exception {
//获取ciphertextBlob
JSONObject generateDataKey = getEncryptionConfigs();
String ciphertextBlob = generateDataKey.getString("ciphertextBlob");
System.out.println(ciphertextBlob);
//构建加密参数
JSONObject encryption = new JSONObject();
encryption.put("Type", "hls-aes-128");
encryption.put("Key", ciphertextBlob);
String url = "http://127.0.0.1:8888?Ciphertext=" + ciphertextBlob; // 解密地址,按需配置
encryption.put("KeyUri", Base64.encodeBase64URLSafeString(url.getBytes()));
encryption.put("KeyType", "KMS");
//构建input, 需要保证Location区域和服务client区域一致
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
//构建一个输出对象
JSONObject output = new JSONObject();
try {
input.put("Object", URLEncoder.encode("mps-test/input/test.mp4", "utf-8"));
output.put("OutputObject", URLEncoder.encode("mps-test/output/test", "utf-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("input URL encode failed");
}
output.put("TemplateId", "<transcode templateId>");
output.put("Encryption", encryption.toJSONString());
JSONArray outputs = new JSONArray();
outputs.add(output);
//提交标准加密转码
com.aliyun.mts20140618.Client client = SubmitJobsForKMS.createMTSClient();
com.aliyun.mts20140618.models.SubmitJobsRequest submitJobsRequest = new com.aliyun.mts20140618.models.SubmitJobsRequest()
//作业输入
.setInput(input.toJSONString())
//作业输出配置
.setOutputs(outputs.toJSONString())
//输出文件所在的OSS Bucket
.setOutputBucket("<your bucket name>")
//输出文件所在的 OSS Bucket 的地域(OSS Region)
.setOutputLocation("oss-cn-shanghai")
//管道ID
.setPipelineId("<transcode pipelineId>");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 复制代码运行请自行打印 API 的返回值
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
/**
* 请求KMS获取加密配置
* @returng
*/
private static JSONObject getEncryptionConfigs() throws Exception {
com.aliyun.kms20160120.Client client = SubmitJobsForKMS.createKMSClient();
com.aliyun.kms20160120.models.GenerateDataKeyRequest generateDataKeyRequest = new com.aliyun.kms20160120.models.GenerateDataKeyRequest();
//需换成KMS控制台的别名为alias/acs/mts的密钥。KMS控制台地址:https://kms.console.aliyun.com/cn-shanghai/key/list
generateDataKeyRequest.setKeyId("3f27f*************f");
generateDataKeyRequest.setKeySpec("AES_128");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 复制代码运行请自行打印 API 的返回值
com.aliyun.kms20160120.models.GenerateDataKeyResponse generateDataKeyResponse = client.generateDataKeyWithOptions(generateDataKeyRequest, runtime);
return JSONObject.parseObject(JSON.toJSONString(generateDataKeyResponse.getBody()));
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
return null;
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
return null;
}
}
public static void main(String[] args) throws Exception{
submitJobsForKMS();
}
}
解密服务
import com.aliyun.tea.TeaException;
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.HttpServerProvider;
import org.apache.commons.codec.binary.Base64;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DecryptServerKMS {
public static void main(String[] args) throws IOException {
DecryptServerKMS server = new DecryptServerKMS();
server.startService();
}
public class HlsDecryptHandler implements HttpHandler {
public void handle(HttpExchange httpExchange) throws IOException {
String requestMethod = httpExchange.getRequestMethod();
if(requestMethod.equalsIgnoreCase("GET")){
//从URL中取得密文密钥
String ciphertext = getCiphertext(httpExchange);
System.out.println(ciphertext);
if (null == ciphertext)
return;
//从KMS中解密出来,并Base64 decode
byte[] key = decrypt(ciphertext);
//设置header
setHeader(httpExchange, key);
//返回密钥
OutputStream responseBody = httpExchange.getResponseBody();
responseBody.write(key);
responseBody.close();
}
}
private void setHeader(HttpExchange httpExchange, byte[] key) throws IOException {
Headers responseHeaders = httpExchange.getResponseHeaders();
responseHeaders.set("Access-Control-Allow-Origin", "*");
httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, key.length);
}
private byte[] decrypt(String ciphertext) {
try {
com.aliyun.kms20160120.Client client = DecryptServerKMS.createKMSClient();
com.aliyun.kms20160120.models.DecryptRequest decryptRequest = new com.aliyun.kms20160120.models.DecryptRequest();
//需换成KMS控制台的别名为alias/acs/mts的密钥。KMS控制台地址:https://kms.console.aliyun.com/cn-shanghai/key/list
decryptRequest.setCiphertextBlob(ciphertext);
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
// 复制代码运行请自行打印 API 的返回值
com.aliyun.kms20160120.models.DecryptResponse decryptResponse = client.decryptWithOptions(decryptRequest, runtime);
String plaintext = decryptResponse.getBody().getPlaintext();
return Base64.decodeBase64(plaintext);
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
return null;
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
return null;
}
}
private String getCiphertext(HttpExchange httpExchange) {
URI uri = httpExchange.getRequestURI();
String queryString = uri.getQuery();
String pattern = "Ciphertext=(\\w*)";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(queryString);
if (m.find())
return m.group(1);
else {
System.out.println("Not Found Ciphertext");
return null;
}
}
}
/**
* 服务启动
*
* @throws IOException
*/
private void startService() throws IOException {
HttpServerProvider provider = HttpServerProvider.provider();
//监听端口8888,能同时接受30个请求, 可自行更改端口
HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(8888), 30);
httpserver.createContext("/", new HlsDecryptHandler());
httpserver.start();
System.out.println("no token hls decrypt server started");
}
/**
* <b>description</b> :
* <p>使用AK&SK初始化KMS账号Client</p>
* @return Client
*
* @throws Exception
*/
public static com.aliyun.kms20160120.Client createKMSClient() throws Exception {
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
config.endpoint = "kms.cn-shanghai.aliyuncs.com";
return new com.aliyun.kms20160120.Client(config);
}
}
Base64方式加密
加密转码
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.tea.TeaException;
import org.apache.commons.codec.binary.Base64;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class SubmitJobsForBase64 {
/**
* <b>description</b> :
* <p>使用AK&SK初始化MPS账号Client</p>
* @return Client
*
* @throws Exception
*/
public static com.aliyun.mts20140618.Client createClient() throws Exception {
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
config.endpoint = "mts.cn-shanghai.aliyuncs.com";
return new com.aliyun.mts20140618.Client(config);
}
/**
* 构建加密配置
* @return
*/
private static JSONObject getEncryptionConfigs() throws Exception {
JSONObject encryption = new JSONObject();
encryption.put("Type", "hls-aes-128");
//加密字符串必须是16位
encryption.put("Key", Base64.encodeBase64URLSafeString("encryptionkey128".getBytes()));
//url为您的解密服务地址
String url = "http://127.0.0.1:8888";
encryption.put("KeyUri", Base64.encodeBase64URLSafeString(url.getBytes()));
encryption.put("KeyType", "Base64");
return encryption;
}
/**
* 提交KMS加密转码
* @return
* @throws Exception
*/
public static void submitJobsForBase64() throws Exception {
//构建input, 需要保证Location区域和服务client区域一致
JSONObject input = new JSONObject();
input.put("Bucket", "<your bucket name>");
input.put("Location", "oss-cn-shanghai");
//构建一个输出对象
JSONObject output = new JSONObject();
try {
input.put("Object", URLEncoder.encode("mps-test/input/test.mp4", "utf-8"));
output.put("OutputObject", URLEncoder.encode("mps-test/output/test", "utf-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("input URL encode failed");
}
output.put("TemplateId", "<transcode templateId>");
output.put("Encryption", getEncryptionConfigs());
JSONArray outputs = new JSONArray();
outputs.add(output);
//提交标准加密转码
com.aliyun.mts20140618.Client client = SubmitJobsForKMS.createMTSClient();
com.aliyun.mts20140618.models.SubmitJobsRequest submitJobsRequest = new com.aliyun.mts20140618.models.SubmitJobsRequest()
//作业输入
.setInput(input.toJSONString())
//作业输出配置
.setOutputs(outputs.toJSONString())
//输出文件所在的OSS Bucket
.setOutputBucket("<your bucket name>")
//输出文件所在的 OSS Bucket 的地域(OSS Region)
.setOutputLocation("oss-cn-shanghai")
//管道ID
.setPipelineId("<transcode pipelineId>");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 复制代码运行请自行打印 API 的返回值
client.submitJobsWithOptions(submitJobsRequest, runtime);
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
public static void main(String[] args) throws Exception{
submitJobsForBase64();
}
}
解密服务
import com.sun.net.httpserver.*;
import com.sun.net.httpserver.spi.HttpServerProvider;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
public class DecryptServerBase64 {
public static void main(String[] args) throws IOException {
DecryptServerBase64 server = new DecryptServerBase64();
server.startService();
}
public class Base64DecryptHandler implements HttpHandler {
/**
* 处理解密请求
* @param httpExchange
* @throws IOException
*/
public void handle(HttpExchange httpExchange) throws IOException {
String requestMethod = httpExchange.getRequestMethod();
if ("GET".equalsIgnoreCase(requestMethod)) {
// 此处的解密密钥需要和加密时候的密钥一致
byte[] key = "encryptionkey128".getBytes();
// 设置header
setHeader(httpExchange, key);
// 返回base64decode之后的密钥
OutputStream responseBody = httpExchange.getResponseBody();
System.out.println(new String(key));
responseBody.write(key);
responseBody.close();
}
}
private void setHeader(HttpExchange httpExchange, byte[] key) throws IOException {
Headers responseHeaders = httpExchange.getResponseHeaders();
responseHeaders.set("Access-Control-Allow-Origin", "*");
httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, key.length);
}
}
/**
* 服务启动
* @throws IOException
*/
private void startService() throws IOException {
HttpServerProvider provider = HttpServerProvider.provider();
//监听端口8888,能同时接受30个请求
HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(8888), 30);
httpserver.createContext("/", new Base64DecryptHandler());
httpserver.start();
System.out.println("base64 hls decrypt server started");
}
}
相关文档
文档内容是否对您有帮助?