Android 视频文件加密

       项目开发中,之前一直是直接播放网络视频,后来要求加上视频缓存的功能,但是这些视频又都是要付费才能观看的,这就涉及到视频的版权问题。为了防止一个用户付费下载后,传播视频,就需要给视频文件加密,在播放时解密,只让视频在我的应用中播放。经过几天的百度、google,然后测试。找到了以下几种加密方法。

一、DES加密。用java中提供的加密包。加密代码如下:

package com.example.progressbardemo;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.SecretKeySpec;

/**
 * Created by Administrator on 2016/1/14.
 */
public class FileDES {
    /**
     * 加密解密的key
     */
    private Key mKey;
    /**
     * 解密的密码
     */
    private Cipher mDecryptCipher;
    /**
     * 加密的密码
     */
    private Cipher mEncryptCipher;

    public FileDES(String key) throws Exception {
        initKey(key);
        initCipher();
    }

    /**
     * 创建一个加密解密的key
     *
     * @param keyRule
     */
    public void initKey(String keyRule) {
        byte[] keyByte = keyRule.getBytes();
        // 创建一个空的八位数组,默认情况下为0
        byte[] byteTemp = new byte[8];
        // 将用户指定的规则转换成八位数组
        for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) {
            byteTemp[i] = keyByte[i];
        }
        mKey = new SecretKeySpec(byteTemp, "DES");
    }

    /***
     * 初始化加载密码
     *
     * @throws Exception
     */
    private void initCipher() throws Exception {
        mEncryptCipher = Cipher.getInstance("DES");
        mEncryptCipher.init(Cipher.ENCRYPT_MODE, mKey);

        mDecryptCipher = Cipher.getInstance("DES");
        mDecryptCipher.init(Cipher.DECRYPT_MODE, mKey);

    }

    /**
     * 加密文件
     *
     * @param in
     * @param savePath 加密后保存的位置
     */
    public void doEncryptFile(InputStream in, String savePath) {
        if (in == null) {
            System.out.println("inputstream is null");
            return;
        }
        try {
            CipherInputStream cin = new CipherInputStream(in, mEncryptCipher);
            OutputStream os = new FileOutputStream(savePath);
            byte[] bytes = new byte[1024];
            int len = -1;
            while ((len = cin.read(bytes)) > 0) {
                os.write(bytes, 0, len);
                os.flush();
            }
            os.close();
            cin.close();
            in.close();
            System.out.println("加密成功");
        } catch (Exception e) {
            System.out.println("加密失败");
            e.printStackTrace();
        }
    }

    /**
     * 加密文件
     *
     * @param filePath 需要加密的文件路径
     * @param savePath 加密后保存的位置
     * @throws FileNotFoundException
     */
    public void doEncryptFile(String filePath, String savePath) throws FileNotFoundException {
        doEncryptFile(new FileInputStream(filePath), savePath);
    }


    /**
     * 解密文件
     *
     * @param in
     */
    public void doDecryptFile(InputStream in, String path) {
        if (in == null) {
            System.out.println("inputstream is null");
            return;
        }
        try {
            CipherInputStream cin = new CipherInputStream(in, mDecryptCipher);
            OutputStream outputStream = new FileOutputStream(path);
            byte[] bytes = new byte[1024];
            int length = -1;
            while ((length = cin.read(bytes)) > 0) {
                outputStream.write(bytes, 0, length);
                outputStream.flush();
            }
            cin.close();
            in.close();
            System.out.println("解密成功");
        } catch (Exception e) {
            System.out.println("解密失败");
            e.printStackTrace();
        }
    }

    /**
     * 解密文件
     *
     * @param filePath 文件路径
     * @throws Exception
     */
    public void doDecryptFile(String filePath, String outPath) throws Exception {
        doDecryptFile(new FileInputStream(filePath), outPath);
    }


    public static void main(String[] args) throws Exception {
        FileDES fileDES = new FileDES("spring.sky");
        fileDES.doEncryptFile("d:/a.txt", "d:/b");  //加密
//        fileDES.doDecryptFile("d:/b"); //解密
    }

}
       经测试,15兆的视频,加密解密都可以成功,但是耗时太长,加密大概耗时20s。很显然,效率太低。视频文件一般都是几百兆,用此方法加密的时间就长的有点离谱了。

       上面这种方式是将视频文件中的每个字节都经过加密算法进行了加密,显示安全性比较高,耗时也长。但是视频文件比较特殊,我们只要将文件的前面多少个字节进行加密,这样播放器就无法识别这个文件的编码,就无法播放了。

二、将视频文件的数据流前100个字节中的每个字节与其下标进行异或运算。解密时只需将加密过的文件再进行一次异或运算即可。

加密解密方法如下:

private final int REVERSE_LENGTH = 100;
/**
 * 加解密
 *
 * @param strFile 源文件绝对路径
 * @return
 */
private boolean encrypt(String strFile) {
    int len = REVERSE_LENGTH;
    try {
        File f = new File(strFile);
        RandomAccessFile raf = new RandomAccessFile(f, "rw");
        long totalLen = raf.length();

        if (totalLen < REVERSE_LENGTH)
            len = (int) totalLen;

        FileChannel channel = raf.getChannel();
        MappedByteBuffer buffer = channel.map(
                FileChannel.MapMode.READ_WRITE, 0, REVERSE_LENGTH);
        byte tmp;
        for (int i = 0; i < len; ++i) {
            byte rawByte = buffer.get(i);
            tmp = (byte) (rawByte ^ i);
            buffer.put(i, tmp);
        }
        buffer.force();
        buffer.clear();
        channel.close();
        raf.close();
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}
        此方法加密耗时很短。

        加密时用到了MappedByteBuffer类。具体含义看此博客http://my.oschina.net/swearyd7/blog/167663?fromerr=dzP0A3fc  

        测试过程中,我将REVERSE_LENGTH 这个常量设置为1,只加密视频文件的前1个字节,没有任何效果。改成2个字节后,加密后的视频就无法播放了,大于等于2个字节都能加密成功。

你可能感兴趣的:(视频,视频加密,android,缓存,版权)