/// <summary> /// (Crudely) determines if file is a CourseSmart file /// </summary> /// <param name="file">Path to file to check</param> /// <returns>True if successful; null otherwise</returns> public static bool IsCourseSmartFile(string file) { CourseSmartReader reader = new CourseSmartReader(file); byte firstByte = reader.ReadByte(); if (firstByte == 0 || firstByte > 5) { // first byte in file must be 1-5 return(false); } switch (firstByte) { case 1: // no restrictions, no key/value pairs, just file data break; case 2: // check for width/height/offset uint width = reader.ReadUInt16(); uint height = reader.ReadUInt16(); uint offset = reader.ReadUInt16(); if (width == 0 || height == 0 || offset == 0) { // should have some value here return(false); } break; case 3: uint numberOfKeyValuePairs = reader.ReadUInt16(); if (numberOfKeyValuePairs == 0 || numberOfKeyValuePairs > 20) { // sanity check on how many key value pairs we will read // should be more than 0 as we need a book name & page #, // but there shouldnt be more than 10ish (most I've seen // is 8, but lets call it 20) return(false); } break; case 4: case 5: // both of these are error cases, no sense loading them as // there shouldnt be anything here return(false); } return(true); }
/// <summary> /// Clean up reader & any data kicking around /// </summary> public void Dispose() { this.Data.Clear(); this.Data = null; if (this.MovieData != null) { this.MovieData = null; } if (this.Reader != null) { this.Reader.Close(); this.Reader.Dispose(); this.Reader = null; } }
/// <summary> /// Constructor creates the underlying reader and handles loading the file /// </summary> /// <param name="file"></param> public CourseSmartFile(string file) { this.Filename = file; this.Reader = new CourseSmartReader(file); this.Load(); }
/// <summary> /// (Crudely) determines if file is a CourseSmart file /// </summary> /// <param name="file">Path to file to check</param> /// <returns>True if successful; null otherwise</returns> public static bool IsCourseSmartFile(string file) { CourseSmartReader reader = new CourseSmartReader(file); byte firstByte = reader.ReadByte(); if (firstByte == 0 || firstByte > 5) { // first byte in file must be 1-5 return false; } switch (firstByte) { case 1: // no restrictions, no key/value pairs, just file data break; case 2: // check for width/height/offset uint width = reader.ReadUInt16(); uint height = reader.ReadUInt16(); uint offset = reader.ReadUInt16(); if (width == 0 || height == 0 || offset == 0) { // should have some value here return false; } break; case 3: uint numberOfKeyValuePairs = reader.ReadUInt16(); if (numberOfKeyValuePairs == 0 || numberOfKeyValuePairs > 20) { // sanity check on how many key value pairs we will read // should be more than 0 as we need a book name & page #, // but there shouldnt be more than 10ish (most I've seen // is 8, but lets call it 20) return false; } break; case 4: case 5: // both of these are error cases, no sense loading them as // there shouldnt be anything here return false; } return true; }
/// <summary> /// Decryption routine - extracted from offline viewer code /// </summary> /// <param name="data">Byte List containing encrypted movie data</param> private void DecryptMovieData(ref byte[] data) { // load encrypted data into cs reader using (MemoryStream dataStream = new MemoryStream(data)) using (CourseSmartReader dataReader = new CourseSmartReader(dataStream)) { byte XORKeyLength = dataReader.ReadByte(); byte SPECIAL = dataReader.ReadByte(); // not 100% on what this value is byte swapTableLength = dataReader.ReadByte(); // read XOR key & swap table byte[] XORKey = dataReader.ReadBytes(XORKeyLength); byte[] swapTable = dataReader.ReadBytes(swapTableLength); // calculate how much movie data remains after reading xor key and swap table int movieDataLength = data.Length - (int)dataReader.BaseStream.Position; // not sure yet int smallerBytesToSwap = movieDataLength / SPECIAL; // smaller int largerBytesToSwap = movieDataLength - (smallerBytesToSwap * (SPECIAL - 1)); // larger // stage 1 - read remaining data from file and decrypt using XOR key List<byte> decryptedDataByteList = new List<byte>(); for (int i = 0; i < movieDataLength; i++) { decryptedDataByteList.Add((byte)(dataReader.ReadByte() ^ XORKey[i % XORKey.Length])); } byte[] decryptedData = decryptedDataByteList.ToArray(); // stage 2 - load decrypted data into cs reader & perform byte-swapping to finish decrypting data using (MemoryStream decryptedDataStream = new MemoryStream(decryptedData)) using (CourseSmartReader decryptedDataReader = new CourseSmartReader(decryptedDataStream)) { for (int i = swapTableLength - 1; i >= 0; i--) { byte swapValue = swapTable[i]; // swap is only performed if value from SwapTable is different from current position in table if (swapValue != i) { // not exactly sure what this is about int bytesToSwap1 = (swapValue == (SPECIAL - 1)) ? largerBytesToSwap : smallerBytesToSwap; int bytesToSwap2 = (i == (SPECIAL - 1)) ? largerBytesToSwap : smallerBytesToSwap; int bytesToSwap = Math.Min(bytesToSwap1, bytesToSwap2); int secondSwapPosition = swapValue * smallerBytesToSwap; int firstSwapPosition = i * smallerBytesToSwap; // read two sets of bytes to swap decryptedDataReader.BaseStream.Position = firstSwapPosition; byte[] firstSwapBuffer = decryptedDataReader.ReadBytes(bytesToSwap); decryptedDataReader.BaseStream.Position = secondSwapPosition; byte[] secondSwapBuffer = decryptedDataReader.ReadBytes(bytesToSwap); // write bytes back to decrypted data array Buffer.BlockCopy(secondSwapBuffer, 0, decryptedData, firstSwapPosition, bytesToSwap); Buffer.BlockCopy(firstSwapBuffer, 0, decryptedData, secondSwapPosition, bytesToSwap); } } } // overwrite reference to data with our freshly decrypted movie data data = decryptedData; } }
/// <summary> /// Decryption routine - extracted from offline viewer code /// </summary> /// <param name="data">Byte List containing encrypted movie data</param> private void DecryptMovieData(ref byte[] data) { // load encrypted data into cs reader using (MemoryStream dataStream = new MemoryStream(data)) using (CourseSmartReader dataReader = new CourseSmartReader(dataStream)) { byte XORKeyLength = dataReader.ReadByte(); byte SPECIAL = dataReader.ReadByte(); // not 100% on what this value is byte swapTableLength = dataReader.ReadByte(); // read XOR key & swap table byte[] XORKey = dataReader.ReadBytes(XORKeyLength); byte[] swapTable = dataReader.ReadBytes(swapTableLength); // calculate how much movie data remains after reading xor key and swap table int movieDataLength = data.Length - (int)dataReader.BaseStream.Position; // not sure yet int smallerBytesToSwap = movieDataLength / SPECIAL; // smaller int largerBytesToSwap = movieDataLength - (smallerBytesToSwap * (SPECIAL - 1)); // larger // stage 1 - read remaining data from file and decrypt using XOR key List <byte> decryptedDataByteList = new List <byte>(); for (int i = 0; i < movieDataLength; i++) { decryptedDataByteList.Add((byte)(dataReader.ReadByte() ^ XORKey[i % XORKey.Length])); } byte[] decryptedData = decryptedDataByteList.ToArray(); // stage 2 - load decrypted data into cs reader & perform byte-swapping to finish decrypting data using (MemoryStream decryptedDataStream = new MemoryStream(decryptedData)) using (CourseSmartReader decryptedDataReader = new CourseSmartReader(decryptedDataStream)) { for (int i = swapTableLength - 1; i >= 0; i--) { byte swapValue = swapTable[i]; // swap is only performed if value from SwapTable is different from current position in table if (swapValue != i) { // not exactly sure what this is about int bytesToSwap1 = (swapValue == (SPECIAL - 1)) ? largerBytesToSwap : smallerBytesToSwap; int bytesToSwap2 = (i == (SPECIAL - 1)) ? largerBytesToSwap : smallerBytesToSwap; int bytesToSwap = Math.Min(bytesToSwap1, bytesToSwap2); int secondSwapPosition = swapValue * smallerBytesToSwap; int firstSwapPosition = i * smallerBytesToSwap; // read two sets of bytes to swap decryptedDataReader.BaseStream.Position = firstSwapPosition; byte[] firstSwapBuffer = decryptedDataReader.ReadBytes(bytesToSwap); decryptedDataReader.BaseStream.Position = secondSwapPosition; byte[] secondSwapBuffer = decryptedDataReader.ReadBytes(bytesToSwap); // write bytes back to decrypted data array Buffer.BlockCopy(secondSwapBuffer, 0, decryptedData, firstSwapPosition, bytesToSwap); Buffer.BlockCopy(firstSwapBuffer, 0, decryptedData, secondSwapPosition, bytesToSwap); } } } // overwrite reference to data with our freshly decrypted movie data data = decryptedData; } }