using System;
using System.Security.Cryptography;
using System.IO;
using System.Net;
using System.Threading;
using System.Timers;
namespace AES_Decrypter
{
class Program
{
static RijndaelManaged rijndaelCipher;
//static SHA1 sha = new SHA1CryptoServiceProvider();
static SHA256 sha = new SHA256Managed();
static Random rnd = new Random();
static RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
static byte[] buffer;
static int num_tried;
static long total_num;
static bool keepgoing;
static void Main(string[] args)
{
Console.WriteLine("[]-[]-[]-[]-[]-[]-[]-[] Basic DSi Bruteforce Application []-[]-[]-[]-[]-[]-[]-[]");
// Create all the constants/variables...
const string DSiNUSURL = "http://nus.cdn.t.shop.nintendowifi.net/ccs/download/";
byte[] contsha1 = new byte[40] { 0x10, 0xb2, 0x8d, 0x8e, 0xcb, 0xcc, 0x73, 0xbc, 0xef, 0x40, 0xb0, 0x24, 0x06, 0x1f, 0x4f, 0xd6, 0xb8, 0x14, 0xdf, 0x08, 0x10, 0xb2, 0x8d, 0x8e, 0xcb, 0xcc, 0x73, 0xbc, 0xef, 0x40, 0xb0, 0x24, 0x06, 0x1f, 0x4f, 0xd6, 0xb8, 0x14, 0xdf, 0x08 };
byte[] testkey = new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte[] titleIV = new byte[16] { 0x00, 0x03, 0x00, 0x0f, 0x48, 0x4e, 0x4c, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte[] contentIV = new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte[] enccontentsha = new byte[40] { 0xFC, 0x20, 0x32, 0x5F, 0x92, 0x96, 0x2A, 0x05, 0x5A, 0xF5, 0x5F, 0xD3, 0x27, 0x2D, 0xD2, 0x04, 0x3D, 0x8D, 0x37, 0xC7, 0xFC, 0x20, 0x32, 0x5F, 0x92, 0x96, 0x2A, 0x05, 0x5A, 0xF5, 0x5F, 0xD3, 0x27, 0x2D, 0xD2, 0x04, 0x3D, 0x8D, 0x37, 0xC7 };
byte[] decfirstbytes = new byte[16] { 0x17, 0xFC, 0xB6, 0xF1, 0x78, 0x4F, 0x8D, 0x1E, 0x93, 0xE2, 0x47, 0x4F, 0x9C, 0x5F, 0x0E, 0xC5 };
Console.WriteLine("Downloading files to decrypt...\n");
WebClient generalWC = new WebClient();
byte[] data = null;
try
{
FileStream localtitle = new FileStream(@"/00000000", FileMode.Open);
data = ReadFully(localtitle);
localtitle.Close();
}
catch
{
try
{
data = generalWC.DownloadData(DSiNUSURL + "0004800F484E4C41/00000000");
}
catch
{ }
}
finally
{
if (data == null)
{
// Fail
Console.WriteLine("Error: NUS 00000003 not found online or locally!");
Console.ReadLine();
Environment.Exit(0);
}
}
Console.WriteLine(" - Received: 00000003");
byte[] titlekeytemp = null;
try
{
FileStream localtitle = new FileStream(@"\cetk", FileMode.Open);
titlekeytemp = ReadFully(localtitle);
localtitle.Close();
}
catch
{
try
{
titlekeytemp = generalWC.DownloadData(DSiNUSURL + "0004800F484E4C41/cetk");
}
catch
{ }
}
finally
{
if (titlekeytemp == null)
{
// Fail
Console.WriteLine("Error: NUS ticket not found online or locally!");
Console.ReadLine();
Environment.Exit(0);
}
}
Console.WriteLine(" - Received: Ticket (cetk)");
byte[] tmd = null;
try
{
FileStream localtitle = new FileStream(@"\tmd", FileMode.Open);
tmd = ReadFully(localtitle);
localtitle.Close();
}
catch
{
try
{
tmd = generalWC.DownloadData(DSiNUSURL + "0004800F484E4C41/tmd");
}
catch
{ }
}
finally
{
if (tmd == null)
{
// Fail
Console.WriteLine("Error: NUS tmd not found online or locally!");
Console.ReadLine();
Environment.Exit(0);
}
}
Console.WriteLine(" - Received: Title metadata (TMD)\n");
// Load latest SHA-1 from TMD
for (int i = 0; i < 40; i++)
{
contsha1[i] = tmd[0xB14 + i];
}
Console.WriteLine("Detected SHA-1: ");
DisplayBytes(contsha1);
// Optimize. Do this to reduce conversion later...
string decstring = Convert.ToBase64String(decfirstbytes);
//contentIV[15] = tmd[0x1E9]; //ichfly only use ID 0
Console.WriteLine("\n\nUsing IV: ");
DisplayBytes(contentIV);
if (Convert.ToBase64String(sha.ComputeHash(data)) != Convert.ToBase64String(enccontentsha))
{
Console.WriteLine("NUS Content has changed. Notify author, although program should still work...");
Console.ReadLine();
//Environment.Exit(0);
}
/*Create all the constants...
const string DSiNUSURL = "http://nus.cdn.shop.wii.com/ccs/download/";
byte[] contsha1 = new byte[20] { 0x10, 0x14, 0x79, 0x94, 0xc3, 0xc5, 0x98, 0x10, 0x4f, 0x1d, 0xd8, 0xea, 0xea, 0xf6, 0xa1, 0xea, 0xdc, 0x85, 0xee, 0x44 };
byte[] testkey = new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte[] finikey = new byte[16] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
byte[] titleIV = new byte[16] { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
byte[] contentIV = new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Console.WriteLine("Downloading files to decrypt...\n");
WebClient generalWC = new WebClient();
byte[] data = generalWC.DownloadData(DSiNUSURL + "0000000100000010/00000002");
byte[] titlekeytemp = generalWC.DownloadData(DSiNUSURL + "0000000100000010/cetk");*/
// Get the Title Key from cetk...
byte[] titlekeyenc = new byte[16];
for (int i = 0; i < 0x10; i++)
{
titlekeyenc[i] = titlekeytemp[0x1BF + i];
}
Console.WriteLine("\n\nEncrypted Title Key of 03 Content...");
DisplayBytes(titlekeyenc);
// Take in any hex codes as parameters...
for (int i = 0; i < args.Length; i++)
{
testkey[i] = byte.Parse(args[i], System.Globalization.NumberStyles.HexNumber);
}
if (args.Length >= 1)
{
Console.WriteLine("\n\nCurrent starting point...");
DisplayBytes(testkey);
}
// Set 'mode' based on input...
Console.WriteLine("\n\nMode:");
Console.WriteLine(" [1] Standard");
Console.WriteLine(" [2] 'Secure' Random");
Console.WriteLine(" [3] '1' Bit Mode");
Console.WriteLine("\nObsolete Modes:");
Console.WriteLine(" [4] Standard Random");
Console.WriteLine(" [D] Debug Mode");
Console.WriteLine("\nSelect a mode: ");
int mode = 0;
System.ConsoleKeyInfo cks = Console.ReadKey(true);
if (cks.KeyChar == '1')
mode = 1;
else if (cks.KeyChar == '2')
mode = 2;
else if (cks.KeyChar == '3')
mode = 3;
else if (cks.KeyChar == '4')
mode = 4;
else if (cks.KeyChar == 'D')
mode = 9;
else
mode = 3;
// AES stuff
// This is for decryting title key from test common keys
// Cipher1 decrypts the Title Key with random common key
rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.None;
rijndaelCipher.KeySize = 128;
rijndaelCipher.BlockSize = 128;
rijndaelCipher.IV = titleIV;
// Cipher2 decrypts the contents using the new TitleKey
RijndaelManaged finaldecrypter;
finaldecrypter = new RijndaelManaged();
finaldecrypter.Mode = CipherMode.CBC;
finaldecrypter.Padding = PaddingMode.None;
finaldecrypter.KeySize = 128;
finaldecrypter.BlockSize = 128;
finaldecrypter.IV = contentIV;
// Fun facts on how long it took...
long timeinms = DateTime.UtcNow.Ticks;
long timeinft = 0;
num_tried = 0;
total_num = 0;
// Optimization? lol
buffer = new byte[6992];
// Every 1 second, show info...
System.Timers.Timer t = new System.Timers.Timer(1000);
t.Elapsed += new ElapsedEventHandler(TimerTicked);
t.Start();
// wow
keepgoing = true;
// Small part of decrypted file...
byte[] encsmall = new byte[16];
for (int i = 0; i < 16; i++)
{
encsmall[i] = data[i];
}
while (keepgoing)
{
// Set the Title Key decrypter to the random test key...
rijndaelCipher.Key = testkey;
// The new key is the decrypted title key by test ckey...
finaldecrypter.Key = Decrypt(titlekeyenc, rijndaelCipher);
// If the miraculous SHA-1 should match...
if (Convert.ToBase64String(Decrypt(encsmall, finaldecrypter)) == decstring)
{
// Common Key is written to console...
Console.WriteLine("Common Key: ");
DisplayBytes(testkey);
Console.WriteLine("Title Key: ");
DisplayBytes(Decrypt(titlekeyenc, rijndaelCipher));
WriteFoundKey(testkey);
Console.WriteLine("\nKey written to /dsikey.bin. DO NOT CLOSE THIS UNTIL YOU CAN VERIFY FILE INTEGRITY.");
Console.WriteLine("\n");
Console.WriteLine("Verifying entire file...");
if (Convert.ToBase64String(sha.ComputeHash(Decrypt(data, finaldecrypter))) == Convert.ToBase64String(contsha1))
Console.WriteLine("SHA-1 test matches :D");
else
Console.WriteLine("SHA-1 failed, still SOMETHING happened :|");
num_tried = 0;
keepgoing = false;
}
// Depending on mode, increment or randomize the test key...
if (mode == 1)
testkey = incrementAtIndex(testkey, 15);
else if (mode == 2)
testkey = SecureRandomize();
else if (mode == 3)
{
testkey = SecureRandomize();
testkey[0] = SetBit(testkey[0], 7, true);
}
else if (mode == 9)
{
Console.WriteLine("\nCurrent COMMON KEY: ");
DisplayBytes(testkey);
Console.WriteLine("\nCurrent TITLE KEY: ");
DisplayBytes(finaldecrypter.Key);
Console.WriteLine("\nThis SHA-1: ");
DisplayBytes(sha.ComputeHash(Decrypt(data, finaldecrypter)));
Console.WriteLine("\nOfficial SHA-1: ");
DisplayBytes(contsha1);
Console.WriteLine("\nEncrypted Chunk: ");
DisplayBytes(encsmall);
Console.WriteLine("\nDecrypted Chunk: ");
DisplayBytes(Decrypt(encsmall, finaldecrypter));
//WriteFoundKey(testkey);
Console.ReadLine();
testkey = SecureRandomize();
testkey[0] = SetBit(testkey[0], 7, true);
}
else if (mode == 4)
testkey = PlainRandomize();
if (mode != 9)
{
num_tried += 1;
total_num += 1;
}
}
// Somehow it worked, so get the new time now...
timeinft = DateTime.UtcNow.Ticks;
// ... and write Done with the total time elapsed...
t.Dispose();
Console.WriteLine("\nDone - " + (timeinft - timeinms) + " Operation");
Console.ReadLine();
Console.ReadLine();
Console.ReadLine();
Console.ReadLine();
}
public static byte[] Decrypt(byte[] encryptedData, RijndaelManaged decrypter)
{
//ICryptoTransform transform = rijndaelCipher.CreateDecryptor();
ICryptoTransform transform = decrypter.CreateDecryptor();
using (MemoryStream ms = new MemoryStream(encryptedData))
{
using (CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Read))
{
return ReadFully(cs);
}
}
}
public static byte[] ReadFully(Stream stream)
{
buffer = new byte[6992];
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0)
return ms.ToArray();
ms.Write(buffer, 0, read);
}
}
}
static void DisplayBytes(byte[] bytes)
{
for (int i = 0; i < bytes.Length; ++i)
{
Console.Write(bytes[i].ToString("X2") + " ");
//Console.Write(bytes[i].ToString("x4") + " ");
//if (i > 0 && i % 16 == 0) Console.Write("\n");
}
//Console.WriteLine("");
}
static public byte[] incrementAtIndex(byte[] array, int index)
{
if (array[index] == byte.MaxValue)
{
array[index] = 0;
if (index > 0)
incrementAtIndex(array, index - 1);
}
else
{
array[index]++;
}
return array;
}
static public byte[] PlainRandomize()
{
//Create random byte array
byte[] randomArray = new byte[16];
// Use 'secure' / regular randomization.
rnd.NextBytes(randomArray);
return randomArray;
}
static public byte[] SecureRandomize()
{
//Create random byte array
byte[] randomArray = new byte[16];
// Use 'secure' / regular randomization.
rng.GetNonZeroBytes(randomArray);
return randomArray;
}
static public void WriteFoundKey(byte[] ckey)
{
try
{
//Console.WriteLine("Writing to file...");
//DisplayBytes(ckey);
FileStream ckeystr = new FileStream(@"/dsikey.bin", FileMode.OpenOrCreate);
ckeystr.Write(ckey, 0, 16);
ckeystr.Close();
}
catch
{
//throw;
}
}
private static bool GetBit(byte b, byte position)
{
return ((b & (byte)(1 << position)) != 0);
}
private static byte SetBit(byte b, byte position, bool newBitValue)
{
byte mask = (byte)(1 << position);
if (newBitValue)
{
return (byte)(b | mask);
}
else
{
return (byte)(b & ~mask);
}
}
private static void TimerTicked(object sender, ElapsedEventArgs e)
{
if (num_tried != 0)
{
Console.Clear();
Console.WriteLine(num_tried + " Keys p/s. (Total: " + total_num + ")");
num_tried = 0;
}
}
}
}