public void processBook(List <byte[]> pidList) { int firstOffset = (int)mSections.ElementAt(0).offset; int cryptoType = mEncMobiBook.getShort(firstOffset + 0xC); if (cryptoType == 0) { Debug.WriteLine("This Book is not encrypted"); } else if (cryptoType != 1 && cryptoType != 2) { throw new Exception("Unknown Mobipocket CryptoType: " + cryptoType); } if (mMetaMap.ContainsKey(406)) { byte[] data406 = mMetaMap[406]; if ((new ArraySlice(data406)).getLongLong() != 0) { throw new Exception("Cannot Decode library or rented eBooks"); } } List <byte[]> goodPids = validatePins(pidList); byte[] pid = { 0, 0, 0, 0, 0, 0, 0, 0 }; byte[] foundKey; if (cryptoType == 1) { byte[] t1KeyVec = Encoding.Default.GetBytes("QDCVEPMU675RUBSZ"); byte [] bookKeyData; if (mHeader.getMagicString().Equals(MobiHeader.TEXT_READ)) { bookKeyData = mEncMobiBook.byteSlice(0x0E + firstOffset, 16); } else if (mMobiVersion < 0) { bookKeyData = mEncMobiBook.byteSlice(0x90 + firstOffset, 16); } else { bookKeyData = mEncMobiBook.byteSlice(mMobiLength + firstOffset + 16, 16); } foundKey = PK1Dec(bookKeyData, t1KeyVec, false); } else { int drmPointer = (int)mEncMobiBook.getLong(firstOffset + 0xA8); int drmCount = (int)mEncMobiBook.getLong(); int drmSize = (int)mEncMobiBook.getLong(); int drmFlags = (int)mEncMobiBook.getLong(); parseDRM(mEncMobiBook.byteSlice(drmPointer + firstOffset, drmSize), drmCount, goodPids); } }
public MobiHeader(ArraySlice headerSlice) { mMagic = System.Text.Encoding.Default.GetString(headerSlice.byteSlice(0x3C, 8)); if (!mMagic.Equals(BOOK_MOBI) && !mMagic.Equals(TEXT_READ)) { throw new Exception("Invalid File Format"); } mNumSections = headerSlice.getShort(76); }
public MobiBook(String filename) { mEncMobiBook = getBookSlice(filename); mHeader = new MobiHeader(mEncMobiBook); mEncMobiBook.seek(MobiHeader.HEADER_SIZE); for (int i = 0; i < mHeader.getNumberSections(); i++) { mSections.Add(new Section(mEncMobiBook)); } int offset = (int)mSections[0].offset; mCompression = mEncMobiBook.getShort(offset); mRecords = mEncMobiBook.getShort(offset + 0x8); if (mHeader.getMagicString().Equals(MobiHeader.TEXT_READ)) { mExtraDataFlags = 0; mMobiLength = 0; mMobiCodepage = 0; mMobiVersion = -1; return; } mMobiLength = (int)mEncMobiBook.getLong(offset + 0x14); mMobiCodepage = (int)mEncMobiBook.getLong(offset + 0x1c); mMobiVersion = (int)mEncMobiBook.getLong(offset + 0x68); if ((mMobiLength >= 0xE4) && (mMobiVersion >= 5)) { mExtraDataFlags = mEncMobiBook.getShort(offset + 0xF2); } if (mCompression != 17480) { // multibyte utf8 data is included in the encryption for PalmDoc compression // so clear that byte so that we leave it to be decrypted. mExtraDataFlags &= 0xFFFE; } //if exth region exists parse it for metadata array int exthFlag = (int)mEncMobiBook.getLong(offset + 0x80); int exthOffset = 16 + mMobiLength; if ((exthFlag & 0x40) > 0) { if ((exthOffset + mEncMobiBook.size() >= 4) && System.Text.Encoding.Default.GetString(mEncMobiBook.byteSlice(exthOffset + offset, 4)).Equals("EXTH")) { int nItems = (int)mEncMobiBook.getLong(exthOffset + offset + 8); int pos = offset + exthOffset + 12; for (int i = 0; i < nItems - 1; i++) { int type = (int)mEncMobiBook.getLong(pos); int size = (int)mEncMobiBook.getLong(pos + 4); mMetaMap[type] = mEncMobiBook.byteSlice(pos + 8, size - 8); /* TODO: # reset the text to speech flag and clipping limit, if present # if type == 401 and size == 9: # set clipping limit to 100% # self.patchSection(0, "\144", 16 + self.mobi_length + pos + 8) # elif type == 404 and size == 9: # make sure text to speech is enabled # self.patchSection(0, "\0", 16 + self.mobi_length + pos + 8) */ pos += size; } } } Debug.WriteLine(mHeader); Debug.WriteLine("BookTitle: {0} \nMobiLength: {1} \nMobiCodePage {2}\nExtraDataFlags: {3} \nMobiVersion: {4}\n", getBookTitle(), mMobiLength, mMobiCodepage, mExtraDataFlags, mMobiVersion); List <byte[]> pidList = new List <byte[]>(); pidList.Add(Encoding.Default.GetBytes("DL3pB54YXE")); pidList.Add(Encoding.Default.GetBytes("DL3pB54Y")); pidList.Add(Encoding.Default.GetBytes("SSEVC1U7")); processBook(pidList); }