2020-04-05-【加密】京东阅读epub解密

 · 2020-4-29 · 次阅读


灵感来源于:

京东阅读android版下载jeb(epub格式)电子书后,book.db文件里有各本书解密用到的cert和random,将jeb解压后得到的文件用libjdrdrm.so里的decrypt函数解密就可得到原始内容。除了图片文件,其他所有文件都是加密的,需要用decrypt解密

首先,下载京东阅读APP,抽取其中的 *.so 库文件。

libBDSpeechDecoder_V1.so
libbd_etts.so
libBugly.so
libcrypto.so
libdecryptionoperation.so
libDecryptorJni.so
libgnustl_shared.so
libjcore121.so
libjcore214.so
libjdcomics.so
libjdCorereadingengine.so
libjdJmaEncryptUtil.so
libjdopus.so
libjdrdrm.so
libjdrebr.so
liblbs.so
libMtaNativeCrash_v2.so
librtmp-jni.so
libsecure.so
libSecurity.so
libsqlcipher.so
libssl.so
libzbar.so
libZBarDecoder.so

这里主要使用的是 libsecure.so libjdrdrm.so 其中,后者负责主要加密过程。

这里我们需要获得加密解密所用到的证书,也就是存放于 book.db 中的文件。

而这个文件是经过加密的,

classes2.dex
com.jd.app.reader.downloader.core.data.database.dao.chapterdivisionsbook.DaoMaster

public OpenHelper(Context context, String str) {
    super(context, str, 6);
}

public OpenHelper(Context context, String str, CursorFactory cursorFactory) {
    super(context, str, cursorFactory, 6);
}

涉及到的加密算法

  • AES, Rijndael算法 https://blog.csdn.net/thinkerleo1997/article/details/80253635
    AES
    这个是在 libjdrdrm.so 的符号表中发现的信息,也就是这个算法中采用了AES的算法,但细节可能有变化,需要使用其他的方法来探索。
  • 数据库,使用的是 sqlcipher 的简单加密算法,解密出来就是正确的数据库文件,密匙存放在 classes.dex 的字节码中。
  • hmacSHA1 是一种需要密码的哈希散列计算算法。

关于 book.db 的线索

以下的加密使用的都是明文密码 password
实测发现,这个加密,仅仅使用了 sqlcipher 进行一次加密,其中的书名是乱码,应当有二次加密的过程才对。

sqlcipher-windows

  • book.db 的加密密匙为:SessionBookDataUtil
  • book.db 的加密密匙为:SessionBookDataUtil

用 sqlcipher 解密流程:

  1. 首先提取出加密的 .db 文件,比如 books.db
    这个文件当中存放这比较重要的两个信息:key random
  2. 输出解密的数据库文件:

sqlite> attach database "E:\books.db" as books key "SessionBookDataUtil";
sqlite> .databases
seq  name             file
---  ---------------  ----------------------------------------------------------
0    main             E:\books_unencrypted.db
2    books            E:\books.db

sqlite> .backup "books" "E:\books_decrypted.db"

重点:

attach database "E:\books.db" as books key "SessionBookDataUtil";
.backup "books" "E:\books_decrypted.db";

greenDAO

classes3.dex
com.jingdong.app.reader.data.a.a.z
这里使用了 greenrobot 的开源库 DaoMaster 数据库,用于对数据进行加密。

greenDAO: Android ORM for your SQLite database
Note: for new apps we recommend ObjectBox, a new object-oriented database that is much faster than SQLite and easier to use. For existing apps based on greenDAO we offer DaoCompat for an easy switch (see also the announcement).

greenDAO Android ORMgreenDAO is an open source Android ORM making development for SQLite databases fun again. It relieves developers from dealing with low-level database requirements while saving development time. SQLite is an awesome embedded relational database. Still, writing SQL and parsing query results are quite tedious and time-consuming tasks. greenDAO frees you from these by mapping Java objects to database tables (called ORM, “object/relational mapping”). This way you can store, update, delete, and query for Java objects using a simple object oriented API.

