right i don't know how

| | Comments (0) | TrackBacks (0)

right i don't know how many laws I may be contravening by publishing
this but here's a nice piece of code by Jon "DeCSS" Johansen to remove
DRMS nicely called "DeDRMS":


/**********************
* DeDRMS.cs: DeDRMS 0.1
**********************
* Copyright (C) 2004 Jon Lech Johansen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
********************/

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;

class M4PStream
{
private Rijndael alg;

private BinaryReader br;
private BinaryWriter bw;
private byte [] sbuffer;

private string AtomDRMS = "drms";
private string AtomMP4A = "mp4a";
private string AtomSINF = "sinf";
private string AtomUSER = "user";
private string AtomKEY = "key ";
private string AtomIVIV = "iviv";
private string AtomNAME = "name";
private string AtomPRIV = "priv";
private string AtomSTSZ = "stsz";
private string AtomMDAT = "mdat";

public M4PStream( FileStream fs )
{
br = new BinaryReader( fs );
bw = new BinaryWriter( fs );
sbuffer = br.ReadBytes( Convert.ToInt32( fs.Length ) );

alg = Rijndael.Create();
alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.None;
}

byte [] NetToHost( byte [] Input, int Pos, int Count )
{
if( BitConverter.IsLittleEndian )
{
for( int i = 0; i < Count; i++ )
{
Array.Reverse( Input, Pos + (i * 4), 4 );
}
}

return Input;
}

int GetAtomPos( string Atom )
{
byte [] Bytes = Encoding.ASCII.GetBytes( Atom );

for( int i = 0; i < (sbuffer.Length - 3); i++ )
{
if( sbuffer[ i + 0 ] == Bytes[ 0 ] &&
sbuffer[ i + 1 ] == Bytes[ 1 ] &&
sbuffer[ i + 2 ] == Bytes[ 2 ] &&
sbuffer[ i + 3 ] == Bytes[ 3 ] )
{
return i;
}
}

throw new Exception( String.Format( "Atom '{0}' not found", Atom ) );
}

uint GetAtomSize( int Pos )
{
byte [] Bytes = new byte[ 4 ];
Buffer.BlockCopy( sbuffer, Pos - 4, Bytes, 0, 4 );
return BitConverter.ToUInt32( NetToHost( Bytes, 0, 1 ), 0 );
}

byte [] GetAtomData( int Pos, bool bNetToHost )
{
uint Size;
byte [] Bytes;

Size = GetAtomSize( Pos );
Bytes = new byte[ Size - 8 ];
Buffer.BlockCopy( sbuffer, Pos + 4, Bytes, 0, Bytes.Length );

return bNetToHost ? NetToHost( Bytes, 0, Bytes.Length / 4 ) : Bytes;
}

public void Decrypt( byte [] CipherText, int Offset, int Count,
byte [] Key, byte [] IV )
{
MemoryStream ms = new MemoryStream();

ICryptoTransform ct = alg.CreateDecryptor( Key, IV );
CryptoStream cs = new CryptoStream( ms, ct, CryptoStreamMode.Write );
cs.Write( CipherText, Offset, (Count / 16) * 16 );
cs.Close();

ms.ToArray().CopyTo( CipherText, Offset );
}

public byte [] GetUserKey( uint UserID, uint KeyID )
{
byte [] UserKey;
BinaryReader bruk;

string strHome =
Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData );
bool bUnix = Environment.OSVersion.ToString().IndexOf( "Unix" ) != -1;
string strFile = String.Format( "{0}{1}{2}drms{3}{4:X8}.{5:D3}", strHome,
Path.DirectorySeparatorChar, bUnix ? "." : "",
Path.DirectorySeparatorChar, UserID, KeyID );

bruk = new BinaryReader( File.OpenRead( strFile ) );
UserKey = bruk.ReadBytes( Convert.ToInt32( bruk.BaseStream.Length ) );
bruk.Close();

return UserKey;
}

public int [] GetSampleTable()
{
byte [] adSTSZ = GetAtomData( GetAtomPos( AtomSTSZ ), true );
int SampleCount = BitConverter.ToInt32( adSTSZ, 8 );
int [] SampleTable = new int[ SampleCount ];

for( int i = 0; i < SampleCount; i++ )
{
SampleTable[ i ] = BitConverter.ToInt32( adSTSZ, 12 + (i * 4) );
}

return SampleTable;
}

public void DeDRMS()
{
byte [] IV = new byte[ 16 ];
byte [] Key = new byte[ 16 ];

int apDRMS = GetAtomPos( AtomDRMS );
int apSINF = GetAtomPos( AtomSINF );
int apMDAT = GetAtomPos( AtomMDAT );

int [] SampleTable = GetSampleTable();

byte [] adUSER = GetAtomData( GetAtomPos( AtomUSER ), true );
byte [] adKEY = GetAtomData( GetAtomPos( AtomKEY ), true );
byte [] adIVIV = GetAtomData( GetAtomPos( AtomIVIV ), false );
byte [] adNAME = GetAtomData( GetAtomPos( AtomNAME ), false );
byte [] adPRIV = GetAtomData( GetAtomPos( AtomPRIV ), false );

uint UserID = BitConverter.ToUInt32( adUSER, 0 );
uint KeyID = BitConverter.ToUInt32( adKEY, 0 );
string strName = Encoding.ASCII.GetString( adNAME );
byte [] UserKey = GetUserKey( UserID, KeyID );

MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider();
MD5.TransformBlock( adNAME, 0, strName.IndexOf( '\0' ), adNAME, 0 );
MD5.TransformFinalBlock( adIVIV, 0, adIVIV.Length );

Decrypt( adPRIV, 0, adPRIV.Length, UserKey, MD5.Hash );

if( Encoding.ASCII.GetString( adPRIV, 0, 4 ) != "itun" )
{
throw new Exception( "Decryption of 'priv' atom failed" );
}

Buffer.BlockCopy( adPRIV, 24, Key, 0, Key.Length );
Buffer.BlockCopy( adPRIV, 48, IV, 0, IV.Length );

for( int i = 0, Pos = apMDAT + 4;
i < SampleTable.Length;
Pos += SampleTable[ i ], i++ )
{
Decrypt( sbuffer, Pos, SampleTable[ i ], Key, IV );
}

Encoding.ASCII.GetBytes( AtomMP4A ).CopyTo( sbuffer, apDRMS );
Encoding.ASCII.GetBytes( AtomSINF.ToUpper() ).CopyTo( sbuffer, apSINF );

bw.Seek( 0, SeekOrigin.Begin );
bw.Write( sbuffer );
}
}

class DeDRMS
{
public static void Main( string [] Args )
{
FileStream fs;
M4PStream m4p;

if( Args.Length != 1 )
{
Console.WriteLine( "Usage: DeDRMS file.m4p" );
return;
}

try
{
fs = new FileStream( Args[ 0 ], FileMode.Open,
FileAccess.Read | FileAccess.Write );
m4p = new M4PStream( fs );
m4p.DeDRMS();
fs.Close();
}
catch( Exception e )
{
Console.WriteLine( "Exception: {0}", e.Message );
return;
}
}
}


--------

Bookmark

0 TrackBacks

Listed below are links to blogs that reference this entry: right i don't know how.

TrackBack URL for this entry:

Leave a comment

Flickr Photo Stream

www.flickr.com

About this Entry

This page contains a single entry by Michael published on April 26, 2004 10:28 AM.

just got myself a Google was the previous entry in this blog.

right i don't know how is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Add to Technorati Favorites
Powered by Movable Type 4.1