2008-07-12 17:40:22 +00:00
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
# include <vector>
# include "AES/aes.h"
# include "VolumeCreator.h"
# include "Volume.h"
2008-09-23 00:05:08 +00:00
# include "VolumeDirectory.h"
2008-07-12 17:40:22 +00:00
# include "VolumeGC.h"
# include "VolumeWiiCrypted.h"
# include "Hash.h"
namespace DiscIO
{
enum EDiscType
{
DISC_TYPE_UNK ,
DISC_TYPE_WII ,
DISC_TYPE_WII_CONTAINER ,
DISC_TYPE_GC
} ;
2008-09-17 23:25:35 +00:00
2008-07-30 06:10:34 +00:00
# ifndef _WIN32
2008-09-17 23:25:35 +00:00
struct SPartition
{
u64 Offset ;
u32 Type ;
} ; //gcc 4.3 cries if it's local
2008-07-20 11:02:41 +00:00
# endif
2008-09-17 23:25:35 +00:00
2008-07-12 17:40:22 +00:00
class CBlobBigEndianReader
{
2008-09-17 23:25:35 +00:00
public :
CBlobBigEndianReader ( IBlobReader & _rReader ) : m_rReader ( _rReader ) { }
2008-07-12 17:40:22 +00:00
2008-09-17 23:25:35 +00:00
u32 Read32 ( u64 _Offset )
{
u32 Temp ;
m_rReader . Read ( _Offset , 4 , ( u8 * ) & Temp ) ;
return ( Common : : swap32 ( Temp ) ) ;
}
2008-07-12 17:40:22 +00:00
2008-09-17 23:25:35 +00:00
private :
IBlobReader & m_rReader ;
2008-07-12 17:40:22 +00:00
} ;
unsigned char g_MasterKey [ 16 ] ;
bool g_MasterKeyInit = false ;
2008-08-14 20:37:14 +00:00
IVolume * CreateVolumeFromCryptedWiiImage ( IBlobReader & _rReader , u32 _VolumeType ) ;
2008-07-12 17:40:22 +00:00
EDiscType GetDiscType ( IBlobReader & _rReader ) ;
IVolume * CreateVolumeFromFilename ( const std : : string & _rFilename )
{
IBlobReader * pReader = CreateBlobReader ( _rFilename . c_str ( ) ) ;
if ( pReader = = NULL )
2008-09-17 23:25:35 +00:00
return NULL ;
2008-07-12 17:40:22 +00:00
switch ( GetDiscType ( * pReader ) )
{
case DISC_TYPE_WII :
case DISC_TYPE_GC :
2008-09-24 19:10:56 +00:00
return new CVolumeGC ( pReader ) ;
2008-07-12 17:40:22 +00:00
case DISC_TYPE_WII_CONTAINER :
{
IVolume * pVolume = CreateVolumeFromCryptedWiiImage ( * pReader , 0 ) ;
if ( pVolume = = NULL )
{
delete pReader ;
}
return ( pVolume ) ;
}
break ;
case DISC_TYPE_UNK :
default :
delete pReader ;
2008-09-17 23:25:35 +00:00
return NULL ;
2008-07-12 17:40:22 +00:00
}
// unreachable code
2008-09-17 23:25:35 +00:00
return NULL ;
2008-07-12 17:40:22 +00:00
}
2008-09-23 00:05:08 +00:00
IVolume * CreateVolumeFromDirectory ( const std : : string & _rDirectory , bool _bIsWii )
{
2008-09-24 19:10:56 +00:00
if ( CVolumeDirectory : : IsValidDirectory ( _rDirectory ) )
2008-09-23 00:05:08 +00:00
return new CVolumeDirectory ( _rDirectory , _bIsWii ) ;
return NULL ;
}
2008-09-21 15:04:22 +00:00
bool IsVolumeWiiDisc ( const IVolume * _rVolume )
2008-07-12 17:40:22 +00:00
{
u32 MagicWord = 0 ;
2008-09-21 15:04:22 +00:00
_rVolume - > Read ( 0x18 , 4 , ( u8 * ) & MagicWord ) ;
2008-07-12 17:40:22 +00:00
2008-09-17 23:25:35 +00:00
return ( Common : : swap32 ( MagicWord ) = = 0x5D1C9EA3 ) ;
2008-07-12 17:40:22 +00:00
}
2008-08-14 20:37:14 +00:00
IVolume * CreateVolumeFromCryptedWiiImage ( IBlobReader & _rReader , u32 _VolumeType )
2008-07-12 17:40:22 +00:00
{
if ( ! g_MasterKeyInit )
{
2008-11-12 04:54:17 +00:00
FILE * pT = fopen ( WII_MASTERKEY_FILE , " rb " ) ;
2008-07-12 17:40:22 +00:00
if ( pT = = NULL )
{
2008-11-26 02:07:29 +00:00
PanicAlert ( " Can't open ' " WII_MASTERKEY_FILE " '. \n If you know the key, now it's the time to paste it into ' " WII_MASTERKEY_FILE_HEX " ' before pressing [OK]. " ) ;
pT = fopen ( WII_MASTERKEY_FILE_HEX , " r " ) ;
if ( pT = = NULL )
return NULL ;
static char hexkey [ 32 ] ;
if ( fread ( hexkey , 1 , 32 , pT ) < 32 )
{
fclose ( pT ) ;
return NULL ;
}
fclose ( pT ) ;
static char binkey [ 16 ] ;
char * t = hexkey ;
for ( int i = 0 ; i < 16 ; i + + )
{
char h [ 3 ] = { * ( t + + ) , * ( t + + ) , 0 } ;
binkey [ i ] = strtol ( h , NULL , 16 ) ;
}
pT = fopen ( WII_MASTERKEY_FILE , " wb " ) ;
if ( pT = = NULL )
return NULL ;
fwrite ( binkey , 16 , 1 , pT ) ;
fclose ( pT ) ;
pT = fopen ( WII_MASTERKEY_FILE , " rb " ) ;
if ( pT = = NULL )
return NULL ;
2008-07-12 17:40:22 +00:00
}
fread ( g_MasterKey , 16 , 1 , pT ) ;
fclose ( pT ) ;
const u32 keyhash = 0x4bc30936 ;
u32 hash = HashAdler32 ( g_MasterKey , 16 ) ;
if ( hash ! = keyhash )
PanicAlert ( " Your Wii disc decryption key is bad. " , keyhash , hash ) ;
else
g_MasterKeyInit = true ;
}
CBlobBigEndianReader Reader ( _rReader ) ;
u32 numPartitions = Reader . Read32 ( 0x40000 ) ;
u64 PartitionsOffset = ( u64 ) Reader . Read32 ( 0x40004 ) < < 2 ;
2008-07-30 06:10:34 +00:00
# ifdef _WIN32
2008-07-12 17:40:22 +00:00
struct SPartition
{
u64 Offset ;
u32 Type ;
} ;
2008-07-20 11:02:41 +00:00
# endif
2008-09-17 23:25:35 +00:00
std : : vector < SPartition > PartitionsVec ;
2008-07-30 06:10:34 +00:00
2008-07-12 17:40:22 +00:00
// read all partitions
for ( u32 i = 0 ; i < numPartitions ; i + + )
{
SPartition Partition ;
Partition . Offset = ( ( u64 ) Reader . Read32 ( PartitionsOffset + ( i * 8 ) + 0 ) ) < < 2 ;
Partition . Type = Reader . Read32 ( PartitionsOffset + ( i * 8 ) + 4 ) ;
PartitionsVec . push_back ( Partition ) ;
}
// find the partition with the game... type == 1 is prolly the firmware update partition
for ( size_t i = 0 ; i < PartitionsVec . size ( ) ; i + + )
{
const SPartition & rPartition = PartitionsVec [ i ] ;
if ( rPartition . Type = = _VolumeType )
{
u8 SubKey [ 16 ] ;
_rReader . Read ( rPartition . Offset + 0x1bf , 16 , SubKey ) ;
u8 IV [ 16 ] ;
memset ( IV , 0 , 16 ) ;
_rReader . Read ( rPartition . Offset + 0x44c , 8 , IV ) ;
AES_KEY AES_KEY ;
AES_set_decrypt_key ( g_MasterKey , 128 , & AES_KEY ) ;
u8 VolumeKey [ 16 ] ;
AES_cbc_encrypt ( SubKey , VolumeKey , 16 , & AES_KEY , IV , AES_DECRYPT ) ;
2008-09-17 23:25:35 +00:00
return new CVolumeWiiCrypted ( & _rReader , rPartition . Offset + 0x20000 , VolumeKey ) ;
2008-07-12 17:40:22 +00:00
}
}
2008-09-17 23:25:35 +00:00
return NULL ;
2008-07-12 17:40:22 +00:00
}
EDiscType GetDiscType ( IBlobReader & _rReader )
{
CBlobBigEndianReader Reader ( _rReader ) ;
// check for wii
{
u32 MagicWord = Reader . Read32 ( 0x18 ) ;
if ( MagicWord = = 0x5D1C9EA3 )
{
if ( Reader . Read32 ( 0x60 ) ! = 0 )
return ( DISC_TYPE_WII ) ;
else
return ( DISC_TYPE_WII_CONTAINER ) ;
}
}
// check for GC
{
u32 MagicWord = Reader . Read32 ( 0x1C ) ;
if ( MagicWord = = 0xC2339F3D )
return ( DISC_TYPE_GC ) ;
}
2008-09-17 23:25:35 +00:00
return DISC_TYPE_UNK ;
2008-07-12 17:40:22 +00:00
}
2008-09-17 23:25:35 +00:00
} // namespace