简单视频加密与授权
应同学邀请参加信息安全大赛,负责作品的"离线空间"模块,简单来说,离线空间就是要求加密视频只能在指定机器播放,并且只能播放规定次数。
思维导图如下
运行环境:JDK1.8, WIN8
一、加密视频EncVideo部分由以下几个模块组成:
1、Mac.Java
负责获取本地Mac
- //获取本机MAC地址
- //提供一个方法 String getMac()
- //返回本机Mac地址
- package org.tree.enc;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- public class Mac {
- public String getMac() throws IOException
- {
- String MacAddress = null;
- BufferedReader br = null;
- Process pro = null;
- try{
- pro = Runtime.getRuntime().exec("ipconfig /all");
- br = new BufferedReader(new InputStreamReader(pro.getInputStream()));
- int index = -1;
- String line = null;
- while((line = br.readLine()) != null){
- String t = "物理地址";
- String que = new String(t.getBytes("GBK"));
- if(((index = line.indexOf(que)) != -1) || ((index = line.toLowerCase().indexOf("physical address")) != -1)){
- index = line.indexOf(":");
- MacAddress = line.substring(index + 1).trim();
- break;
- }
- }
- }
- catch(Exception e){
- e.printStackTrace();
- }
- finally{
- br.close();
- }
- return MacAddress;
- }
- }
2、MD5.java
负责将Mac进行MD5加密
- //对MAC地址进行MD5加密,生成32位字符串
- //提供一个方法String getMD5()
- //返回经过MD5加密后的MAC
- package org.tree.enc;
- import java.security.MessageDigest;
- public class MD5 {
- public String getMD5(){
- String RawMessage = null;
- String MD5Message = null;
- try{
- RawMessage = new Mac().getMac();;
- MessageDigest md = MessageDigest.getInstance("MD5");
- md.update(RawMessage.getBytes());
- byte[] b = md.digest();
- StringBuffer temp = new StringBuffer("");
- for(int i = 0 ; i < b.length; i++){
- int tep = b[i];
- if(tep < 0){
- tep += 256;
- }
- if(tep < 16){
- temp.append("0");
- }
- temp.append(Integer.toHexString(tep));
- }
- MD5Message = temp.toString();
- }
- catch(Exception e){
- e.printStackTrace();
- }
- return MD5Message;
- }
- }
3、EncVideo.java
负责对视频进行加密
- //加密视频,在视频末尾添加MAC的MD5,生成Result.k文件
- //提供一个方法 void encVideo(String InPath, String OutPath)
- //InPath:需要加密的文件路径 OutPath:输出文件路径
- package org.tree.enc;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- public class EncVideo {
- public void encVideo(String InPath, String OutPath) throws IOException
- {
- FileInputStream in = null;
- FileOutputStream out = null;
- try{
- in = new FileInputStream(InPath);
- out = new FileOutputStream(new File(OutPath+"\\Result.k"));
- byte[] b = new byte[1024];
- int temp = 0;
- while((temp = in.read(b)) != -1){
- out.write(b);
- }
- out.write(new MD5().getMD5().getBytes());
- }
- catch(Exception e){
- e.printStackTrace();
- }
- finally{
- if(in != null){
- in.close();
- }
- if(out != null){
- out.close();
- }
- }
- }
- }
4、UI.java
负责GUI部分
- package org.tree.enc;
- import java.awt.BorderLayout;
- import java.io.File;
- import javax.swing.JButton;
- import javax.swing.JDialog;
- import javax.swing.JFileChooser;
- import javax.swing.JFrame;
- import javax.swing.JLabel;
- import javax.swing.JPanel;
- public class UI {
- private String InPath = null;
- private String OutPath = null;
- public UI(){
- JFrame f = new JFrame("加密视频");
- f.setSize(200, 150);
- f.setResizable(false);
- JPanel p1 = new JPanel();
- JPanel p2 = new JPanel();
- JPanel p3 = new JPanel();
- JFileChooser fc1 = new JFileChooser();
- JButton b1 = new JButton("选择加密文件");
- JFileChooser fc2 = new JFileChooser();
- JButton b2 = new JButton("选择保存位置");
- JButton b3 = new JButton("加密");
- p1.add(b1);
- p2.add(b2);
- p3.add(b3);
- f.add(p1, BorderLayout.NORTH);
- f.add(p2, BorderLayout.CENTER);
- f.add(p3, BorderLayout.SOUTH);
- f.setVisible(true);
- b1.addActionListener(event -> {
- fc1.setDialogTitle("请选择需要加密的文件");
- fc1.showOpenDialog(b1);
- });
- b2.addActionListener(event -> {
- fc2.setDialogTitle("请选择要保存的位置");
- fc2.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- fc2.showSaveDialog(b2);
- });
- fc1.addPropertyChangeListener(event -> {
- if(event.getPropertyName() == JFileChooser.SELECTED_FILE_CHANGED_PROPERTY){
- File file = (File)event.getNewValue();
- InPath = file.getPath();
- }
- });
- fc2.addPropertyChangeListener(event -> {
- if(event.getPropertyName() == JFileChooser.SELECTED_FILE_CHANGED_PROPERTY){
- File file = (File)event.getNewValue();
- OutPath = file.getPath();
- }
- });
- b3.addActionListener(event -> {
- try{
- if(InPath == null){
- JDialog d = new JDialog(f, "您没有选择需要加密的文件!", true);
- JLabel la = new JLabel("请选择需要加密的文件!", JLabel.CENTER);
- d.add(la, BorderLayout.CENTER);
- d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- d.setSize(300, 100);
- d.setVisible(true);
- }
- else if(OutPath == null){
- JDialog d = new JDialog(f, "您没有选择保存的位置!", true);
- JLabel la = new JLabel("请选择需要保存的位置!", JLabel.CENTER);
- d.add(la, BorderLayout.CENTER);
- d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- d.setSize(300, 100);
- d.setVisible(true);
- }
- else{
- new EncVideo().encVideo(InPath, OutPath);
- JDialog d = new JDialog(f, "加密完毕!", false);
- JLabel la = new JLabel("加密完毕!", JLabel.CENTER);
- d.add(la, BorderLayout.CENTER);
- d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- d.setSize(300, 100);
- d.setVisible(true);
- }
- }
- catch(Exception e){
- e.printStackTrace();
- }
- });
- f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- }
- public static void main(String[] args){
- new UI();
- }
- }
运行效果(以test.mp4为例):
1、程序主界面
2、程序运行结果
二、解密视频DecVideo由以下几个模块组成:
1、Mac.java
获取MAC 同上
2、MD5.java
对MAC进行MD5加密 同上
3、DecVideo.java
负责对提取视频中的MD5
- //提取视频中MAC
- //提供一个方法 String getMacMD5(String path)
- //返回视频中的MAC path:要打开的加密文件的路径
- package org.tree.pla;
- import java.io.RandomAccessFile;
- public class DecVideo {
- public String getMacMD5(String path){
- String VideoMD5 = null;
- try(RandomAccessFile raf = new RandomAccessFile(path, "r")){
- long len = raf.length();
- raf.seek(len-32);
- byte[] b = new byte[32];
- raf.read(b);
- VideoMD5 = new String(b);
- }
- catch(Exception e){
- e.printStackTrace();
- }
- return VideoMD5;
- }
- }
负责调用本地播放器播放视频
- //播放视频
- //提供两个方法 boolean CompareMD5(String path)
- //比较视频中的MAC与本地MAC
- //void Player(Sting path)
- //播放视频
- //提供一个类变量 int count 用来标识剩余授权次数
- package org.tree.pla;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.RandomAccessFile;
- public class PlayVideo {
- public static int count = 10;
- public boolean CompareMD5(String path){
- String VideoMD5 = new DecVideo().getMacMD5(path);
- String LocalMD5 = new MD5().getMD5();
- if(VideoMD5.equals(LocalMD5)){
- return true;
- }
- else{
- return false;
- }
- }
- public void Player(String path){
- if(new PlayVideo().CompareMD5(path)){
- try{
- FileInputStream in = new FileInputStream(path);
- FileOutputStream out = new FileOutputStream("C:\\tmp\\isctmp.avi");
- byte[] tmpb = new byte[1024];
- int index = 0;
- while((index = in.read(tmpb)) != -1){
- out.write(tmpb);
- }
- in.close();
- out.close();
- File f = new File("C:\\Users\\Public\\Documents\\IscInfo.ini");
- if(f.exists()){
- RandomAccessFile raf = new RandomAccessFile(f, "rw");
- byte[] b = new byte[4];
- raf.read(b);
- String result = new String(b);
- int num = Integer.parseInt(result.trim());
- if(num != 0 && num <= 10){
- raf.setLength(0);
- num--;
- PlayVideo.count = num;
- String numtmp = num + "";
- raf.write(numtmp.getBytes());
- Process pro = Runtime.getRuntime().exec("C:\\Program Files\\Windows Media Player\\wmplayer.exe " + "C:\\tmp\\isctmp.avi");
- }
- else{
- File inf = new File(path);
- inf.delete();
- }
- raf.close();
- }
- else{
- PlayVideo.count = 10;
- FileOutputStream out1 = new FileOutputStream(f.getPath());
- out1.write("10".getBytes());
- Process pro = Runtime.getRuntime().exec("C:\\Program Files\\Windows Media Player\\wmplayer.exe " + "C:\\tmp\\isctmp.avi");
- out1.close();
- }
- }
- catch(Exception e){
- e.printStackTrace();
- }
- }
- else{
- System.out.println("你不能播放这个视频");
- }
- }
- }
负责GUI,验证授权信息
- package org.tree.pla;
- import java.awt.BorderLayout;
- import java.awt.event.WindowAdapter;
- import java.awt.event.WindowEvent;
- import java.io.File;
- import javax.swing.JButton;
- import javax.swing.JDialog;
- import javax.swing.JFileChooser;
- import javax.swing.JFrame;
- import javax.swing.JLabel;
- public class UI {
- private String path = null;
- public UI(){
- JFrame f = new JFrame("播放加密视频");
- f.setSize(250, 100);
- f.setResizable(false);
- JButton b1 = new JButton("选择加密文件");
- JButton b2 = new JButton("播放");
- JFileChooser fc = new JFileChooser();
- f.add(b1, BorderLayout.CENTER);
- f.add(b2, BorderLayout.SOUTH);
- f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
- f.setVisible(true);
- b1.addActionListener(event -> {
- fc.setDialogTitle("请选择需要打开的文件");
- fc.showOpenDialog(b1);
- });
- b2.addActionListener(event -> {
- if(path == null){
- JDialog d = new JDialog(f, "您没有选择打开的文件!", true);
- JLabel la = new JLabel("请选择需要打开的文件!", JLabel.CENTER);
- d.add(la, BorderLayout.CENTER);
- d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- d.setSize(300, 100);
- d.setVisible(true);
- }
- if(new PlayVideo().CompareMD5(path)){
- if(PlayVideo.count <= 0){
- JDialog d = new JDialog(f, "权限不足", true);
- JLabel la = new JLabel("您的剩余授权次数不足!", JLabel.CENTER);
- d.add(la, BorderLayout.CENTER);
- d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- d.setSize(300, 100);
- d.setVisible(true);
- File file = new File(path);
- file.delete();
- }
- else{
- new PlayVideo().Player(path);
- JDialog d = new JDialog(f, "剩余使用次数");
- JLabel la = new JLabel("剩余使用次数为: " + PlayVideo.count, JLabel.CENTER);
- d.add(la, BorderLayout.CENTER);
- d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- d.setSize(300, 100);
- d.setVisible(true);
- }
- }
- else{
- JDialog d = new JDialog(f, "权限不足", true);
- JLabel la = new JLabel("您没有别授权打开此文件!", JLabel.CENTER);
- d.add(la, BorderLayout.CENTER);
- d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- d.setSize(300, 100);
- d.setVisible(true);
- File file = new File(path);
- file.delete();
- }
- });
- fc.addPropertyChangeListener(event -> {
- if(event.getPropertyName() == JFileChooser.SELECTED_FILE_CHANGED_PROPERTY){
- File file = (File)event.getNewValue();
- path = file.getPath();
- }
- });
- f.addWindowListener(new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- try{
- File file = new File("C:\\tmp\\isctmp.avi");
- file.delete();
- }
- catch(Exception ex){
- ex.printStackTrace();
- }
- System.exit(0);
- }
- });
- }
- public static void main(String[] args){
- new UI();
- }
- }
程序运行结果:
1、程序主界面
2、程序运行界面
小结
简单的视频加密,不过现在的加密非常的脆弱,比如将.k改名为.avi等视频格式就可以正常播放,修改授权信息内容就可以无限次播放,将隐式转换成视频格式的文件复制一份也可以正常播放。要对抗这种方式的攻击就需要用到其他加密方法,这就不在本文讨论范围了QAQ(其实我会说我也不懂吗。。。我只负责这个模块,听说还有左右手识别,吧唧吧唧的什么的加密方法Orz)
PS.忽略我写的渣的JAVA代码。。新手...IO方面各种流乱用 还有GUI那写的更不能看了QAQ
==================================================================
IscInfo.ini文件非常容易被修改,所以想出了一个解决办法
在将.k文件转化为.avi格式时,文件流是打开的,此时我们可以修改.k文件尾部的授权次数信息,每次打开视频前检测剩余几次授权,这样就不需要IscInfo.ini这个文件了
加密部分
1、MAC.Java不变,获取本地MAC地址
2、MD5.java 略微修改,使之可以加密所有传入的字符串,比如授权次数
- //对MAC地址进行MD5加密,生成32位字符串
- //提供一个方法String getMD5()
- //返回经过MD5加密后的MAC
- package org.tree.enc;
- import java.security.MessageDigest;
- public class MD5 {
- //能够加密所有传入的字符串
- public String getMD5(String mac){
- String RawMessage = null;
- String MD5Message = null;
- try{
- RawMessage = mac;
- MessageDigest md = MessageDigest.getInstance("MD5");
- md.update(RawMessage.getBytes());
- byte[] b = md.digest();
- StringBuffer temp = new StringBuffer("");
- for(int i = 0 ; i < b.length; i++){
- int tep = b[i];
- if(tep < 0){
- tep += 256;
- }
- if(tep < 16){
- temp.append("0");
- }
- temp.append(Integer.toHexString(tep));
- }
- MD5Message = temp.toString();
- }
- catch(Exception e){
- e.printStackTrace();
- }
- return MD5Message;
- }
- }
将MAC添加进视频尾部后,再加入授权次数,使后64位都是加密信息
- //加密视频,在视频末尾添加MAC的MD5,生成Result.k文件
- //提供一个方法 void encVideo(String InPath, String OutPath)
- //InPath:需要加密的文件路径 OutPath:输出文件路径
- package org.tree.enc;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- public class EncVideo {
- public void encVideo(String InPath, String OutPath) throws IOException
- {
- FileInputStream in = null;
- FileOutputStream out = null;
- try{
- in = new FileInputStream(InPath);
- out = new FileOutputStream(new File(OutPath+"\\Result.k"));
- byte[] b = new byte[1024];
- int temp = 0;
- while((temp = in.read(b)) != -1){
- out.write(b);
- }
- out.write(new MD5().getMD5(new Mac().getMac()).getBytes());
- //在尾部添加进授权信息
- out.write(new MD5().getMD5("10").getBytes());
- }
- catch(Exception e){
- e.printStackTrace();
- }
- finally{
- if(in != null){
- in.close();
- }
- if(out != null){
- out.close();
- }
- }
- }
- }
4、UI.java GUI部分不变
解密部分:
1、MAC.java
同加密部分
2、MD5.java
同加密部分 使之加密所有字符串
3、DecVideo.java
不仅提取出视频尾部MAC,也提取出授权次数
- //提取视频中MAC
- //提供一个方法 String getMacMD5(String path)
- //返回视频中的MAC path:要打开的加密文件的路径
- //返回视频尾部的授权次数
- package org.tree.pla;
- import java.io.RandomAccessFile;
- public class DecVideo {
- //提取视频内Mac信息
- public String getMacMD5(String path){
- String VideoMD5 = null;
- try(RandomAccessFile raf = new RandomAccessFile(path, "r")){
- long len = raf.length();
- raf.seek(len-64);
- byte[] b = new byte[32];
- raf.read(b);
- VideoMD5 = new String(b);
- }
- catch(Exception e){
- e.printStackTrace();
- }
- return VideoMD5;
- }
- //提取视频内授权次数信息
- public String getVideoCount(String path){
- String VideoCount = null;
- try(RandomAccessFile raf = new RandomAccessFile(path, "r")){
- long len = raf.length();
- raf.seek(len-32);
- byte[] b = new byte[32];
- raf.read(b);
- VideoCount = new String (b);
- }
- catch(Exception e){
- e.printStackTrace();
- }
- return VideoCount;
- }
- }
不仅比较MAC, 还要比较剩余授权次数,且如果满足播放条件 ,剩余授权次数-1重新写入视频尾部
- //播放视频
- //提供两个方法 boolean CompareMD5(String path)
- //比较视频中的MAC与本地MAC
- //void Player(Sting path)
- //播放视频
- //提供一个类变量 int count 用来标识剩余授权次数
- package org.tree.pla;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.RandomAccessFile;
- import java.util.ArrayList;
- public class PlayVideo {
- //存储MD5加密后的0-10数字用于比较剩余授权次数
- public static ArrayList<String> ComList = new ArrayList<>();
- public static void init(){
- for(int i = 0 ; i <= 10 ; i ++){
- ComList.add(new MD5().getMD5(i+""));
- }
- }
- //比较视频中MAC与本地MAC
- public boolean CompareMacMD5(String path){
- String VideoMD5 = new DecVideo().getMacMD5(path);
- String localMD5 = null;
- try{
- localMD5 = new MD5().getMD5(new Mac().getMac());
- }
- catch(Exception e){
- e.printStackTrace();
- }
- if(VideoMD5.equals(localMD5)){
- return true;
- }
- else{
- return false;
- }
- }
- //获取剩余授权次数
- public int CompareCountMD5(String path){
- String VideoCount = new DecVideo().getVideoCount(path);
- return ComList.indexOf(VideoCount);
- }
- public void Player(String path){
- if(new PlayVideo().CompareMacMD5(path)){
- try{
- FileInputStream in = new FileInputStream(path);
- FileOutputStream out = new FileOutputStream("C:\\tmp\\isctmp.avi");
- byte[] tmpb = new byte[1024];
- int index = 0;
- while((index = in.read(tmpb)) != -1){
- out.write(tmpb);
- }
- in.close();
- out.close();
- int count = new PlayVideo().CompareCountMD5(path);
- //如果剩余授权次数>0 播放且次数-1重新写入视频尾部
- if(count > 0){
- RandomAccessFile raf = new RandomAccessFile(path, "rw");
- long len = raf.length();
- raf.seek(len-32);
- String result = count - 1 + "";
- result = new MD5().getMD5(result);
- raf.write(result.getBytes());
- Process pro = Runtime.getRuntime().exec("C:\\Program Files\\Windows Media Player\\wmplayer.exe " + "C:\\tmp\\isctmp.avi");
- raf.close();
- }
- }
- catch(Exception e){
- e.printStackTrace();
- }
- }
- }
- }
5、UI.java
基本不变 负责GUI
小结
通过上面的方法,一定程度上提高了安全性
原文链接:http://blog.csdn.net/acm_yuuji/article/details/43822229
相关推荐
- 简单视频加密与授权
- AES加密算法的简单介绍与实现
- 大众点评文字与数字加密轻松解密 不需要查看位移偏量等操作 简单明白
- TSINGSEE青犀视频云边端架构视频平台,加密机授权如何配置成固定ip?
- 使用Shiro加密与解密实现简单用户注册与登录验证
- android应用中怎么对视频进行加密与解密
- Linux下实现 OpenSSL 简单加密与解密字符串
- android应用中怎么对视频进行加密与解密
- 任何简单的PHP库授权与谷歌,FB,Twitter
- Linux下实现 OpenSSL 简单加密与解密字符串
- PanDownload回归!70MB/s!
- windows下图床神器(结合markdown和七牛)