greenDAO

import com.jingdong.app.reader.tools.base.b;

private static DaoSession a;

public static DaoSession a(Context context) {
    AssertUtil.assertApplicationContext(context);
    if (a == null) {
        synchronized (z.class) {
            DaoMaster daoMaster;
            a aVar = new a(context, "book.db");
            if (b.a) {
                daoMaster = new DaoMaster(aVar.getWritableDb());
            } else {
                daoMaster = new DaoMaster(aVar.getEncryptedWritableDb("SessionBookDataUtil"));
            }
            a = daoMaster.newSession();
        }
    }
    return a;
}

这是一个 public static 变量类,用于存放全局变量的。
classes.dex
com.jingdong.app.reader.tools.base.b

package com.jingdong.app.reader.tools.base;

import java.util.Map;

/* compiled from: BuildConfigUtil */
public class b {
    public static boolean a;
    public static String b;
    public static int c;
    public static String d;
    public static String e;
    public static String f;
    public static String g;
    public static String h;
    public static String i;
    public static String j;
    public static String k;
    public static Map<String, String> l;
    public static int m;
}

初始化代码在这里:
这里的 b.a 应该是一个 debug 标志,用于调试过程中取消加密流程。

import com.jingdong.app.reader.tools.base.b;

@Keep
public class JdReaderApp extends BaseApplication {
        
