1 /* cssdec.c - simple css descrambling program using libdvdcss
2 * Copyright © 2012 Géraud Meyer <graud@gmx.com>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * You should have received a copy of the GNU General Public License along
13 * with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <dvdcss/dvdcss.h>
30 #define EX_USAGE (~((~0)<<8))
31 #define EX_OPEN (~((~0)<<7))
34 #define EX_UNDECRYPTED (1<<0)
36 # define PROGRAM_NAME "cssdec"
38 #ifndef PROGRAM_VERSION
39 # define PROGRAM_VERSION "0.1"
41 const char *progname
= PROGRAM_NAME
;
42 const char *progversion
= PROGRAM_VERSION
;
45 /* readsector() return flags */
46 #define READ_ERROR 1<<0
48 #define SCRAMBLED 1<<2
49 #define DECRYPTED 1<<3
50 #define FAILED_DECRYPTION 1<<5
52 static int readsector ( dvdcss_t
, unsigned char *, const int );
53 static int isscrambled( const unsigned char * );
54 static int dumpsector ( unsigned char *, FILE * );
55 static int printe ( const char, const char *, ... );
59 fprintf( stderr
, "Usage:\n" );
60 fprintf( stderr
, "\t%s -V\n", progname
);
61 fprintf( stderr
, "\t%s [-v|-q] [-e] [-o <out_file> [-a]] <file> [<start_sect> [<end_sect>]]\n",
63 fprintf( stderr
, "\t%s [-v|-q] -k <file> [<start_sect>]\n", progname
);
66 int main( int argc
, char *argv
[] )
68 int status
= EX_SUCCESS
;
69 const char *dvdfile
, *outfile
= NULL
;
72 const char *outfile_mode
= "w+";
73 unsigned char data
[ DVDCSS_BLOCK_SIZE
* 2 ];
74 unsigned char *buffer
;
75 unsigned int sector
= 0, end
= INT_MAX
;
76 int n_processed
= 0, n_scrambled
= 0, n_undecrypted
= 0;
80 char b_noeof
= 0, b_keyonly
= 0;
83 while( (rc
= getopt( argc
, argv
, "qveo:akV" )) != -1 )
105 printf( "%s version %s (libdvdcss version %s)\n",
106 progname
, progversion
, dvdcss_interface_2
);
117 /* Command line args */
118 if( argc
< 1 || argc
> 3 || (b_keyonly
&& argc
> 2) )
120 printe( 1, "syntax error" );
125 if( argc
>= 2 ) sector
= (int)strtol( argv
[1], (char **)NULL
, 0 );
126 if( argc
>= 3 ) end
= (int)strtol( argv
[2], (char **)NULL
, 0 );
128 /* Initialize libdvdcss */
129 printe( 2, "%s version %s (libdvdcss version %s)",
130 progname
, progversion
, dvdcss_interface_2
);
131 dvdcss
= dvdcss_open( (char *)dvdfile
);
134 printe( 1, "opening of the DVD (%s) failed", dvdfile
);
135 exit( status
| EX_OPEN
);
138 /* Try to get a key */
139 printe( 2, "trying to obtain the title key at sector %d", sector
);
140 rc
= dvdcss_seek( dvdcss
, sector
, DVDCSS_SEEK_KEY
);
143 printe( 1, "getting the title key failed (%s)",
144 dvdcss_error( dvdcss
) );
145 exit( status
| EX_KEY
);
147 if( b_keyonly
) goto CLOSEDVD_EXIT
;
149 /* Open the output file */
152 out
= fopen( outfile
, outfile_mode
);
155 printe( 1, "opening of the output file (%s) failed (%s)",
156 outfile
, strerror( errno
) );
157 exit( status
| EX_OPEN
);
161 /* Align our read buffer */
162 buffer
= data
+ DVDCSS_BLOCK_SIZE
163 - ((long int)data
& (DVDCSS_BLOCK_SIZE
-1));
165 for( ; sector
< end
; sector
++ )
168 rc
= readsector( dvdcss
, buffer
, sector
);
173 printe( 2, "stop reading before sector %d", sector
);
176 if( rc
& READ_ERROR
)
178 printe( 1, "sect %d: read error; aborting", sector
);
186 if( ! (rc
& DECRYPTED
) )
190 /* Process the sector */
191 if( ! dumpsector( buffer
, out
) ) {
192 printe( 1, "sect %d: writing failed; aborting", sector
);
198 /* Summary & Return status */
199 printe( 2, "summary of processed sectors:" );
200 printe( 2, "%d undecrypted scrambled sectors", n_undecrypted
);
201 printe( 2, "%d scrambled sectors", n_scrambled
);
202 printe( 2, "%d processed sectors", n_processed
);
204 printe( 2, "partial processing because of an I/O error" );
205 if( b_noeof
&& sector
< end
) status
|= EX_IO
;
206 if( n_undecrypted
> 0 ) status
|= EX_UNDECRYPTED
;
209 if( fflush( out
) != 0 )
211 printe( 1, "flushing of the output failed (%s)", strerror( errno
) );
215 if( fclose( out
) == EOF
)
216 printe( 1, "closing of the ouput file failed (%s)",
219 rc
= dvdcss_close( dvdcss
);
220 if( rc
< 0 ) printe( 1, "closing of the DVD failed" );
224 /* Read a sector; read decrypted again if it seems crypted */
225 static int readsector( dvdcss_t dvdcss
, unsigned char *buffer
, const int sector
)
229 /* Seek at sector sector and read one sector */
230 rc
= dvdcss_seek( dvdcss
, sector
, DVDCSS_NOFLAGS
);
233 printe( 1, "sect %d: seek failed (%s)", sector
, dvdcss_error( dvdcss
) );
234 return flags
| READ_ERROR
;
236 rc
= dvdcss_read( dvdcss
, buffer
, 1, DVDCSS_NOFLAGS
);
239 printe( 1, "sect %d: read failed (%s)", sector
, dvdcss_error( dvdcss
) );
240 return flags
| READ_ERROR
;
244 printe( 1, "sect %d: EOF", sector
);
245 return flags
| READ_EOF
;
248 if( ! isscrambled( buffer
) /* Check if sector is encrypted */ )
249 printe( 3, "sect %d: not crypted", sector
);
252 printe( 3, "sect %d: crypted", sector
);
255 /* Seek at sector sector and try to decrypt sector */
256 rc
= dvdcss_seek( dvdcss
, sector
, DVDCSS_NOFLAGS
);
259 printe( 1, "sect %d: seek failed (%s)",
260 sector
, dvdcss_error( dvdcss
) );
263 rc
= dvdcss_read( dvdcss
, buffer
, 1, DVDCSS_READ_DECRYPT
);
264 /* Warning: A failure to decrypt is not considered an error in
265 * libdvdcss 1.2.12 */
268 printe( 2, "sect %d: read (decrypted) failed (%s)",
269 sector
, dvdcss_error( dvdcss
) );
273 if( isscrambled( buffer
) /* Check if the decryption really succeeded */ )
275 /* Probably a bug in libdvdcss not to have given an error earlier */
276 printe( 1, "sect %d: still apparently crypted after decryption",
278 flags
|= FAILED_DECRYPTION
;
282 printe( 3, "sect %d: decrypted", sector
);
290 /* Check if a sector is scrambled */
291 static int isscrambled( const unsigned char *buffer
)
293 return buffer
[ 0x14 ] & 0x30;
296 /* Dump the sector on stdout */
297 static int dumpsector( unsigned char *buffer
, FILE *out
)
300 n
= fwrite( (void *)buffer
, DVDCSS_BLOCK_SIZE
, 1, out
);
303 printe( 1, "write error (%s)", strerror( errno
) );
310 /* Print a line on stderr preceded by the program name */
311 int printe( const char level
, const char *format
, ... )
315 if( level
> verbosity
) return 1;
317 va_start( arg
, format
);
318 fprintf( stderr
, "%s: ", progname
);
319 rc
= vfprintf( stderr
, format
, arg
);
321 fprintf( stderr
, "\n" );