Audio-M4P

 view release on metacpan or  search on metacpan

lib/Audio/M4P/Decrypt.pm  view on Meta::CPAN

sub DeDRMS {
    my ( $self, $infile, $outfile ) = @_;
    $self->{QTStream}->ReadFile($infile);
    $self->{QTStream}->ParseBuffer();
    my $sampleTable = $self->{QTStream}->GetSampleTable();
    my $userKey     = $self->GetUserKey( $self->{QTStream}->{userID},
        $self->{QTStream}->{keyID} )
      || $self->GetSCInfoUserKey();
    if ( !$userKey ) {
        carp "Cannot find user key for $infile";
        return;
    }
    else {
        print "User key is $userKey\n" if $self->{DEBUG};
    }
    my $md5 = new Digest::MD5;
    $md5->add( $self->{QTStream}->{name}, $self->{QTStream}->{iviv} );
    my $alg = new Crypt::Rijndael( $userKey, Crypt::Rijndael::MODE_CBC );
    $alg->set_iv( $md5->digest );
    $self->Decrypt(
        \$self->{QTStream}->{priv},          0,
        length( $self->{QTStream}->{priv} ), $alg
    );
    if ( $self->{QTStream}->{priv} !~ /^itun/ ) {
        carp "Priv decryption if $infile failed.";
        return;
    }
    my $key = substr( $self->{QTStream}->{priv}, 24, 16 );
    $alg = new Crypt::Rijndael( $key, Crypt::Rijndael::MODE_CBC );
    $alg->set_iv( substr( $self->{QTStream}->{priv}, 48, 16 ) );
    my $mdata = $self->{QTStream}->FindAtom('mdat');
    my $posit = $mdata->start + 8;

    foreach my $samplesize ( @{$sampleTable} ) {
        $self->Decrypt( $mdata->rbuf, $posit, $samplesize, $alg );
        $posit += $samplesize;
    }
    $self->{QTStream}->ConvertDrmsToMp4a();
    if ( $self->{forceclean} ) {
        $self->{QTStream}
          ->CleanAppleM4aPersonalData( force => 1, zero_free_atoms => 1 );
    }
    $self->{QTStream}->WriteFile($outfile);
}

# DeDRMS is aliased to DecryptFile
sub DecryptFile { DeDRMS(@_) }

=head1 NAME

Audio::M4P::Decrypt -- DRMS decryption of Apple iTunes style MP4 player files

=head1 DESCRIPTION
    
Originally derived from the DeDRMS.cs program by Jon Lech Johansen

=head1 SYNOPSIS

 use Audio::M4P::Decrypt;

 my $outfile = 'mydecodedfile';
 my $deDRMS = new Audio::M4P::Decrypt;
 $deDRMS->DeDRMS($mp4file, $outfile);


=head1 METHODS

=over 4

=item B<new>

 my $cs = new Audio::M4P::Decrypt;

 my $cs_conparam = Audio::M4P::Decrypt->new(
   strHome => '~', sPfix => '.', dirSep => '/' );

Optional arguments: strHome is the directory containing the keyfile directory.
After running VLC on a .m4p file under Windows, MacOS X, and Linux, this should
be found by the module automatically (APPDATA dir under Win32, ~/ under OS X and 
Linux). sPfix is '.' for MacOS/*nix, nil with Windows. dirSep is the char that 
separates directories, often /.

For debugging purposes, use eg:
 my $cs_conparam = Audio::M4P::Decrypt->new(
     DEBUG => 1, DEBUGDUMPFILE => 'm4ptree.html'
 );

DEBUG turns on debugging output. DEBUGDUMPFILE is an output file name to dump 
an html picture of the m4p data structure. 

=item B<DeDRMS>

 my $cs = new Audio::M4P::Decrypt( forceclean => 1 );
 $cs->DeDRMS('infilename', 'outfilename');

Decode infilename, write to outfilename. Reading slurps up an entire file,
so output can overwrite the same file without a problem, we hope. Backup first.
'forceclean => 1' will also attempt to remove residual personal data from the file.

=item B<DecryptFile>

$cs->DecryptFile('infilename', 'outfilename');

More descriptive alias for the B<DeDRMS> method.

=back

=head1 B<SEE ALSO>

=over 4

=item L<LWP::UserAgent::iTMS_Client>

=item L<iTunes::Sid>

=back

=head1 B<NOTES>

    This software is designed to allow different but fair use of music by the 
    purchaser of the music. In no way is this software intended to facilitate 



( run in 1.753 second using v1.01-cache-2.11-cpan-39bf76dae61 )