福昕阅读器drm加密解密总结
drm是数字版权保护的一种方式,前一段时间在做四川文轩数字图书馆项目的时候用到了相关的知识,感觉这东西对于一些在线阅读和视频播放还是有很大用处的。
对于其工作原理我也很好奇,先摘抄度娘的内容如下,当然你也可以直接访问度娘:http://baike.baidu.com/view/47310.htm?fr=aladdin
系统原理
/**
* 文件名 BaseFoac.java
* 包含类名列表 com.issmobile.numlibrary.tool
* 版本信息 版本号
* 创建日期 2014年7月15日
* 版权声明
*/ package com.issmobile.numlibrary.tool; import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.CookieStore;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames; import android.util.Log; import com.foxit.general.BufferFileRead;
import com.foxit.general.DrmNative;
import com.foxit.general.PdfBaseDef;
import com.foxit.general.PdfDocNative;
import com.foxit.general.PdfDrmNative;
import com.foxit.general.ObjectRef;
import com.foxit.general.PdfSecurityNative;
import com.foxit.general.RsaKey;
import com.foxit.general.RtBaseDef;
import com.foxit.general.RtNative; /**
* 类名
* @author 王洪贺<br/>
* 实现的主要功能。
* 创建日期 2014年7月15日
*/ public class BaseFoac { protected ObjectRef m_encryptParams = null;
private CookieStore m_cookieStore = null;
private byte[] m_decoderPubKey = null; /**用户名*/
private String mUserName;
/**密码*/
private String mPassword;
/**密码*/
private String mDevSN; private String m_host = null;
private String m_port = null;
private String m_object = null;
private ObjectRef security = null;
private RsaKey m_rsaKey = null;
/**文件本地地址*/
private String drmfile = null;
private DefaultHttpClient httpClient = null;//new DefaultHttpClient();
private String m_sessionID = null; /**
* 获取信封的时候初始化,需要用户名密码
* */
public BaseFoac(String mUserName, String mPassword, String drmfile) {
this.mUserName = "ElibUser." + mUserName;
this.mPassword = mPassword;
this.mDevSN = mPassword;
this.drmfile = drmfile;
} /**
* 解密文件的时候初始化
* */
public BaseFoac() {
} public void setDRMFileName(String filename) {
drmfile = filename;
} public boolean isDocWrapper(ObjectRef document) {
if (!PdfDrmNative.isDocWrapper(document))
return false;
return true;
} public boolean isFoxitDRM(ObjectRef document) {
if (!PdfDrmNative.isDocWrapper(document))
return false; m_encryptParams = PdfDrmNative.getEncryptParams(document); if (m_encryptParams == null)
return false; return true;
} protected String getServiceURL() {
//TODO 获取到书籍中验证drm的网址,由于目前服务器不可用,返回默认地址,正式版修改回来
// return PdfDrmNative.getEncryptParamsItemString(m_encryptParams,
// PdfBaseDef.ENCRYPTPARAMS_SERVICEURL);
return URLConstants.licenseURL;
} /**
* 解析网址
*/
protected void parseURL(String serviceUrl) {
if (serviceUrl == null)
return;
int hostIndex = serviceUrl.indexOf("://");
String tmp = serviceUrl.substring(hostIndex + 3);
int objIndex = tmp.indexOf("/");
int portIndex = tmp.indexOf(":");
if (portIndex < 0) {
m_port = "80";
m_host = tmp.substring(0, objIndex);
} else {
m_port = tmp.substring(portIndex + 1, objIndex);
m_host = tmp.substring(0, portIndex);
}
m_object = tmp.substring(objIndex + 1);
} /**
* 获取开始的请求信息
*/
protected String getSessionBeginRequest(String sessionID) {
ObjectRef foac = DrmNative.createFoac(true);
if (foac == null)
return null; DrmNative.setFoacSessionID(foac, sessionID); ObjectRef category = DrmNative.getFoacDataCategory(foac);
if (category == null) {
DrmNative.deleteFoac(foac);
return null;
} DrmNative.setFoacRequestID(foac, "SessionBegin"); ObjectRef subCategory = DrmNative.addSubCategory(category, "FlowCode", true);
String flowCode = PdfDrmNative.getEncryptParamsItemString(m_encryptParams,
PdfBaseDef.ENCRYPTPARAMS_FLOWCODE);
DrmNative.setCategoryAttribute(subCategory, "Value", flowCode); String request = DrmNative.saveFoac(foac);
DrmNative.deleteFoac(foac);
return "XmlContent=" + request;
} /**
* 发送请求信息并返回接受到的数据,需访问网络
*/
protected String sendAndReceive(String bsSend) {
String result = null;
try {
httpClient = new DefaultHttpClient();
String temp = bsSend.replace("&", "%26");
temp = temp.replace("+", "%2B");
InetAddress addr = InetAddress.getByName(m_host); String url;
if (addr.toString().substring(1).indexOf("/") != -1)
url = "http://" + m_host + ":" + m_port + "/" + m_object;
else
url = "http://" + m_host + ":" + m_port + "/" + m_object;
HttpPost httpPost = new HttpPost(url);
HttpEntity entity = new StringEntity(temp);
httpPost.setEntity(entity); httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); // if (m_cookieStore != null)
httpClient.setCookieStore(m_cookieStore); httpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 300000);
httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 300000); HttpResponse httpResponse = httpClient.execute(httpPost);
int status = httpResponse.getStatusLine().getStatusCode();
long len = httpResponse.getEntity().getContentLength(); StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse
.getEntity().getContent()));
for (String s = reader.readLine(); s != null; s = reader.readLine()) {
builder.append(s);
}
result = builder.toString();
m_cookieStore = ((AbstractHttpClient) httpClient).getCookieStore(); if (result.indexOf("xml") == -1)
return null; } catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 解析收到的信息
*/
protected void parseSessionBeginRecieve(String receive) {
ObjectRef foac = DrmNative.loadFoac(receive.getBytes());
if (foac == null)
return; String state = DrmNative.getFoacAnswerState(foac);
if (state.indexOf("1") > -1) {
ObjectRef category = DrmNative.getFoacDataCategory(foac); //Pubkey
int iCount = DrmNative.countSubCategories(category, "ServerPubKey");
if (iCount == 0) {
DrmNative.deleteFoac(foac);
return;
}
ObjectRef subCategory = DrmNative.getSubCategory(category, "ServerPubKey", 0);
String bsPubKey = DrmNative.getCategoryAttributeValue(subCategory, "Value"); ObjectRef sessionID = DrmNative.getSubCategory(category, "SessionID", 0);
m_sessionID = DrmNative.getCategoryAttributeValue(sessionID, "Value"); // m_decoderPubKey = Base64.decode(bsPubKey, Base64.DEFAULT);
m_decoderPubKey = RtNative.base64Decode(bsPubKey.getBytes(), 0, bsPubKey.length());
}
DrmNative.deleteFoac(foac);
} /**
* 加密字符串
*/
protected String EncryptString(String str) {
byte[] data = DrmNative.pkiRsaEncrypt(str, m_decoderPubKey);
//return Base64.encodeToString(data, Base64.DEFAULT);
return RtNative.base64EncodeToString(data, 0, data.length);
} /**
* 获取检查账户的请求信息
*/
protected String GetCheckAccountRequest(String sessionID) {
String fileID = PdfDrmNative.getEncryptParamsItemString(m_encryptParams,
PdfBaseDef.ENCRYPTPARAMS_FILEID);
String strFileID = EncryptString(fileID); String order = PdfDrmNative.getEncryptParamsItemString(m_encryptParams,
PdfBaseDef.ENCRYPTPARAMS_ORDER);
String strOrder = EncryptString(order); String account = EncryptString(mUserName);
String password = EncryptString(mPassword); ObjectRef foac = DrmNative.createFoac(true);
DrmNative.setFoacSessionID(foac, sessionID); DrmNative.setFoacRequestID(foac, "AuthAccount"); ObjectRef category = DrmNative.getFoacDataCategory(foac);
if (category == null) {
DrmNative.deleteFoac(foac);
return null;
} ObjectRef subCategory = DrmNative.addSubCategory(category, "EncryptAccount", true);
DrmNative.setCategoryAttribute(subCategory, "Value", account); subCategory = DrmNative.addSubCategory(category, "EncryptPassword", true);
DrmNative.setCategoryAttribute(subCategory, "Value", password); subCategory = DrmNative.addSubCategory(category, "EncryptOrderID", true);
DrmNative.setCategoryAttribute(subCategory, "Value", strOrder); subCategory = DrmNative.addSubCategory(category, "EncryptFileID", true);
DrmNative.setCategoryAttribute(subCategory, "Value", strFileID); String request = DrmNative.saveFoac(foac); DrmNative.deleteFoac(foac); return "XmlContent=" + request;
} /**
* 解析收到账户认证的信息
*/
protected boolean ParseCheckAccountRequest(String receive) {
ObjectRef foac = DrmNative.loadFoac(receive.getBytes());
if (foac == null)
return false; boolean bRet = false; ///foac verify
String bsState = DrmNative.getFoacAnswerState(foac);
if (bsState.equals("1")) {
ObjectRef category = DrmNative.getFoacDataCategory(foac); int iCount = DrmNative.countSubCategories(category, "Result");
if (iCount == 0) {
DrmNative.deleteFoac(foac);
return false;
}
ObjectRef subCategory = DrmNative.getSubCategory(category, "Result", 0);
String result = DrmNative.getCategoryAttributeValue(subCategory, "Value");
bRet = result.equals("1");
}
DrmNative.deleteFoac(foac);
return bRet;
} /**
* 获取信封请求信息
*/
public String GetEnvelopRequest(String sessionID) {
String fileID = PdfDrmNative.getEncryptParamsItemString(m_encryptParams,
PdfBaseDef.ENCRYPTPARAMS_FILEID);
String strFileID = EncryptString(fileID); String order = PdfDrmNative.getEncryptParamsItemString(m_encryptParams,
PdfBaseDef.ENCRYPTPARAMS_ORDER);
String strOrder = order;//EncryptString(order); String userName = mUserName;//EncryptString(m_userName);
String password = EncryptString(mPassword);
String devSn = EncryptString(mDevSN); byte[] seed = {
'F', 'o', 'x', 'i', 't', 'A', 'n', 'd', 'r', 'o', 'i', 'd'
}; m_rsaKey = DrmNative.createRsaKey(1024, seed, null); if (m_rsaKey == null)
return null; String strClientPubKey = RtNative.base64EncodeToString(m_rsaKey.publicKey, 0,
m_rsaKey.publicKey.length);
// String strClientPubKey = Base64.encodeToString(clientPubKey, Base64.DEFAULT); ObjectRef foac = DrmNative.createFoac(true);
DrmNative.setFoacSessionID(foac, sessionID); DrmNative.setFoacRequestID(foac, "GetEnvelop"); ObjectRef category = DrmNative.getFoacDataCategory(foac);
if (category == null) {
DrmNative.deleteFoac(foac);
return null;
} ObjectRef subCategory = DrmNative.addSubCategory(category, "OrderID", true);
DrmNative.setCategoryAttribute(subCategory, "Value", strOrder); subCategory = DrmNative.addSubCategory(category, "EncryptFileID", true);
DrmNative.setCategoryAttribute(subCategory, "Value", strFileID); subCategory = DrmNative.addSubCategory(category, "ClientPubKey", true);
DrmNative.setCategoryAttribute(subCategory, "Value", strClientPubKey); subCategory = DrmNative.addSubCategory(category, "Usermail", true);
DrmNative.setCategoryAttribute(subCategory, "Value", userName); subCategory = DrmNative.addSubCategory(category, "EncryptPassword", true);
DrmNative.setCategoryAttribute(subCategory, "Value", password); subCategory = DrmNative.addSubCategory(category, "EncryptDeviceSN", true);
DrmNative.setCategoryAttribute(subCategory, "Value", devSn); String request = DrmNative.saveFoac(foac); DrmNative.deleteFoac(foac); return "XmlContent=" + request;
} /**
* 解析收到的信封信息
*/
public boolean parseEnvelopRequest(ObjectRef document, String receive) { BufferFileRead bufReader = new BufferFileRead(receive.getBytes(), 0);
ObjectRef envelope = DrmNative.loadEnvelope(bufReader);
byte[] key = DrmNative.getEnvelopeKey(envelope); String algorithm = DrmNative.getEnvelopeAlgorithm(envelope);
byte[] deKey = DrmNative.pkiRsaDecrypt(key, m_rsaKey.privateKey); security = new ObjectRef();
String filter = "FoxitSTD";
int ret = PdfSecurityNative.createFoxitDRMSecurity(filter,
algorithm.equals("FOXIT_ENCRYPT2") ? RtBaseDef.CIPHER_AES : RtBaseDef.CIPHER_RC4,
deKey, security);
if (ret != RtBaseDef.ERR_SUCCESS)
return false; int offset = PdfDrmNative.getDocWrapperOffset(document);
boolean flag = PdfSecurityNative.verifyFoxitDRMSecurity(security); ret = PdfDocNative.closeDoc(document);
if (ret != RtBaseDef.ERR_SUCCESS)
return false; ret = PdfDocNative.loadDoc(drmfile, 0, offset, document);
if (ret != RtBaseDef.ERR_SUCCESS)
return false; return true;
} /**
* 解密文件
*/
public boolean decrypt(ObjectRef document) {
if (document == null)
return false; String serviceUrl = getServiceURL();
if (serviceUrl == null)
return false;
parseURL(serviceUrl);
System.out.println("URL ==" + serviceUrl); String sessionID = "6F9629FF-8A86-D011-B42D-00C04FC964FF";
String send = getSessionBeginRequest(sessionID);
if (send == null)
return false;
String receive = sendAndReceive(send);
if (receive == null)
return false;
parseSessionBeginRecieve(receive); String checkAccount = GetCheckAccountRequest(sessionID);
if (checkAccount == null)
return false;
receive = sendAndReceive(checkAccount);
if (receive == null)
return false;
if (!ParseCheckAccountRequest(receive))
return false; String envelope = GetEnvelopRequest(sessionID);
if (envelope == null)
return false;
receive = sendAndReceive(envelope);
if (receive == null)
return false; return parseEnvelopRequest(document, receive);
} /**
* 获取信封
* @author honghe
*/
public String getEnvelop(ObjectRef document) {
if (document == null)
return null; String serviceUrl = getServiceURL();
if (serviceUrl == null)
return null;
parseURL(serviceUrl);
System.out.println("URL ==" + serviceUrl); String sessionID = "6F9629FF-8A86-D011-B42D-00C04FC964FF";
String send = getSessionBeginRequest(sessionID);
if (send == null)
return null;
String receive = sendAndReceive(send);
if (receive == null)
return null;
parseSessionBeginRecieve(receive); String checkAccount = GetCheckAccountRequest(sessionID);
if (checkAccount == null)
return null;
receive = sendAndReceive(checkAccount);
if (receive == null)
return null;
if (!ParseCheckAccountRequest(receive))
return null; String envelope = GetEnvelopRequest(sessionID);
if (envelope == null)
return null;
receive = sendAndReceive(envelope);
if (receive == null)
return null; return receive;
} /**
* 根据信封信息解密文档
* @author honghe
*/
public boolean decryptDoc(ObjectRef document, String receive) {
BufferFileRead bufReader = new BufferFileRead(receive.getBytes(), 0);
ObjectRef envelope = DrmNative.loadEnvelope(bufReader);
byte[] key = DrmNative.getEnvelopeKey(envelope);
String algorithm = DrmNative.getEnvelopeAlgorithm(envelope);
byte[] seed = {
'F', 'o', 'x', 'i', 't', 'A', 'n', 'd', 'r', 'o', 'i', 'd'
};
m_rsaKey = DrmNative.createRsaKey(1024, seed, null);
byte[] deKey = DrmNative.pkiRsaDecrypt(key, m_rsaKey.privateKey); security = new ObjectRef();
String filter = "FoxitSTD";
int ret = PdfSecurityNative.createFoxitDRMSecurity(filter,
algorithm.equals("FOXIT_ENCRYPT2") ? RtBaseDef.CIPHER_AES : RtBaseDef.CIPHER_RC4,
deKey, security);
if (ret != RtBaseDef.ERR_SUCCESS)
return false; int offset = PdfDrmNative.getDocWrapperOffset(document);
boolean flag = PdfSecurityNative.verifyFoxitDRMSecurity(security); ret = PdfDocNative.closeDoc(document);
if (ret != RtBaseDef.ERR_SUCCESS)
return false; ret = PdfDocNative.loadDoc(drmfile, 0, offset, document);
if (ret != RtBaseDef.ERR_SUCCESS)
return false; return true;
} public void destroy() {
int ret = RtBaseDef.ERR_ERROR;
if (m_encryptParams != null)
ret = PdfDrmNative.releaseEncryptParams(m_encryptParams);
if (security != null)
ret = PdfSecurityNative.destroySecurity(security); } }
简单的说一下调用的过程:
1.首先用客户端下载一本经过drm加密的书籍(加密的过程是文轩那边已经加密好的了)
2.下载完后根据书籍中的drm地址和加密信息以及用户的用户名和密码获取信封(按照福昕提供的api是在阅读的时候在线联网解密的,但客户要求可以离线阅读,因此下载书的时候要先取得解密用的信封)
获取信封的调用方法
if(finished) {
FoxitRAMManager.getInstance();
ObjectRef document = new ObjectRef();
int result = PdfDocNative.loadDoc(book.loc, null, document);
if (result != RtBaseDef.ERR_SUCCESS) {
throw new Exception("load drm fail!");
}
User user = AppContext.getInstance().getUserModel().user;
BaseFoac baseFoac = new BaseFoac(user.uName, user.pwd, book.loc);
if (baseFoac.isFoxitDRM(document)) {
baseFoac.setDRMFileName(book.loc);
String envelop = baseFoac.getEnvelop(document);
if (envelop != null) {
book.receive = envelop;
}
else {
throw new Exception("get envelop fail!");
}
}
// baseFoac.destroy();
PdfDocNative.closeDoc(document);
}
3.将获取的信封根据书籍对应的信息保存到数据库中,一本书一个用来解密的信封。
4.用户打开书籍的时候获取该书籍存储于数据库中的信封,用信封对书籍进行解密,用户就可以看到该书籍了。
FoxitRAMManager.getInstance();
document = new ObjectRef();
int result = PdfDocNative.loadDoc(filePath, null, document);
if (result != RtBaseDef.ERR_SUCCESS)
return false;
// 根据得到的信封解密书籍
mBaseFoac = new BaseFoac();
if (mBaseFoac.isDocWrapper(document)) {
mBaseFoac.setDRMFileName(filePath);
if (!mBaseFoac.decryptDoc(document, receive)) {
return false;
}
} else {
return false;
}
这样做的好处是该用户下载的书籍用其他的阅读器是无法打开的,而且解密的信封也是跟用户和服务器相关的,其他人或者是不联网验证也是无法查看传送的书籍的,有效的保护了数字版权。
代码已上传github。
地址为:https://github.com/dongweiq/study/tree/master/pdf_drm
代码中appid和password已删除,此外你只有加入jar包和so文件才可以运行。
我的github地址:https://github.com/dongweiq/study
欢迎关注,欢迎star o(∩_∩)o 。有什么问题请邮箱联系 dongweiqmail@gmail.com qq714094450
福昕阅读器drm加密解密总结的更多相关文章
- 新版福昕阅读器(Foxit Reader)启动速度慢解决办法
新版福昕阅读器(FoxitReader)启动速度慢解决办法之前喜欢使用福昕阅读器的原因就是看中了其小巧,可是最近版本的阅读器打开速度变得慢了很多(不是电脑配置问题),比AdobeReader还要慢,这 ...
- 近日测试发现所有Excel相关功能均会抛异常,查后发现与福昕阅读器不兼容
报这种错: System.Runtime.InteropServices.COMException (0x80010105): 服务器出现意外情况. (异常来自 HRESULT:0x80010105 ...
- ubuntu 安装FoxitReader福昕阅读器(转载)
虽然不怎么用Ubuntu来看文档,但是偶尔还是需要看一下的.而Ubuntu自带的打开PDF的软件真的看着很难受,装一个跨平台的福昕好了. 首先,下载.可以官网下载:福昕官网 不过晚上不知道网络抽风还是 ...
- ubuntu卸载福昕阅读器
在安装目录找到maintenancetool.sh运行之 ~/opt/foxitsoftware/foxitreader
- 福昕阅读器打开PDF文档速度慢
RT---------------- 操作如下两步可加快打开速度: 1.Program Files\Foxit Software\Foxit Reader下面的Shell Extensions文件夹删 ...
- 福昕阅读器把pdf某一页保存出来
第一步: 第二步: 第三步: 第四步:点击保存即可
- 关于linux上pdf阅读器
今天也是倒腾linux 上pdf阅读器好久. 1.okular是挺好的,但是却太大了,好多功能,我没有细看.我简单的打开了几个pdf文件,发现加载速度还是太慢了.所以基于种种,我给卸载掉了. 安装直接 ...
- Ubuntu 18.10 安装PDF阅读器
======================================== 软件开发转移到了 Linux上,使用Ubuntu 18.10作为桌面开发环境 下面介绍 安装PDF阅读器 1.下载 福 ...
- 采用WPF技术,开发OFD电子文档阅读器
前言 OFD是国家标准版式文档格式,于2016年生效.OFD文档国家标准参见<电子文件存储与交换格式版式文档>.既然是国家标准,OFD随后肯定会首先在政务系统使用,并逐步推向社会各个方面. ...
随机推荐
- Assembly 'Microsoft.Office.Interop.Excel
编译的时候报错,都无法通过编译: Assembly 'Microsoft.Office.Interop.Excel, Version=14.0.0.0, Culture=neutral, Public ...
- PHP Cookies
PHP Cookies cookie 常用于识别用户. Cookie 是什么? cookie 常用于识别用户.cookie 是一种服务器留在用户计算机上的小文件.每当同一台计算机通过浏览器请求页面时, ...
- QT学习篇:入门(1)
第一个为管理界面: (1)安全库存的设置,包括序号.物品代码.物品类型.最大库存量.最小库存量.最大库存比率.最小库存比率: (2)计算频率设置,包括:实时,定时(单位分为:分钟.小时.天),来自gl ...
- 学习OpenSeadragon之一(一个显示多层图片的开源JS库)
OpenSeadragon是一个可以显示多层图片(可放大缩小)的Web库,基于JavaScript,支持桌面和手机. 由于我项目需要,却没有找到任何中文教程,因此在官网上一边学习,一边总结于此. 官网 ...
- 《Linux内核分析》 week6作业-Linux内核fork()系统调用的创建过程
一.进程控制块PCB-stack_struct 进程在操作系统中都有一个结构,用于表示这个进程.这就是进程控制块(PCB),在Linux中具体实现是task_struct数据结构,它主要记录了以下信息 ...
- 复制、移动和删除:cp, rm, mv
要复制文件,请使用cp(copy)命令.不过,cp命令的用途很多.除了单纯的复制之外,还可以建立连接文件(就是快捷方式),比较两个文件的新旧而予以更新,以及复制整个目录等等.至于移动目录与文件,则使用 ...
- phpcms V9 联动菜单的调用
/*********************************** 通过id获取显示联动菜单的 顶级父类的名称* @param $linkageid 联动菜单id* @param $keyi ...
- C#中的委托和事件2-1(转)
PDF 浏览:http://www.tracefact.net/Document/Delegates-and-Events-in-CSharp.pdf引言 委托 和 事件在 .Net Framew ...
- Python文件处理之文件读取方式(二)
Python的open文件的读取方式有以下几种方法: read([size]):读取文件,如果传了size参数,则读取size字节,否则读取全部 readline([size]):读取一行 readl ...
- Number对象
<script type="text/javascript"> /* Number对象. 创建Number对象的方式: 方式1: var 变量= new Number( ...