package com.mpaa.decss; import java.io.*; /** * Title: LinearFeedbackShiftRegisterPair.java * Description: Sort of based on JDeCSS Java code originally written by Gavin Hall (www.tweakmonkey.freeserve.co.uk) * The title key cracker is based on Frank Stevenson's work describing various ways to break CSS and a close * examinination of VobDec code. * * This version has been brought to you by DiatriBe. * * Note: There is no attempt to do DVD drive authentication in this code. You should first play the DVD * with a software player (only for a second, unless you want to watch the whole movie). Once this is done, * then authentication has completed. The VOB files can now be copied! * @author DiatriBe * @version 1.0 */ public class CSSDescrambler { LinearFeedbackShiftRegisterPair feedbackRegisterPair = new LinearFeedbackShiftRegisterPair(); TitleKey titleKey; File inputVobFile; File outputVobFile; /** * Default constructor. * * @param titleKey the 40 bit key used for the decryption. * @param inputVobFile the source MPEG file. This can be the file that is directly on the DVD (once the drive has * been authenticated, files can be copied directly from it). * @param outputVobFile the file to write the decrpyted stream into. */ public CSSDescrambler(TitleKey titleKey, File inputVobFile, File outputVobFile) { this.titleKey = titleKey; this.inputVobFile = inputVobFile; this.outputVobFile = outputVobFile; } /** * This method will descramble a file passed in to the constructor as inputVobFile to the file passed in as outputVobFile, * using the title key. */ public void descramble() { try { DataInputStream reader = new DataInputStream(new BufferedInputStream(new FileInputStream(inputVobFile))); DataOutputStream writer = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outputVobFile))); long fileSize = inputVobFile.length(); long bytesRead = 0; int[] sector = new int[2048]; for (int block = 0; bytesRead < fileSize; block++) { for (int index = 0; index < 2048; index++) sector[index] = reader.readUnsignedByte(); bytesRead += 2048; if ((block % 1000) == 0) System.out.println("Decrypting block " + block); if ((sector[0x14] & 0x30) != 0) // PES scrambling control { sector = descrambleSector(sector); sector[0x14] &= 0x8F; } for (int index = 0; index < 2048; index++) writer.writeByte(sector[index]); } reader.close(); writer.flush(); writer.close(); } catch (FileNotFoundException fnfe) { System.out.println("The imput file '" + inputVobFile.getName() + "' could not be found."); } catch (Exception ex) { System.out.println("There was an error encountered while trying to decrypt '" + inputVobFile.getName() + "' to '" + outputVobFile.getName() + "'"); ex.printStackTrace(); } } /** * This method does the actual descrambling of a single sector. The title key is used to decrypt the data. * * @param sector int array (2048) containing an encrypted DVD sector. * @return returns the decrypted sector as a int array (2048). */ private int[] descrambleSector(int[] sector) { MirrorBitsTable mirrorTable = MirrorBitsTable.getInstance(); feedbackRegisterPair.setRegisters(titleKey); // feedbackRegisterPair.useClassic(true); int[] salt = { sector[0x54], sector[0x55], sector[0x56], sector[0x57], sector[0x58] }; feedbackRegisterPair.salt(salt); int carry = 0; for (int index = 128; index < 2048; index++) { feedbackRegisterPair.clockOneByte(); int cipherStreamOutput = feedbackRegisterPair.getLfsr17Output(true) + feedbackRegisterPair.getLfsr25Output(false) + carry; int tableSubstitution = SubstitutionTable.getAt(sector[index]); sector[index] = (cipherStreamOutput ^ tableSubstitution) & 0xFF; carry = cipherStreamOutput>> 8; } return sector; } /** * This is the main method for the prgram that will be executed when the program is started. * * @param args command line arguments. */ public static void main(String[] args) { if (args.length != 2) { System.out.println("Wrong number of arguments (" + args.length + ") passed!"); System.out.println("Format is CSSDescrambler 'input file name' 'output file name'"); return; } File inputFile = new File(args[0]); System.out.println(); System.out.println("Descrambling file '" + args[0] + "' to '" + args[1] + "'"); System.out.println(); System.out.println("Blocks in input file = " + (inputFile.length() / 2048)); System.out.println(); TitleKeyCracker titleKeyCracker = new TitleKeyCracker(inputFile); if (titleKeyCracker.attackKey()) { TitleKey titleKey = titleKeyCracker.getTitleKey(); // TitleKey titleKey = new TitleKey(0xA7, 0x07, 0xBF, 0x53, 0x84); System.out.println("Title key found is = " + titleKey.toString()); System.out.println(); System.out.println("Descrambling started."); CSSDescrambler cssDescrambler = new CSSDescrambler(titleKey, inputFile, new File(args[1])); long startTime = System.currentTimeMillis(); cssDescrambler.descramble(); long endTime = System.currentTimeMillis(); System.out.println("Descrambling finished. Elapsed time = " + ((endTime - startTime) / 1000) + " sec"); } else System.out.println("\n Unable to descramble file because title key attack failed"); } }