    private void initPreloadedCPA() {
        String str = "100000";
        try {
            String[] stringArray = getResources().getStringArray(2130903044);
            String[] stringArray2 = getResources().getStringArray(2130903043);
            String[] stringArray3 = getResources().getStringArray(2130903042);
            if (stringArray.length == stringArray2.length && stringArray.length == stringArray3.length) {
                for (int i = 0; i < stringArray.length; i++) {
                    StringBuilder stringBuilder = new StringBuilder();
                    stringBuilder.append("system/etc/");
                    stringBuilder.append(stringArray[i]);
                    if (new File(stringBuilder.toString()).exists()) {
                        CharSequence charSequence = stringArray2[i];
                        CharSequence charSequence2 = stringArray3[i];
                        if (!TextUtils.isEmpty(charSequence) && !TextUtils.isEmpty(charSequence2)) {
                            b.f = charSequence;
                            b.g = charSequence2;
                            b.h = "yd001";
                            b.i = str;
                            b.j = str;
                            StringBuilder stringBuilder2 = new StringBuilder();
                            stringBuilder2.append(b.g);
                            stringBuilder2.append("_");
                            stringBuilder2.append(b.h);
                            b.e = stringBuilder2.toString();
                            return;
                        }
                        return;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void initBasicInfo() {
        StringBuilder stringBuilder;
        b.a = false;
        b.b = "com.jingdong.app.reader.campus";
        b.c = 3030002;
        b.d = "3.3.0";
        b.k = "college";
        com.meituan.android.walle.b a = f.a(this);
        String str = "_";
        if (a != null) {
            b.f = a.a();
            b.l = a.b();
            if (!com.jingdong.app.reader.tools.k.a.a(b.l)) {
                b.i = (String) b.l.get("unionId");
                b.j = (String) b.l.get("unionSiteId");
                b.g = (String) b.l.get("partnerID");
                b.h = (String) b.l.get("subPartnerID");
                if (!(TextUtils.isEmpty(b.g) || TextUtils.isEmpty(b.h))) {
                    stringBuilder = new StringBuilder();
                    stringBuilder.append(b.g);
                    stringBuilder.append(str);
                    stringBuilder.append(b.h);
                    b.e = stringBuilder.toString();
                }
            }
        }
        if (TextUtils.isEmpty(b.f)) {
            b.f = "guanwang";
        }
        if (TextUtils.isEmpty(b.g)) {
            b.g = "hybt100";
        }
        if (TextUtils.isEmpty(b.h)) {
            b.h = "hybt103";
        }
        String str2 = "100000";
        if (TextUtils.isEmpty(b.i)) {
            b.i = str2;
        }
        if (TextUtils.isEmpty(b.j)) {
            b.j = str2;
        }
        if (!(!TextUtils.isEmpty(b.e) || TextUtils.isEmpty(b.g) || TextUtils.isEmpty(b.h))) {
            stringBuilder = new StringBuilder();
            stringBuilder.append(b.g);
            stringBuilder.append(str);
            stringBuilder.append(b.h);
            b.e = stringBuilder.toString();
        }
        initPreloadedCPA();
        fix();
    }

    
}

章节信息的加密 chapter_divisions_book_store.db SessionChapterDivisionsBookStoreDataUtil

classes2.dex
com.jd.app.reader.downloader.core.data.database.manage.SessionChapterDivisionsBookStoreDataUtil

这里的加密密码为:

 public static DaoSession getChapterDivisionsBookStoreDaoSession(Context context) throws Exception {
        AssertUtil.assertApplicationContext(context);
        if (mChapterDivisionsBookStoreDaoSession == null) {
            synchronized (SessionChapterDivisionsBookStoreDataUtil.class) {
                DaoMaster daoMaster;
                if (helper == null) {
                    helper = new DevOpenHelper(context, "chapter_divisions_book_store.db", null);
                }
                if (b.a) {
                    daoMaster = new DaoMaster(helper.getWritableDb());
                } else {
                    daoMaster = new DaoMaster(helper.getEncryptedWritableDb("password"));
                }
                mChapterDivisionsBookStoreDaoSession = daoMaster.newSession();
            }
        }
        return mChapterDivisionsBookStoreDaoSession;
    }

SessionDownloadFailedRecordUtil -> download_failed_record.db

@classes2.dex

com.jd.app.reader.downloader.core.data.database.manage.SessionDownloadFailedRecordUtil

    public static DaoSession getDownloadFailedRecordTableModelDaoSession(Context context) throws Exception {
        AssertUtil.assertApplicationContext(context);
        if (mDownloadFailedRecord == null) {
            synchronized (SessionDownloadFailedRecordUtil.class) {
                DaoMaster daoMaster;
                if (helper == null) {
                    helper = new DevOpenHelper(context, "download_failed_record.db", null);
                }
                if (b.a) {
                    daoMaster = new DaoMaster(helper.getWritableDb());
                } else {
                    daoMaster = new DaoMaster(helper.getEncryptedWritableDb("password"));
                }
                mDownloadFailedRecord = daoMaster.newSession();
            }
        }
        return mDownloadFailedRecord;
    }

SessionTheWholeBookStoreDataUtil -> the_whole_book_store.db

完整书籍存储数据。
com.jd.app.reader.downloader.core.data.database.manage.SessionTheWholeBookStoreDataUtil

public static DaoSession getTheWholeBookStoreDaoSession(Context context) throws Exception {
    AssertUtil.assertApplicationContext(context);
    if (mTheWholeBookStoreDaoSession == null) {
        synchronized (SessionTheWholeBookStoreDataUtil.class) {
            DaoMaster daoMaster;
            if (helper == null) {
                helper = new DevOpenHelper(context, "the_whole_book_store.db", null);
            }
            if (b.a) {
                daoMaster = new DaoMaster(helper.getWritableDb());
            } else {
                daoMaster = new DaoMaster(helper.getEncryptedWritableDb("password"));
            }
            mTheWholeBookStoreDaoSession = daoMaster.newSession();
        }
    }
    return mTheWholeBookStoreDaoSession;
}

SessionFileStoreDataUtil -> file_store.db

com.jd.app.reader.downloader.core.data.database.manage.SessionFileStoreDataUtil

public static DaoSession getFileStoreDaoSession(Context context) throws Exception {
    AssertUtil.assertApplicationContext(context);
    if (mFileStoreDaoSession == null) {
        synchronized (SessionFileStoreDataUtil.class) {
            DaoMaster daoMaster;
            if (helper == null) {
                helper = new DevOpenHelper(context, "file_store.db", null);
            }
            if (b.a) {
                daoMaster = new DaoMaster(helper.getWritableDb());
            } else {
                daoMaster = new DaoMaster(helper.getEncryptedWritableDb("password"));
            }
            mFileStoreDaoSession = daoMaster.newSession();
        }
    }
    return mFileStoreDaoSession;
}

dict.db

private static DaoSession a(Context context, boolean z) {
    AssertUtil.assertApplicationContext(context);
    if (a == null || z) {
        synchronized (C.class) {
            a aVar = new a(context, "dict.db");
            boolean z2 = b.a;
            a = new DaoMaster(aVar.getEncryptedWritableDb("SessionDictDataUtil")).newSession();
        }
    }
    return a;
}

Notebook.db

@classes3.dex
通过搜过关键词 getEncryptedWritableDb 得到

public static DaoSession a(Context context) {
    AssertUtil.assertApplicationContext(context);
    if (a == null) {
        synchronized (z.class) {
            DaoMaster daoMaster;
            C0156a c0156a = new C0156a(context, "NoteBook.db");
            if (b.a) {
                daoMaster = new DaoMaster(c0156a.getWritableDb());
            } else {
                daoMaster = new DaoMaster(c0156a.getEncryptedWritableDb("SessionBookDataUtil"));
            }
            a = daoMaster.newSession();
        }
    }
    return a;
}

book.db

@classes3.dex
com.jingdong.app.reader.data.a.a.z

public static DaoSession a(Context context) {
    AssertUtil.assertApplicationContext(context);
    if (a == null) {
        synchronized (z.class) {
            DaoMaster daoMaster;
            a aVar = new a(context, "book.db");
            if (b.a) {
                daoMaster = new DaoMaster(aVar.getWritableDb());
            } else {
                daoMaster = new DaoMaster(aVar.getEncryptedWritableDb("SessionBookDataUtil"));
            }
            a = daoMaster.newSession();
        }
    }
    return a;
}
public static DaoSession a(Context context) {
    AssertUtil.assertApplicationContext(context);
    if (a == null) {
        synchronized (A.class) {
            a = new DaoMaster(new a(context, "books.db").getEncryptedWritableDb("SessionBookDataUtil")).newSession();
        }
    }
    return a;
}

这里的 a 类,是一个DAO的子类,
同文件:

private static DaoSession a;

    /* compiled from: SessionBookDataUtil */
    public static class a extends OpenHelper {
        public a(Context context, String str) {
            super(context, str);
        }

        private void a(Database database) {
            try {
                if (!a(database, "JDFolder", "TEAM_ID")) {
                    database.execSQL("ALTER TABLE JDFolder ADD COLUMN TEAM_ID TEXT DEFAULT '' ");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        private void b(Database database) {
            try {
                if (!a(database, "JDBookMark", "MEDIA_TIME")) {
                    database.execSQL("ALTER TABLE JDBookMark ADD COLUMN MEDIA_TIME INTEGER DEFAULT 0");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (!a(database, "JDBook", "BUY_TYPE")) {
                    database.execSQL("ALTER TABLE JDBook ADD COLUMN BUY_TYPE INTEGER DEFAULT 0");
                }
            } catch (SQLException e2) {
                e2.printStackTrace();
            }
        }

        private void c(Database database) {
            try {
                if (!a(database, "JDBook", "TEAM_ID")) {
                    database.execSQL("ALTER TABLE JDBook ADD COLUMN TEAM_ID TEXT DEFAULT '' ");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        public void onUpgrade(Database database, int i, int i2) {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("Upgrading schema from version ");
            stringBuilder.append(i);
            stringBuilder.append(" to ");
            stringBuilder.append(i2);
            Log.i("greenDAO", stringBuilder.toString());
            if (i < 9) {
                c(database);
            }
            if (i < 10) {
                a(database);
            }
            if (i < 12) {
                b(database);
            }
        }

关于书本的加密 OpenBookAction

类名:com.jingdong.app.reader.main.action.OpenBookAction

    /* access modifiers changed from: private */
    public boolean a(g gVar, i iVar, JDBook jDBook, Bundle bundle, JDBookMark jDBookMark) {
        g gVar2 = gVar;
        JDBook jDBook2 = jDBook;
        String format = jDBook.getFormat();
        String str = "bookFormatTag";
        String str2 = "bookServerIdTag";
        String str3 = "";
        if (a.c().r()) {
            if (!c(jDBook2)) {
                onRouterFail(gVar2, -1, "团队版权限已到期,无法继续阅读该书!");
                return true;
            }
        } else if (!c(jDBook2)) {
            ActivityTag activityTag = ActivityTag.JD_BOOKSHELF_OPENBOOK_EXCEPTION_ACTIVITY;
            Bundle bundle2 = new Bundle();
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(jDBook.getBookId());
            stringBuilder.append(str3);
            bundle2.putString(str2, stringBuilder.toString());
            bundle2.putString(str, format);
            onRouterSuccess(gVar2, new com.jingdong.app.reader.router.b.a(activityTag, bundle2));
            return true;
        }
        String str4 = JDBookTag.BOOK_FORMAT_COMICS;
        boolean equalsIgnoreCase = str4.equalsIgnoreCase(format);
        String str5 = JDBookTag.BOOK_FORMAT_MP3;
        Object obj = (equalsIgnoreCase || str5.equalsIgnoreCase(format) || b(jDBook2)) ? 1 : null;
        if (obj == null) {
            return false;
        }
        String h = a.c().h();
        JDBookMark jDBookMark2 = (JDBookMark) new com.jingdong.app.reader.data.a.a.k(this.app).c(Properties.BookRowId.eq(jDBook.getId()), Properties.UserId.eq(h), Properties.Type.eq(Integer.valueOf(0)));
        ActivityTag activityTag2 = ActivityTag.JD_EPUB_READER_ACTIVITY;
        Bundle bundle3 = bundle == null ? new Bundle() : bundle;
        bundle3.putLong("bookRowIdTag", jDBook.getId().longValue());
        StringBuilder stringBuilder2 = new StringBuilder();
        stringBuilder2.append(jDBook.getBookId());
        stringBuilder2.append(str3);
        bundle3.putString(str2, stringBuilder2.toString());
        bundle3.putString("bookPathTag", jDBook.getBookPath());
        bundle3.putString("bookNameTag", jDBook.getBookName());
        bundle3.putString("bookAuthorTag", jDBook.getAuthor());
        bundle3.putInt("bookFromTag", jDBook.getFrom());
        bundle3.putString(str, format);
        bundle3.putString("bookCoverTag", jDBook.getBigImageUrl());
        bundle3.putString("BookDecryptKeyTag", jDBook.getKey());
        bundle3.putString("bookDeviceKeyTag", jDBook.getUuid());
        bundle3.putString("BookDecryptRandomTag", jDBook.getRandom());
        bundle3.putInt("bookSourceTag", jDBook.getSource());
        bundle3.putInt("bookUpdateTag", jDBook.getUpdateNum());
        bundle3.putLong("bookSizeTag", jDBook.getSize());
        bundle3.putLong("book_buy_type_tag", jDBook.getBuyType());
        bundle3.putBoolean("bookFullDownloadTag", jDBook.getIsFullDownload());
        boolean r = a.c().r();
        str2 = JDBookTag.BOOK_FORMAT_PDF;
        String str6 = JDBookTag.BOOK_FORMAT_EPUB;
        if (!(r || jDBook.getFrom() != 0 || ((!str6.equalsIgnoreCase(format) && !str2.equalsIgnoreCase(format)) || 1 == jDBook.getSource() || 6 == jDBook.getSource()))) {
            bundle3.putBoolean("bookCanBuyTAG", true);
        }
        str = "bookMarkChapterIdTag";
        if (jDBookMark2 != null) {
            bundle3.putInt("bookMarkChapterIndexTag", jDBookMark2.getChapterIndex());
            bundle3.putString(str, jDBookMark2.getChapterId());
            bundle3.putInt("bookMarkParagraphTag", jDBookMark2.getStartParaIndex());
            bundle3.putString("bookMarkNodeTag", jDBookMark2.getStartNodePath());
            bundle3.putInt("bookMarkOffsetTag", jDBookMark2.getStartOffsetInPara());
            bundle3.putInt("bookMarkPdfPageTag", jDBookMark2.getPdfPage());
        }
        if (jDBookMark != null) {
            bundle3.putString("targetBookMarkChapterIdTag", jDBookMark.getChapterId());
            bundle3.putInt("targetBookMarkParagraphTag", jDBookMark.getStartParaIndex());
            bundle3.putInt("targetBookMarkOffsetTag", jDBookMark.getStartOffsetInPara());
        }
        if (str6.equalsIgnoreCase(format)) {
            activityTag2 = ActivityTag.JD_EPUB_READER_ACTIVITY;
        } else if (str2.equalsIgnoreCase(format)) {
            if (a()) {
                activityTag2 = ActivityTag.JD_PDF_ACTIVITY;
            } else {
                activityTag2 = ActivityTag.JD_PLUGIN_ACTIVITY;
                bundle3.putLong("download_plugin_name_tag", JDPluginTag.plugin_PDF_Type);
            }
        } else if (JDBookTag.BOOK_FORMAT_TXT.equalsIgnoreCase(format)) {
            activityTag2 = ActivityTag.JD_EPUB_READER_ACTIVITY;
            if (jDBook.getFrom() == 0) {
                new f(this.app, jDBook.getKey()).a(jDBook.getBookPath());
            }
        } else if (str5.equalsIgnoreCase(format)) {
            activityTag2 = ActivityTag.JD_MEDIAPLAYER_ACTIVITY;
            bundle3.putString("audioCoverTag", jDBook.getCustomUrl());
            bundle3.putString(str, str3);
        } else if (str4.equalsIgnoreCase(format)) {
            activityTag2 = ActivityTag.JD_COMICS_ACTIVITY;
        }
        StringBuilder stringBuilder3 = new StringBuilder();
        stringBuilder3.append(jDBook.getBookId());
        stringBuilder3.append(str3);
        a(stringBuilder3.toString(), bundle3);
        a(jDBook2, bundle3);
        onRouterSuccess(gVar2, new com.jingdong.app.reader.router.b.a(activityTag2, bundle3));
        a(iVar, jDBook2);
        return true;
    }

可能和加解密又关联:
@classes4.dex
com.jingdong.app.reader.tools.b.a


/* compiled from: ClientReuqestEncryptionUtil */

public String a(String str) {
    return decryptionoperation.a(str, a(), this.i);
}

public String a(String str, boolean z) {
    return decryptionoperation.a(str, a(z), this.i);
}

LocalFileHeader

@classes4.dex
com.jingdong.app.reader.tools.l.d.g
用来存放加密所需变量的类。

/* compiled from: LocalFileHeader */
public class g {
    private int a;
    private int b;
    private byte[] c;
    private int d;
    private int e;
    private long f = 0;
    private byte[] g;
    private long h;
    private long i = 0;
    private int j;
    private int k;
    private String l;
    private long m;
    private boolean n;
    private int o = -1;
    private char[] p;
    private ArrayList q;
    private k r;
    private a s;
    private boolean t;
    private boolean u = false;
    private boolean v;

    public void a(int i) {
        this.d = i;
    }

    public void b(byte[] bArr) {
        this.c = bArr;
    }

    public int c() {
        return this.d;
    }

    public long d() {
        return this.f;
    }

    public void e(int i) {
        this.e = i;
    }

    public void f(int i) {
        this.a = i;
    }

    public void g(int i) {
        this.b = i;
    }

    public String h() {
        return this.l;
    }

    public int i() {
        return this.j;
    }

    public byte[] j() {
        return this.c;
    }

    public int k() {
        return this.e;
    }

    public long l() {
        return this.m;
    }

    public char[] m() {
        return this.p;
    }

    public int n() {
        return this.a;
    }

    public long o() {
        return this.i;
    }

    public int p() {
        return this.b;
    }

    public boolean q() {
        return this.n;
    }

    public boolean r() {
        return this.v;
    }

    public void a(long j) {
        this.h = j;
    }

    public void b(long j) {
        this.f = j;
    }

    public void c(int i) {
        this.k = i;
    }

    public void d(long j) {
        this.i = j;
    }

    public int e() {
        return this.o;
    }

    public ArrayList f() {
        return this.q;
    }

    public int g() {
        return this.k;
    }

    public void a(String str) {
        this.l = str;
    }

    public long b() {
        return this.h;
    }

    public void c(long j) {
        this.m = j;
    }

    public void d(int i) {
        this.j = i;
    }

    public void a(byte[] bArr) {
        this.g = bArr;
    }

    public void b(boolean z) {
        this.n = z;
    }

    public void c(boolean z) {
        this.v = z;
    }

    public void d(boolean z) {
        this.u = z;
    }

    public void a(char[] cArr) {
        this.p = cArr;
    }

    public void b(int i) {
        this.o = i;
    }

    public void a(ArrayList arrayList) {
        this.q = arrayList;
    }

    public void a(boolean z) {
        this.t = z;
    }

    public void a(k kVar) {
        this.r = kVar;
    }

    public a a() {
        return this.s;
    }

    public void a(a aVar) {
        this.s = aVar;
    }
}

com.jingdong.app.reader.tools.l.b.a

AESDecrypter

/* compiled from: AESDecrypter */
public class a implements c {
    private g a;
    private com.jingdong.app.reader.tools.l.b.b.a b;
    private com.jingdong.app.reader.tools.l.b.a.a c;
    private final int d = 2;
    private int e;
    private int f;
    private int g;
    private byte[] h;
    private byte[] i;
    private byte[] j;
    private byte[] k;
    private int l = 1;
    private byte[] m;
    private byte[] n;
    private int o = 0;

    public a(g gVar, byte[] bArr, byte[] bArr2) throws ZipException {
        if (gVar != null) {
            this.a = gVar;
            this.k = null;
            this.m = new byte[16];
            this.n = new byte[16];
            a(bArr, bArr2);
            return;
        }
        throw new ZipException("one of the input parameters is null in AESDecryptor Constructor");
    }

    private void a(byte[] bArr, byte[] bArr2) throws ZipException {
        g gVar = this.a;
        if (gVar != null) {
            com.jingdong.app.reader.tools.l.d.a a = gVar.a();
            if (a != null) {
                StringBuilder stringBuilder;
                int a2 = a.a();
                if (a2 == 1) {
                    this.e = 16;
                    this.f = 16;
                    this.g = 8;
                } else if (a2 == 2) {
                    this.e = 24;
                    this.f = 24;
                    this.g = 12;
                } else if (a2 == 3) {
                    this.e = 32;
                    this.f = 32;
                    this.g = 16;
                } else {
                    stringBuilder = new StringBuilder();
                    stringBuilder.append("invalid aes key strength for file: ");
                    stringBuilder.append(this.a.h());
                    throw new ZipException(stringBuilder.toString());
                }
                if (this.a.m() == null || this.a.m().length <= 0) {
                    throw new ZipException("empty or null password provided for AES Decryptor");
                }
                bArr = a(bArr, this.a.m());
                if (bArr != null) {
                    a2 = bArr.length;
                    int i = this.e;
                    int i2 = this.f;
                    if (a2 == (i + i2) + 2) {
                        this.h = new byte[i];
                        this.i = new byte[i2];
                        this.j = new byte[2];
                        System.arraycopy(bArr, 0, this.h, 0, i);
                        System.arraycopy(bArr, this.e, this.i, 0, this.f);
                        System.arraycopy(bArr, this.e + this.f, this.j, 0, 2);
                        bArr = this.j;
                        if (bArr == null) {
                            throw new ZipException("invalid derived password verifier for AES");
                        } else if (Arrays.equals(bArr2, bArr)) {
                            this.b = new com.jingdong.app.reader.tools.l.b.b.a(this.h);
                            this.c = new com.jingdong.app.reader.tools.l.b.a.a("HmacSHA1");
                            this.c.a(this.i);
                            return;
                        } else {
                            stringBuilder = new StringBuilder();
                            stringBuilder.append("Wrong Password for file: ");
                            stringBuilder.append(this.a.h());
                            throw new ZipException(stringBuilder.toString(), 5);
                        }
                    }
                }
                throw new ZipException("invalid derived key");
            }
            throw new ZipException("invalid aes extra data record - in init method of AESDecryptor");
        }
        throw new ZipException("invalid file header in init method of AESDecryptor");
    }

    public int b() {
        return 2;
    }

    public int c() {
        return this.g;
    }

    public byte[] d() {
        return this.k;
    }

    public int a(byte[] bArr, int i, int i2) throws ZipException {
        if (this.b != null) {
            int i3 = i;
            while (true) {
                int i4 = i + i2;
                if (i3 >= i4) {
                    return i2;
                }
                int i5 = i3 + 16;
                try {
                    this.o = i5 <= i4 ? 16 : i4 - i3;
                    this.c.a(bArr, i3, this.o);
                    d.a(this.m, this.l, 16);
                    this.b.a(this.m, this.n);
                    for (i4 = 0; i4 < this.o; i4++) {
                        int i6 = i3 + i4;
                        bArr[i6] = (byte) (bArr[i6] ^ this.n[i4]);
                    }
                    this.l++;
                    i3 = i5;
                } catch (ZipException e) {
                    throw e;
                } catch (Exception e2) {
                    throw new ZipException(e2);
                }
            }
        }
        throw new ZipException("AES not initialized properly");
    }

    private byte[] a(byte[] bArr, char[] cArr) throws ZipException {
        try {
            return new b(new c("HmacSHA1", "ISO-8859-1", bArr, PushConstants.PUSHSERVICE_INFO_SENDMESSAGE_BY_NOTIFICATIONSERVICE)).a(cArr, (this.e + this.f) + 2);
        } catch (Exception e) {
            throw new ZipException(e);
        }
    }

    public byte[] a() {
        return this.c.b();
    }

    public void a(byte[] bArr) {
        this.k = bArr;
    }
}

关于 GreenDAO

Database Initialization

Make sure to use a subclass of OpenHelper provided in DaoMaster to create your database instance. For example the simple DevOpenHelper, also provided in DaoMaster.

Then, when creating your database instance, just call .getEncryptedWritableDb() instead of .getWritableDb(). Finally, pass the database to DaoMaster as usual:

DevOpenHelper helper = new DevOpenHelper(this, "notes-db-encrypted.db");
Database db = helper.getEncryptedWritableDb("<your-secret-password>");
daoSession = new DaoMaster(db).newSession();

  1. SQLite 常用的命令:
    1. 输出控制
sqlite> .mode column
sqlite> .timer on
sqlite> .headers on
sqlite> .databases

seq  name             file
---  ---------------  ----------------------------------------------------------
0    main             E:\books_unencrypted.db
2    books            E:\books.db