mirror of
https://github.com/StudentBlake/XCI-Explorer
synced 2024-11-22 04:03:04 +00:00
Minor cleanup, update keys, add portable publish profile
This commit is contained in:
parent
a328030ff6
commit
2370bc6cf4
23 changed files with 2721 additions and 2901 deletions
|
@ -15,4 +15,10 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Be.Windows.Forms.HexBox.Net5" Version="1.8.0" />
|
<PackageReference Include="Be.Windows.Forms.HexBox.Net5" Version="1.8.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="tools\hactool.exe">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -1,154 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace XCI_Explorer.Helpers
|
|
||||||
{
|
|
||||||
public class BetterBinaryReader : IDisposable
|
|
||||||
{
|
|
||||||
public string FileName;
|
|
||||||
public bool Initiated;
|
|
||||||
public Stream Stream;
|
|
||||||
private BinaryReader br;
|
|
||||||
|
|
||||||
public BetterBinaryReader()
|
|
||||||
{
|
|
||||||
Initiated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BetterBinaryReader(string file)
|
|
||||||
{
|
|
||||||
Initiated = false;
|
|
||||||
Load(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BetterBinaryReader(Stream s)
|
|
||||||
{
|
|
||||||
Initiated = false;
|
|
||||||
FileName = "";
|
|
||||||
Stream = s;
|
|
||||||
br = new BinaryReader(Stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Initiated = false;
|
|
||||||
br.Close();
|
|
||||||
br = null;
|
|
||||||
Stream.Close();
|
|
||||||
Stream = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Load(string file)
|
|
||||||
{
|
|
||||||
FileName = file;
|
|
||||||
Stream = new FileStream(file, FileMode.Open);
|
|
||||||
br = new BinaryReader(Stream);
|
|
||||||
Initiated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Seek(long o)
|
|
||||||
{
|
|
||||||
if (o > -1)
|
|
||||||
{
|
|
||||||
Stream.Seek(o, SeekOrigin.Begin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Skip(long o)
|
|
||||||
{
|
|
||||||
Stream.Seek(o, SeekOrigin.Current);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long Position()
|
|
||||||
{
|
|
||||||
return Stream.Position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Read()
|
|
||||||
{
|
|
||||||
return br.ReadBytes(1)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Read(byte[] buffer, int index, int count)
|
|
||||||
{
|
|
||||||
return br.Read(buffer, index, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Read(char[] buffer, int index, int count)
|
|
||||||
{
|
|
||||||
return br.Read(buffer, index, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] ReadBytes(int l)
|
|
||||||
{
|
|
||||||
if (l >= 0 && l <= 2147483647)
|
|
||||||
{
|
|
||||||
return br.ReadBytes(l);
|
|
||||||
}
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stream ReadBytesButLonger(long l)
|
|
||||||
{
|
|
||||||
MemoryStream memoryStream = new MemoryStream();
|
|
||||||
for (long num = 0L; num < l; num++)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Console.WriteLine(memoryStream.Length);
|
|
||||||
return memoryStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ReadCharsAsString(int l)
|
|
||||||
{
|
|
||||||
return new string(br.ReadChars(l));
|
|
||||||
}
|
|
||||||
|
|
||||||
public short ReadShort()
|
|
||||||
{
|
|
||||||
return br.ReadInt16();
|
|
||||||
}
|
|
||||||
|
|
||||||
public short ReadInt16()
|
|
||||||
{
|
|
||||||
return br.ReadInt16();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ReadInt()
|
|
||||||
{
|
|
||||||
return br.ReadInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ReadInt32()
|
|
||||||
{
|
|
||||||
return br.ReadInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long ReadLong()
|
|
||||||
{
|
|
||||||
return br.ReadInt64();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long ReadInt64()
|
|
||||||
{
|
|
||||||
return br.ReadInt64();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ReadString()
|
|
||||||
{
|
|
||||||
return br.ReadString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private long GreatestDivisor(long n)
|
|
||||||
{
|
|
||||||
long result = 0L;
|
|
||||||
for (long num = 1L; num < n / 64; num++)
|
|
||||||
{
|
|
||||||
if (n % num == 0L && num != n)
|
|
||||||
{
|
|
||||||
result = num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +1,17 @@
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace XCI_Explorer.Helpers
|
namespace XCI_Explorer.Helpers;
|
||||||
{
|
|
||||||
public class BetterTreeNode : TreeNode
|
|
||||||
{
|
|
||||||
public long Offset;
|
|
||||||
public long Size;
|
|
||||||
public string ExpectedHash;
|
|
||||||
public string ActualHash;
|
|
||||||
public long HashedRegionSize;
|
|
||||||
|
|
||||||
public BetterTreeNode(string t)
|
public class BetterTreeNode : TreeNode
|
||||||
{
|
{
|
||||||
base.Text = t;
|
public long Offset;
|
||||||
}
|
public long Size;
|
||||||
|
public string ExpectedHash;
|
||||||
|
public string ActualHash;
|
||||||
|
public long HashedRegionSize;
|
||||||
|
|
||||||
|
public BetterTreeNode(string t)
|
||||||
|
{
|
||||||
|
Text = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,80 +1,79 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
|
|
||||||
|
internal static class CNMT
|
||||||
{
|
{
|
||||||
internal static class CNMT
|
public class CNMT_Header
|
||||||
{
|
{
|
||||||
public class CNMT_Header
|
public byte[] Data;
|
||||||
|
public long TitleID;
|
||||||
|
public int TitleVersion;
|
||||||
|
public byte Type;
|
||||||
|
public byte Reserved1;
|
||||||
|
public short Offset;
|
||||||
|
public short ContentCount;
|
||||||
|
public short MetaCount;
|
||||||
|
public byte[] Reserved2;
|
||||||
|
|
||||||
|
public enum TitleType
|
||||||
{
|
{
|
||||||
public byte[] Data;
|
SYSTEM_PROGRAMS = 0x01,
|
||||||
public long TitleID;
|
SYSTEM_DATA_ARCHIVES,
|
||||||
public int TitleVersion;
|
SYSTEM_UPDATE,
|
||||||
public byte Type;
|
FIRMWARE_PACKAGE_A,
|
||||||
public byte Reserved1;
|
FIRMWARE_PACKAGE_B,
|
||||||
public short Offset;
|
REGULAR_APPLICATION = 0x80,
|
||||||
public short ContentCount;
|
UPDATE_TITLE,
|
||||||
public short MetaCount;
|
ADD_ON_CONTENT,
|
||||||
public byte[] Reserved2;
|
DELTA_TITLE
|
||||||
|
|
||||||
public enum TitleType
|
|
||||||
{
|
|
||||||
SYSTEM_PROGRAMS = 0x01,
|
|
||||||
SYSTEM_DATA_ARCHIVES,
|
|
||||||
SYSTEM_UPDATE,
|
|
||||||
FIRMWARE_PACKAGE_A,
|
|
||||||
FIRMWARE_PACKAGE_B,
|
|
||||||
REGULAR_APPLICATION = 0x80,
|
|
||||||
UPDATE_TITLE,
|
|
||||||
ADD_ON_CONTENT,
|
|
||||||
DELTA_TITLE
|
|
||||||
}
|
|
||||||
|
|
||||||
public CNMT_Header(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
TitleID = BitConverter.ToInt64(data, 0);
|
|
||||||
TitleVersion = BitConverter.ToInt32(data, 8);
|
|
||||||
Type = Data[12];
|
|
||||||
Reserved1 = Data[13];
|
|
||||||
Offset = BitConverter.ToInt16(data, 14);
|
|
||||||
ContentCount = BitConverter.ToInt16(data, 16);
|
|
||||||
MetaCount = BitConverter.ToInt16(data, 16);
|
|
||||||
Reserved2 = Data.Skip(20).Take(12).ToArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CNMT_Entry
|
public CNMT_Header(byte[] data)
|
||||||
{
|
{
|
||||||
public byte[] Data;
|
Data = data;
|
||||||
public byte[] Hash;
|
TitleID = BitConverter.ToInt64(data, 0);
|
||||||
public byte[] NcaId;
|
TitleVersion = BitConverter.ToInt32(data, 8);
|
||||||
public long Size;
|
Type = Data[12];
|
||||||
public byte Type;
|
Reserved1 = Data[13];
|
||||||
public byte Reserved;
|
Offset = BitConverter.ToInt16(data, 14);
|
||||||
|
ContentCount = BitConverter.ToInt16(data, 16);
|
||||||
public enum ContentType
|
MetaCount = BitConverter.ToInt16(data, 16);
|
||||||
{
|
Reserved2 = Data.Skip(20).Take(12).ToArray();
|
||||||
META,
|
|
||||||
PROGRAM,
|
|
||||||
DATA,
|
|
||||||
CONTROL,
|
|
||||||
OFFLINE_MANUAL,
|
|
||||||
LEGAL,
|
|
||||||
GAME_UPDATE
|
|
||||||
}
|
|
||||||
|
|
||||||
public CNMT_Entry(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Hash = Data.Skip(0).Take(32).ToArray();
|
|
||||||
NcaId = Data.Skip(32).Take(16).ToArray();
|
|
||||||
Size = BitConverter.ToInt32(data, 48) + BitConverter.ToInt16(data, 52) * 65536;
|
|
||||||
Type = Data[54];
|
|
||||||
Reserved = Data[55];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CNMT_Header[] CNMT_Headers = new CNMT_Header[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CNMT_Entry
|
||||||
|
{
|
||||||
|
public byte[] Data;
|
||||||
|
public byte[] Hash;
|
||||||
|
public byte[] NcaId;
|
||||||
|
public long Size;
|
||||||
|
public byte Type;
|
||||||
|
public byte Reserved;
|
||||||
|
|
||||||
|
public enum ContentType
|
||||||
|
{
|
||||||
|
META,
|
||||||
|
PROGRAM,
|
||||||
|
DATA,
|
||||||
|
CONTROL,
|
||||||
|
OFFLINE_MANUAL,
|
||||||
|
LEGAL,
|
||||||
|
GAME_UPDATE
|
||||||
|
}
|
||||||
|
|
||||||
|
public CNMT_Entry(byte[] data)
|
||||||
|
{
|
||||||
|
Data = data;
|
||||||
|
Hash = Data.Skip(0).Take(32).ToArray();
|
||||||
|
NcaId = Data.Skip(32).Take(16).ToArray();
|
||||||
|
Size = BitConverter.ToInt32(data, 48) + BitConverter.ToInt16(data, 52) * 65536;
|
||||||
|
Type = Data[54];
|
||||||
|
Reserved = Data[55];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CNMT_Header[] CNMT_Headers = new CNMT_Header[1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,69 +1,77 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Windows.Forms;
|
|
||||||
using System.Text;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
|
|
||||||
|
public class CenterWinDialog : IDisposable
|
||||||
{
|
{
|
||||||
public class CenterWinDialog : IDisposable
|
private int mTries = 0;
|
||||||
|
private Form mOwner;
|
||||||
|
|
||||||
|
public CenterWinDialog(Form owner)
|
||||||
{
|
{
|
||||||
private int mTries = 0;
|
mOwner = owner;
|
||||||
private Form mOwner;
|
if (owner.WindowState != FormWindowState.Minimized)
|
||||||
|
|
||||||
public CenterWinDialog(Form owner)
|
|
||||||
{
|
{
|
||||||
mOwner = owner;
|
owner.BeginInvoke(new MethodInvoker(findDialog));
|
||||||
if (owner.WindowState != FormWindowState.Minimized)
|
|
||||||
{
|
|
||||||
owner.BeginInvoke(new MethodInvoker(findDialog));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findDialog()
|
|
||||||
{
|
|
||||||
// Enumerate windows to find the message box
|
|
||||||
if (mTries < 0) return;
|
|
||||||
EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
|
|
||||||
if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero))
|
|
||||||
{
|
|
||||||
if (++mTries < 10) mOwner.BeginInvoke(new MethodInvoker(findDialog));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private bool checkWindow(IntPtr hWnd, IntPtr lp)
|
|
||||||
{
|
|
||||||
// Checks if <hWnd> is a dialog
|
|
||||||
StringBuilder sb = new StringBuilder(260);
|
|
||||||
GetClassName(hWnd, sb, sb.Capacity);
|
|
||||||
if (sb.ToString() != "#32770") return true;
|
|
||||||
// Got it
|
|
||||||
Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
|
|
||||||
RECT dlgRect;
|
|
||||||
GetWindowRect(hWnd, out dlgRect);
|
|
||||||
MoveWindow(hWnd,
|
|
||||||
frmRect.Left + (frmRect.Width - dlgRect.Right + dlgRect.Left) / 2,
|
|
||||||
frmRect.Top + (frmRect.Height - dlgRect.Bottom + dlgRect.Top) / 2,
|
|
||||||
dlgRect.Right - dlgRect.Left,
|
|
||||||
dlgRect.Bottom - dlgRect.Top, true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
mTries = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// P/Invoke declarations
|
|
||||||
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
|
|
||||||
[DllImport("kernel32.dll")]
|
|
||||||
private static extern int GetCurrentThreadId();
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
|
|
||||||
private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void findDialog()
|
||||||
|
{
|
||||||
|
// Enumerate windows to find the message box
|
||||||
|
if (mTries < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EnumThreadWndProc callback = new(checkWindow);
|
||||||
|
if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero))
|
||||||
|
{
|
||||||
|
if (++mTries < 10)
|
||||||
|
{
|
||||||
|
mOwner.BeginInvoke(new MethodInvoker(findDialog));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool checkWindow(IntPtr hWnd, IntPtr lp)
|
||||||
|
{
|
||||||
|
// Checks if <hWnd> is a dialog
|
||||||
|
StringBuilder sb = new(260);
|
||||||
|
GetClassName(hWnd, sb, sb.Capacity);
|
||||||
|
if (sb.ToString() != "#32770")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Got it
|
||||||
|
Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
|
||||||
|
RECT dlgRect;
|
||||||
|
GetWindowRect(hWnd, out dlgRect);
|
||||||
|
MoveWindow(hWnd,
|
||||||
|
frmRect.Left + (frmRect.Width - dlgRect.Right + dlgRect.Left) / 2,
|
||||||
|
frmRect.Top + (frmRect.Height - dlgRect.Bottom + dlgRect.Top) / 2,
|
||||||
|
dlgRect.Right - dlgRect.Left,
|
||||||
|
dlgRect.Bottom - dlgRect.Top, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
mTries = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// P/Invoke declarations
|
||||||
|
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern int GetCurrentThreadId();
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
|
||||||
|
private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
|
||||||
}
|
}
|
|
@ -2,19 +2,18 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
|
|
||||||
|
public partial class CertForm : Form
|
||||||
{
|
{
|
||||||
public partial class CertForm : Form
|
public CertForm(MainForm mainForm)
|
||||||
{
|
{
|
||||||
public CertForm(MainForm mainForm)
|
InitializeComponent();
|
||||||
{
|
FileStream fileStream = new(mainForm.TB_File.Text, FileMode.Open, FileAccess.Read);
|
||||||
InitializeComponent();
|
byte[] array = new byte[512];
|
||||||
FileStream fileStream = new FileStream(mainForm.TB_File.Text, FileMode.Open, FileAccess.Read);
|
fileStream.Position = 28672L;
|
||||||
byte[] array = new byte[512];
|
fileStream.Read(array, 0, 512);
|
||||||
fileStream.Position = 28672L;
|
hbxHexView.ByteProvider = new DynamicByteProvider(array);
|
||||||
fileStream.Read(array, 0, 512);
|
fileStream.Close();
|
||||||
hbxHexView.ByteProvider = new DynamicByteProvider(array);
|
|
||||||
fileStream.Close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,51 +2,50 @@ using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
|
|
||||||
|
internal static class HFS0
|
||||||
{
|
{
|
||||||
internal static class HFS0
|
public class HFS0_Header
|
||||||
{
|
{
|
||||||
public class HFS0_Header
|
public byte[] Data;
|
||||||
|
public string Magic;
|
||||||
|
public int FileCount;
|
||||||
|
public int StringTableSize;
|
||||||
|
public int Reserved;
|
||||||
|
|
||||||
|
public HFS0_Header(byte[] data)
|
||||||
{
|
{
|
||||||
public byte[] Data;
|
Data = data;
|
||||||
public string Magic;
|
Magic = Encoding.UTF8.GetString(Data.Take(4).ToArray());
|
||||||
public int FileCount;
|
FileCount = BitConverter.ToInt32(data, 4);
|
||||||
public int StringTableSize;
|
StringTableSize = BitConverter.ToInt32(data, 8);
|
||||||
public int Reserved;
|
Reserved = BitConverter.ToInt32(data, 12);
|
||||||
|
|
||||||
public HFS0_Header(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Magic = Encoding.UTF8.GetString(Data.Take(4).ToArray());
|
|
||||||
FileCount = BitConverter.ToInt32(data, 4);
|
|
||||||
StringTableSize = BitConverter.ToInt32(data, 8);
|
|
||||||
Reserved = BitConverter.ToInt32(data, 12);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HSF0_Entry
|
|
||||||
{
|
|
||||||
public byte[] Data;
|
|
||||||
public long Offset;
|
|
||||||
public long Size;
|
|
||||||
public int Name_ptr;
|
|
||||||
public int HashedRegionSize;
|
|
||||||
public long Padding;
|
|
||||||
public byte[] Hash;
|
|
||||||
public string Name;
|
|
||||||
|
|
||||||
public HSF0_Entry(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Offset = BitConverter.ToInt64(data, 0);
|
|
||||||
Size = BitConverter.ToInt64(data, 8);
|
|
||||||
Name_ptr = BitConverter.ToInt32(data, 16);
|
|
||||||
HashedRegionSize = BitConverter.ToInt32(data, 20);
|
|
||||||
Padding = BitConverter.ToInt64(data, 24);
|
|
||||||
Hash = Data.Skip(32).Take(32).ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HFS0_Header[] HFS0_Headers = new HFS0_Header[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class HSF0_Entry
|
||||||
|
{
|
||||||
|
public byte[] Data;
|
||||||
|
public long Offset;
|
||||||
|
public long Size;
|
||||||
|
public int Name_ptr;
|
||||||
|
public int HashedRegionSize;
|
||||||
|
public long Padding;
|
||||||
|
public byte[] Hash;
|
||||||
|
public string Name;
|
||||||
|
|
||||||
|
public HSF0_Entry(byte[] data)
|
||||||
|
{
|
||||||
|
Data = data;
|
||||||
|
Offset = BitConverter.ToInt64(data, 0);
|
||||||
|
Size = BitConverter.ToInt64(data, 8);
|
||||||
|
Name_ptr = BitConverter.ToInt32(data, 16);
|
||||||
|
HashedRegionSize = BitConverter.ToInt32(data, 20);
|
||||||
|
Padding = BitConverter.ToInt64(data, 24);
|
||||||
|
Hash = Data.Skip(32).Take(32).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HFS0_Header[] HFS0_Headers = new HFS0_Header[1];
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,42 +1,41 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
|
|
||||||
|
public static class NACP
|
||||||
{
|
{
|
||||||
public static class NACP
|
public class NACP_String
|
||||||
{
|
{
|
||||||
public class NACP_String
|
public byte[] Data;
|
||||||
|
public byte Check;
|
||||||
|
public string GameName;
|
||||||
|
public string GameAuthor;
|
||||||
|
|
||||||
|
public NACP_String(byte[] data)
|
||||||
{
|
{
|
||||||
public byte[] Data;
|
Data = data;
|
||||||
public byte Check;
|
Check = Data[0];
|
||||||
public string GameName;
|
GameName = Encoding.UTF8.GetString(Data.Take(512).ToArray());
|
||||||
public string GameAuthor;
|
GameAuthor = Encoding.UTF8.GetString(Data.Skip(512).Take(256).ToArray());
|
||||||
|
|
||||||
public NACP_String(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Check = Data[0];
|
|
||||||
GameName = Encoding.UTF8.GetString(Data.Take(512).ToArray());
|
|
||||||
GameAuthor = Encoding.UTF8.GetString(Data.Skip(512).Take(256).ToArray());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NACP_Data
|
|
||||||
{
|
|
||||||
public byte[] Data;
|
|
||||||
public string GameVer;
|
|
||||||
public string GameProd;
|
|
||||||
|
|
||||||
public NACP_Data(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
GameVer = Encoding.UTF8.GetString(Data.Skip(0x60).Take(16).ToArray());
|
|
||||||
GameProd = Encoding.UTF8.GetString(Data.Skip(0xA8).Take(8).ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NACP_String[] NACP_Strings = new NACP_String[16];
|
|
||||||
|
|
||||||
public static NACP_Data[] NACP_Datas = new NACP_Data[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NACP_Data
|
||||||
|
{
|
||||||
|
public byte[] Data;
|
||||||
|
public string GameVer;
|
||||||
|
public string GameProd;
|
||||||
|
|
||||||
|
public NACP_Data(byte[] data)
|
||||||
|
{
|
||||||
|
Data = data;
|
||||||
|
GameVer = Encoding.UTF8.GetString(Data.Skip(0x60).Take(16).ToArray());
|
||||||
|
GameProd = Encoding.UTF8.GetString(Data.Skip(0xA8).Take(8).ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NACP_String[] NACP_Strings = new NACP_String[16];
|
||||||
|
|
||||||
|
public static NACP_Data[] NACP_Datas = new NACP_Data[1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,34 +2,33 @@ using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
|
|
||||||
|
internal static class NCA
|
||||||
{
|
{
|
||||||
internal static class NCA
|
public class NCA_Header
|
||||||
{
|
{
|
||||||
public class NCA_Header
|
public byte[] Data;
|
||||||
|
public string Magic;
|
||||||
|
public long TitleID;
|
||||||
|
public byte SDKVersion1;
|
||||||
|
public byte SDKVersion2;
|
||||||
|
public byte SDKVersion3;
|
||||||
|
public byte SDKVersion4;
|
||||||
|
public byte MasterKeyRev;
|
||||||
|
|
||||||
|
public NCA_Header(byte[] data)
|
||||||
{
|
{
|
||||||
public byte[] Data;
|
Data = data;
|
||||||
public string Magic;
|
Magic = Encoding.UTF8.GetString(Data.Skip(512).Take(4).ToArray());
|
||||||
public long TitleID;
|
TitleID = BitConverter.ToInt64(data, 528);
|
||||||
public byte SDKVersion1;
|
SDKVersion1 = Data[540];
|
||||||
public byte SDKVersion2;
|
SDKVersion2 = Data[541];
|
||||||
public byte SDKVersion3;
|
SDKVersion3 = Data[542];
|
||||||
public byte SDKVersion4;
|
SDKVersion4 = Data[543];
|
||||||
public byte MasterKeyRev;
|
MasterKeyRev = Data[544];
|
||||||
|
|
||||||
public NCA_Header(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Magic = Encoding.UTF8.GetString(Data.Skip(512).Take(4).ToArray());
|
|
||||||
TitleID = BitConverter.ToInt64(data, 528);
|
|
||||||
SDKVersion1 = Data[540];
|
|
||||||
SDKVersion2 = Data[541];
|
|
||||||
SDKVersion3 = Data[542];
|
|
||||||
SDKVersion4 = Data[543];
|
|
||||||
MasterKeyRev = Data[544];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NCA_Header[] NCA_Headers = new NCA_Header[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static NCA_Header[] NCA_Headers = new NCA_Header[1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,47 +2,46 @@ using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
|
|
||||||
|
internal static class PFS0
|
||||||
{
|
{
|
||||||
internal static class PFS0
|
public class PFS0_Header
|
||||||
{
|
{
|
||||||
public class PFS0_Header
|
public byte[] Data;
|
||||||
|
public string Magic;
|
||||||
|
public int FileCount;
|
||||||
|
public int StringTableSize;
|
||||||
|
public int Reserved;
|
||||||
|
|
||||||
|
public PFS0_Header(byte[] data)
|
||||||
{
|
{
|
||||||
public byte[] Data;
|
Data = data;
|
||||||
public string Magic;
|
Magic = Encoding.UTF8.GetString(Data.Take(4).ToArray());
|
||||||
public int FileCount;
|
FileCount = BitConverter.ToInt32(data, 4);
|
||||||
public int StringTableSize;
|
StringTableSize = BitConverter.ToInt32(data, 8);
|
||||||
public int Reserved;
|
Reserved = BitConverter.ToInt32(data, 12);
|
||||||
|
|
||||||
public PFS0_Header(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Magic = Encoding.UTF8.GetString(Data.Take(4).ToArray());
|
|
||||||
FileCount = BitConverter.ToInt32(data, 4);
|
|
||||||
StringTableSize = BitConverter.ToInt32(data, 8);
|
|
||||||
Reserved = BitConverter.ToInt32(data, 12);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PFS0_Entry
|
|
||||||
{
|
|
||||||
public byte[] Data;
|
|
||||||
public long Offset;
|
|
||||||
public long Size;
|
|
||||||
public int Name_ptr;
|
|
||||||
public int Reserved;
|
|
||||||
public string Name;
|
|
||||||
|
|
||||||
public PFS0_Entry(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Offset = BitConverter.ToInt64(data, 0);
|
|
||||||
Size = BitConverter.ToInt64(data, 8);
|
|
||||||
Name_ptr = BitConverter.ToInt32(data, 16);
|
|
||||||
Reserved = BitConverter.ToInt32(data, 20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PFS0_Header[] PFS0_Headers = new PFS0_Header[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PFS0_Entry
|
||||||
|
{
|
||||||
|
public byte[] Data;
|
||||||
|
public long Offset;
|
||||||
|
public long Size;
|
||||||
|
public int Name_ptr;
|
||||||
|
public int Reserved;
|
||||||
|
public string Name;
|
||||||
|
|
||||||
|
public PFS0_Entry(byte[] data)
|
||||||
|
{
|
||||||
|
Data = data;
|
||||||
|
Offset = BitConverter.ToInt64(data, 0);
|
||||||
|
Size = BitConverter.ToInt64(data, 8);
|
||||||
|
Name_ptr = BitConverter.ToInt32(data, 16);
|
||||||
|
Reserved = BitConverter.ToInt32(data, 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PFS0_Header[] PFS0_Headers = new PFS0_Header[1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,26 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
{
|
|
||||||
internal static class Program
|
|
||||||
{
|
|
||||||
[STAThread]
|
|
||||||
private static void Main()
|
|
||||||
{
|
|
||||||
AppDomain.CurrentDomain.AssemblyResolve += (Object sender, ResolveEventArgs args) =>
|
|
||||||
{
|
|
||||||
System.Reflection.AssemblyName embeddedAssembly = new System.Reflection.AssemblyName(args.Name);
|
|
||||||
String resourceName = "XCI_Explorer" + "." + embeddedAssembly.Name + ".dll";
|
|
||||||
|
|
||||||
using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
|
internal static class Program
|
||||||
{
|
{
|
||||||
Byte[] assemblyData = new Byte[stream.Length];
|
[STAThread]
|
||||||
stream.Read(assemblyData, 0, assemblyData.Length);
|
private static void Main()
|
||||||
return System.Reflection.Assembly.Load(assemblyData);
|
{
|
||||||
}
|
AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs args) =>
|
||||||
};
|
{
|
||||||
Application.EnableVisualStyles();
|
System.Reflection.AssemblyName embeddedAssembly = new System.Reflection.AssemblyName(args.Name);
|
||||||
Application.SetCompatibleTextRenderingDefault(false);
|
string resourceName = "XCI_Explorer" + "." + embeddedAssembly.Name + ".dll";
|
||||||
Application.Run(new MainForm());
|
|
||||||
}
|
using Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
|
||||||
|
byte[] assemblyData = new byte[stream.Length];
|
||||||
|
stream.Read(assemblyData, 0, assemblyData.Length);
|
||||||
|
return System.Reflection.Assembly.Load(assemblyData);
|
||||||
|
};
|
||||||
|
Application.EnableVisualStyles();
|
||||||
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
Application.Run(new MainForm());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using XCI_Explorer.Helpers;
|
using XCI_Explorer.Helpers;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
|
|
||||||
|
public class TreeViewFileSystem
|
||||||
{
|
{
|
||||||
public class TreeViewFileSystem
|
public TreeView treeView;
|
||||||
|
|
||||||
|
public TreeViewFileSystem(TreeView tv)
|
||||||
{
|
{
|
||||||
public TreeView treeView;
|
}
|
||||||
|
|
||||||
public TreeViewFileSystem(TreeView tv)
|
public BetterTreeNode AddDir(string name, BetterTreeNode parent = null)
|
||||||
|
{
|
||||||
|
BetterTreeNode betterTreeNode = new(name)
|
||||||
{
|
{
|
||||||
}
|
Offset = -1L,
|
||||||
|
Size = -1L
|
||||||
|
};
|
||||||
|
parent.Nodes.Add(betterTreeNode);
|
||||||
|
return betterTreeNode;
|
||||||
|
}
|
||||||
|
|
||||||
public BetterTreeNode AddDir(string name, BetterTreeNode parent = null)
|
public BetterTreeNode AddFile(string name, BetterTreeNode parent, long offset, long size) => AddFile(name, parent, offset, size, 0, "", "");
|
||||||
{
|
|
||||||
BetterTreeNode betterTreeNode = new BetterTreeNode(name);
|
|
||||||
betterTreeNode.Offset = -1L;
|
|
||||||
betterTreeNode.Size = -1L;
|
|
||||||
parent.Nodes.Add(betterTreeNode);
|
|
||||||
return betterTreeNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BetterTreeNode AddFile(string name, BetterTreeNode parent, long offset, long size)
|
public BetterTreeNode AddFile(string name, BetterTreeNode parent, long offset, long size, long HashedRegionSize, string ExpectedHash, string ActualHash)
|
||||||
|
{
|
||||||
|
BetterTreeNode betterTreeNode = new(name)
|
||||||
{
|
{
|
||||||
return AddFile(name, parent, offset, size, 0, "", "");
|
Offset = offset,
|
||||||
}
|
Size = size,
|
||||||
|
ExpectedHash = ExpectedHash,
|
||||||
public BetterTreeNode AddFile(string name, BetterTreeNode parent, long offset, long size, long HashedRegionSize, string ExpectedHash, string ActualHash)
|
ActualHash = ActualHash,
|
||||||
{
|
HashedRegionSize = HashedRegionSize
|
||||||
BetterTreeNode betterTreeNode = new BetterTreeNode(name);
|
};
|
||||||
betterTreeNode.Offset = offset;
|
parent.Nodes.Add(betterTreeNode);
|
||||||
betterTreeNode.Size = size;
|
return betterTreeNode;
|
||||||
betterTreeNode.ExpectedHash = ExpectedHash;
|
|
||||||
betterTreeNode.ActualHash = ActualHash;
|
|
||||||
betterTreeNode.HashedRegionSize = HashedRegionSize;
|
|
||||||
parent.Nodes.Add(betterTreeNode);
|
|
||||||
return betterTreeNode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,130 +1,73 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
|
|
||||||
|
internal static class Util
|
||||||
{
|
{
|
||||||
internal static class Util
|
public static string GetCapacity(int id)
|
||||||
{
|
{
|
||||||
public static string GetCapacity(int id)
|
return id switch
|
||||||
{
|
{
|
||||||
switch (id)
|
250 => "1GB",
|
||||||
{
|
248 => "2GB",
|
||||||
case 250:
|
240 => "4GB",
|
||||||
return "1GB";
|
224 => "8GB",
|
||||||
case 248:
|
225 => "16GB",
|
||||||
return "2GB";
|
226 => "32GB",
|
||||||
case 240:
|
_ => "?",
|
||||||
return "4GB";
|
};
|
||||||
case 224:
|
|
||||||
return "8GB";
|
|
||||||
case 225:
|
|
||||||
return "16GB";
|
|
||||||
case 226:
|
|
||||||
return "32GB";
|
|
||||||
default:
|
|
||||||
return "?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetMkey(byte id)
|
|
||||||
{
|
|
||||||
switch (id)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
return "MasterKey0 (1.0.0-2.3.0)";
|
|
||||||
case 2:
|
|
||||||
return "MasterKey1 (3.0.0)";
|
|
||||||
case 3:
|
|
||||||
return "MasterKey2 (3.0.1-3.0.2)";
|
|
||||||
case 4:
|
|
||||||
return "MasterKey3 (4.0.0-4.1.0)";
|
|
||||||
case 5:
|
|
||||||
return "MasterKey4 (5.0.0-5.1.0)";
|
|
||||||
case 6:
|
|
||||||
return "MasterKey5 (6.0.0-6.1.0)";
|
|
||||||
case 7:
|
|
||||||
return "MasterKey6 (6.2.0)";
|
|
||||||
case 8:
|
|
||||||
return "MasterKey7 (7.0.0-8.0.1)";
|
|
||||||
case 9:
|
|
||||||
return "MasterKey8 (8.1.0-8.1.1)";
|
|
||||||
case 10:
|
|
||||||
return "MasterKey9 (9.0.0-9.0.1)";
|
|
||||||
case 11:
|
|
||||||
return "MasterKey10 (9.1.0-12.0.3)";
|
|
||||||
case 12:
|
|
||||||
return "MasterKey11 (12.1.0)";
|
|
||||||
case 13:
|
|
||||||
return "MasterKey12 (13.0.0-?)";
|
|
||||||
case 14:
|
|
||||||
return "MasterKey13";
|
|
||||||
case 15:
|
|
||||||
return "MasterKey14";
|
|
||||||
case 16:
|
|
||||||
return "MasterKey15";
|
|
||||||
case 17:
|
|
||||||
return "MasterKey16";
|
|
||||||
case 18:
|
|
||||||
return "MasterKey17";
|
|
||||||
case 19:
|
|
||||||
return "MasterKey18";
|
|
||||||
case 20:
|
|
||||||
return "MasterKey19";
|
|
||||||
case 21:
|
|
||||||
return "MasterKey20";
|
|
||||||
case 22:
|
|
||||||
return "MasterKey21";
|
|
||||||
case 23:
|
|
||||||
return "MasterKey22";
|
|
||||||
case 24:
|
|
||||||
return "MasterKey23";
|
|
||||||
case 25:
|
|
||||||
return "MasterKey24";
|
|
||||||
case 26:
|
|
||||||
return "MasterKey25";
|
|
||||||
case 27:
|
|
||||||
return "MasterKey26";
|
|
||||||
case 28:
|
|
||||||
return "MasterKey27";
|
|
||||||
case 29:
|
|
||||||
return "MasterKey28";
|
|
||||||
case 30:
|
|
||||||
return "MasterKey29";
|
|
||||||
case 31:
|
|
||||||
return "MasterKey30";
|
|
||||||
case 32:
|
|
||||||
return "MasterKey31";
|
|
||||||
case 33:
|
|
||||||
return "MasterKey32";
|
|
||||||
default:
|
|
||||||
return "?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool checkFile(string filepath)
|
|
||||||
{
|
|
||||||
return File.Exists(filepath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] StringToByteArray(string hex)
|
|
||||||
{
|
|
||||||
return (from x in Enumerable.Range(0, hex.Length)
|
|
||||||
where x % 2 == 0
|
|
||||||
select Convert.ToByte(hex.Substring(x, 2), 16)).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Base64Encode(string plainText)
|
|
||||||
{
|
|
||||||
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
|
|
||||||
return System.Convert.ToBase64String(plainTextBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Base64Decode(string base64EncodedData)
|
|
||||||
{
|
|
||||||
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
|
|
||||||
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetMkey(byte id)
|
||||||
|
{
|
||||||
|
return id switch
|
||||||
|
{
|
||||||
|
0 or 1 => "MasterKey0 (1.0.0-2.3.0)",
|
||||||
|
2 => "MasterKey1 (3.0.0)",
|
||||||
|
3 => "MasterKey2 (3.0.1-3.0.2)",
|
||||||
|
4 => "MasterKey3 (4.0.0-4.1.0)",
|
||||||
|
5 => "MasterKey4 (5.0.0-5.1.0)",
|
||||||
|
6 => "MasterKey5 (6.0.0-6.1.0)",
|
||||||
|
7 => "MasterKey6 (6.2.0)",
|
||||||
|
8 => "MasterKey7 (7.0.0-8.0.1)",
|
||||||
|
9 => "MasterKey8 (8.1.0-8.1.1)",
|
||||||
|
10 => "MasterKey9 (9.0.0-9.0.1)",
|
||||||
|
11 => "MasterKey10 (9.1.0-12.0.3)",
|
||||||
|
12 => "MasterKey11 (12.1.0)",
|
||||||
|
13 => "MasterKey12 (13.0.0-?)",
|
||||||
|
14 => "MasterKey13",
|
||||||
|
15 => "MasterKey14",
|
||||||
|
16 => "MasterKey15",
|
||||||
|
17 => "MasterKey16",
|
||||||
|
18 => "MasterKey17",
|
||||||
|
19 => "MasterKey18",
|
||||||
|
20 => "MasterKey19",
|
||||||
|
21 => "MasterKey20",
|
||||||
|
22 => "MasterKey21",
|
||||||
|
23 => "MasterKey22",
|
||||||
|
24 => "MasterKey23",
|
||||||
|
25 => "MasterKey24",
|
||||||
|
26 => "MasterKey25",
|
||||||
|
27 => "MasterKey26",
|
||||||
|
28 => "MasterKey27",
|
||||||
|
29 => "MasterKey28",
|
||||||
|
30 => "MasterKey29",
|
||||||
|
31 => "MasterKey30",
|
||||||
|
32 => "MasterKey31",
|
||||||
|
33 => "MasterKey32",
|
||||||
|
_ => "?",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] StringToByteArray(string hex) => (from x in Enumerable.Range(0, hex.Length)
|
||||||
|
where x % 2 == 0
|
||||||
|
select Convert.ToByte(hex.Substring(x, 2), 16)).ToArray();
|
||||||
|
|
||||||
|
public static string Base64Encode(string plainText)
|
||||||
|
=> Convert.ToBase64String(Encoding.UTF8.GetBytes(plainText));
|
||||||
|
|
||||||
|
public static string Base64Decode(string base64EncodedData)
|
||||||
|
=> Encoding.UTF8.GetString(Convert.FromBase64String(base64EncodedData));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,30 +2,29 @@ using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace XCI_Explorer
|
namespace XCI_Explorer;
|
||||||
|
|
||||||
|
public static class XCI
|
||||||
{
|
{
|
||||||
public static class XCI
|
public class XCI_Header
|
||||||
{
|
{
|
||||||
public class XCI_Header
|
public byte[] Data;
|
||||||
|
public string Magic;
|
||||||
|
public byte CardSize1;
|
||||||
|
public long CardSize2;
|
||||||
|
public long HFS0OffsetPartition;
|
||||||
|
public long HFS0SizeParition;
|
||||||
|
|
||||||
|
public XCI_Header(byte[] data)
|
||||||
{
|
{
|
||||||
public byte[] Data;
|
Data = data;
|
||||||
public string Magic;
|
Magic = Encoding.UTF8.GetString(Data.Skip(256).Take(4).ToArray());
|
||||||
public byte CardSize1;
|
CardSize1 = Data[269];
|
||||||
public long CardSize2;
|
CardSize2 = BitConverter.ToInt64(data, 280);
|
||||||
public long HFS0OffsetPartition;
|
HFS0OffsetPartition = BitConverter.ToInt64(data, 304);
|
||||||
public long HFS0SizeParition;
|
HFS0SizeParition = BitConverter.ToInt64(data, 312);
|
||||||
|
|
||||||
public XCI_Header(byte[] data)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Magic = Encoding.UTF8.GetString(Data.Skip(256).Take(4).ToArray());
|
|
||||||
CardSize1 = Data[269];
|
|
||||||
CardSize2 = BitConverter.ToInt64(data, 280);
|
|
||||||
HFS0OffsetPartition = BitConverter.ToInt64(data, 304);
|
|
||||||
HFS0SizeParition = BitConverter.ToInt64(data, 312);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static XCI_Header[] XCI_Headers = new XCI_Header[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static XCI_Header[] XCI_Headers = new XCI_Header[1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,195 +1,190 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace XTSSharp
|
namespace XTSSharp;
|
||||||
|
|
||||||
|
public class RandomAccessSectorStream : Stream
|
||||||
{
|
{
|
||||||
public class RandomAccessSectorStream : Stream
|
private readonly byte[] _buffer;
|
||||||
|
private readonly int _bufferSize;
|
||||||
|
private readonly SectorStream _s;
|
||||||
|
private readonly bool _isStreamOwned;
|
||||||
|
private bool _bufferDirty;
|
||||||
|
private bool _bufferLoaded;
|
||||||
|
private int _bufferPos;
|
||||||
|
public override bool CanRead => _s.CanRead;
|
||||||
|
public override bool CanSeek => _s.CanSeek;
|
||||||
|
public override bool CanWrite => _s.CanWrite;
|
||||||
|
public override long Length => _s.Length + _bufferPos;
|
||||||
|
|
||||||
|
public override long Position
|
||||||
{
|
{
|
||||||
private readonly byte[] _buffer;
|
get
|
||||||
private readonly int _bufferSize;
|
|
||||||
private readonly SectorStream _s;
|
|
||||||
private readonly bool _isStreamOwned;
|
|
||||||
private bool _bufferDirty;
|
|
||||||
private bool _bufferLoaded;
|
|
||||||
private int _bufferPos;
|
|
||||||
public override bool CanRead => _s.CanRead;
|
|
||||||
public override bool CanSeek => _s.CanSeek;
|
|
||||||
public override bool CanWrite => _s.CanWrite;
|
|
||||||
public override long Length => _s.Length + _bufferPos;
|
|
||||||
|
|
||||||
public override long Position {
|
|
||||||
get {
|
|
||||||
if (!_bufferLoaded)
|
|
||||||
{
|
|
||||||
return _s.Position + _bufferPos;
|
|
||||||
}
|
|
||||||
return _s.Position - _bufferSize + _bufferPos;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
if (value < 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException("value");
|
|
||||||
}
|
|
||||||
long num = value % _bufferSize;
|
|
||||||
long position = value - num;
|
|
||||||
if (_bufferLoaded)
|
|
||||||
{
|
|
||||||
long num2 = _s.Position - _bufferSize;
|
|
||||||
if (value > num2 && value < num2 + _bufferSize)
|
|
||||||
{
|
|
||||||
_bufferPos = (int)num;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_bufferDirty)
|
|
||||||
{
|
|
||||||
WriteSector();
|
|
||||||
}
|
|
||||||
_s.Position = position;
|
|
||||||
ReadSector();
|
|
||||||
_bufferPos = (int)num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public RandomAccessSectorStream(SectorStream s)
|
|
||||||
: this(s, false)
|
|
||||||
{
|
{
|
||||||
}
|
if (!_bufferLoaded)
|
||||||
|
|
||||||
public RandomAccessSectorStream(SectorStream s, bool isStreamOwned)
|
|
||||||
{
|
|
||||||
_s = s;
|
|
||||||
_isStreamOwned = isStreamOwned;
|
|
||||||
_buffer = new byte[s.SectorSize];
|
|
||||||
_bufferSize = s.SectorSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
Flush();
|
|
||||||
base.Dispose(disposing);
|
|
||||||
if (_isStreamOwned)
|
|
||||||
{
|
{
|
||||||
_s.Dispose();
|
return _s.Position + _bufferPos;
|
||||||
}
|
}
|
||||||
|
return _s.Position - _bufferSize + _bufferPos;
|
||||||
}
|
}
|
||||||
|
set
|
||||||
public override void Flush()
|
|
||||||
{
|
{
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
|
}
|
||||||
|
long num = value % _bufferSize;
|
||||||
|
long position = value - num;
|
||||||
|
if (_bufferLoaded)
|
||||||
|
{
|
||||||
|
long num2 = _s.Position - _bufferSize;
|
||||||
|
if (value > num2 && value < num2 + _bufferSize)
|
||||||
|
{
|
||||||
|
_bufferPos = (int)num;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (_bufferDirty)
|
if (_bufferDirty)
|
||||||
{
|
{
|
||||||
WriteSector();
|
WriteSector();
|
||||||
}
|
}
|
||||||
|
_s.Position = position;
|
||||||
|
ReadSector();
|
||||||
|
_bufferPos = (int)num;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override long Seek(long offset, SeekOrigin origin)
|
public RandomAccessSectorStream(SectorStream s)
|
||||||
|
: this(s, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public RandomAccessSectorStream(SectorStream s, bool isStreamOwned)
|
||||||
|
{
|
||||||
|
_s = s;
|
||||||
|
_isStreamOwned = isStreamOwned;
|
||||||
|
_buffer = new byte[s.SectorSize];
|
||||||
|
_bufferSize = s.SectorSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
Flush();
|
||||||
|
base.Dispose(disposing);
|
||||||
|
if (_isStreamOwned)
|
||||||
{
|
{
|
||||||
long num;
|
_s.Dispose();
|
||||||
switch (origin)
|
|
||||||
{
|
|
||||||
case SeekOrigin.Begin:
|
|
||||||
num = offset;
|
|
||||||
break;
|
|
||||||
case SeekOrigin.End:
|
|
||||||
num = Length - offset;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
num = Position + offset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Position = num;
|
|
||||||
return num;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void SetLength(long value)
|
public override void Flush()
|
||||||
|
{
|
||||||
|
if (_bufferDirty)
|
||||||
{
|
{
|
||||||
long num = value % _s.SectorSize;
|
WriteSector();
|
||||||
if (num > 0)
|
|
||||||
{
|
|
||||||
value = value - num + _bufferSize;
|
|
||||||
}
|
|
||||||
_s.SetLength(value);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
long num = origin switch
|
||||||
{
|
{
|
||||||
long position = Position;
|
SeekOrigin.Begin => offset,
|
||||||
if (position + count > _s.Length)
|
SeekOrigin.End => Length - offset,
|
||||||
|
_ => Position + offset,
|
||||||
|
};
|
||||||
|
Position = num;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
long num = value % _s.SectorSize;
|
||||||
|
if (num > 0)
|
||||||
|
{
|
||||||
|
value = value - num + _bufferSize;
|
||||||
|
}
|
||||||
|
_s.SetLength(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
long position = Position;
|
||||||
|
if (position + count > _s.Length)
|
||||||
|
{
|
||||||
|
count = (int)(_s.Length - position);
|
||||||
|
}
|
||||||
|
if (!_bufferLoaded)
|
||||||
|
{
|
||||||
|
ReadSector();
|
||||||
|
}
|
||||||
|
int num = 0;
|
||||||
|
while (count > 0)
|
||||||
|
{
|
||||||
|
int num2 = Math.Min(count, _bufferSize - _bufferPos);
|
||||||
|
Buffer.BlockCopy(_buffer, _bufferPos, buffer, offset, num2);
|
||||||
|
offset += num2;
|
||||||
|
_bufferPos += num2;
|
||||||
|
count -= num2;
|
||||||
|
num += num2;
|
||||||
|
if (_bufferPos == _bufferSize)
|
||||||
{
|
{
|
||||||
count = (int)(_s.Length - position);
|
ReadSector();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
while (count > 0)
|
||||||
|
{
|
||||||
if (!_bufferLoaded)
|
if (!_bufferLoaded)
|
||||||
{
|
{
|
||||||
ReadSector();
|
ReadSector();
|
||||||
}
|
}
|
||||||
int num = 0;
|
int num = Math.Min(count, _bufferSize - _bufferPos);
|
||||||
while (count > 0)
|
Buffer.BlockCopy(buffer, offset, _buffer, _bufferPos, num);
|
||||||
{
|
offset += num;
|
||||||
int num2 = Math.Min(count, _bufferSize - _bufferPos);
|
_bufferPos += num;
|
||||||
Buffer.BlockCopy(_buffer, _bufferPos, buffer, offset, num2);
|
count -= num;
|
||||||
offset += num2;
|
_bufferDirty = true;
|
||||||
_bufferPos += num2;
|
if (_bufferPos == _bufferSize)
|
||||||
count -= num2;
|
|
||||||
num += num2;
|
|
||||||
if (_bufferPos == _bufferSize)
|
|
||||||
{
|
|
||||||
ReadSector();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
while (count > 0)
|
|
||||||
{
|
|
||||||
if (!_bufferLoaded)
|
|
||||||
{
|
|
||||||
ReadSector();
|
|
||||||
}
|
|
||||||
int num = Math.Min(count, _bufferSize - _bufferPos);
|
|
||||||
Buffer.BlockCopy(buffer, offset, _buffer, _bufferPos, num);
|
|
||||||
offset += num;
|
|
||||||
_bufferPos += num;
|
|
||||||
count -= num;
|
|
||||||
_bufferDirty = true;
|
|
||||||
if (_bufferPos == _bufferSize)
|
|
||||||
{
|
|
||||||
WriteSector();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReadSector()
|
|
||||||
{
|
|
||||||
if (_bufferLoaded && _bufferDirty)
|
|
||||||
{
|
{
|
||||||
WriteSector();
|
WriteSector();
|
||||||
}
|
}
|
||||||
if (_s.Position != _s.Length)
|
|
||||||
{
|
|
||||||
int num = _s.Read(_buffer, 0, _buffer.Length);
|
|
||||||
if (num != _bufferSize)
|
|
||||||
{
|
|
||||||
Array.Clear(_buffer, num, _buffer.Length - num);
|
|
||||||
}
|
|
||||||
_bufferLoaded = true;
|
|
||||||
_bufferPos = 0;
|
|
||||||
_bufferDirty = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteSector()
|
|
||||||
{
|
|
||||||
if (_bufferLoaded)
|
|
||||||
{
|
|
||||||
_s.Seek(-_bufferSize, SeekOrigin.Current);
|
|
||||||
}
|
|
||||||
_s.Write(_buffer, 0, _bufferSize);
|
|
||||||
_bufferDirty = false;
|
|
||||||
_bufferLoaded = false;
|
|
||||||
_bufferPos = 0;
|
|
||||||
Array.Clear(_buffer, 0, _bufferSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ReadSector()
|
||||||
|
{
|
||||||
|
if (_bufferLoaded && _bufferDirty)
|
||||||
|
{
|
||||||
|
WriteSector();
|
||||||
|
}
|
||||||
|
if (_s.Position != _s.Length)
|
||||||
|
{
|
||||||
|
int num = _s.Read(_buffer, 0, _buffer.Length);
|
||||||
|
if (num != _bufferSize)
|
||||||
|
{
|
||||||
|
Array.Clear(_buffer, num, _buffer.Length - num);
|
||||||
|
}
|
||||||
|
_bufferLoaded = true;
|
||||||
|
_bufferPos = 0;
|
||||||
|
_bufferDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteSector()
|
||||||
|
{
|
||||||
|
if (_bufferLoaded)
|
||||||
|
{
|
||||||
|
_s.Seek(-_bufferSize, SeekOrigin.Current);
|
||||||
|
}
|
||||||
|
_s.Write(_buffer, 0, _bufferSize);
|
||||||
|
_bufferDirty = false;
|
||||||
|
_bufferLoaded = false;
|
||||||
|
_bufferPos = 0;
|
||||||
|
Array.Clear(_buffer, 0, _bufferSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,119 +1,115 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace XTSSharp
|
namespace XTSSharp;
|
||||||
|
|
||||||
|
public class SectorStream : Stream
|
||||||
{
|
{
|
||||||
public class SectorStream : Stream
|
private readonly Stream _baseStream;
|
||||||
|
private readonly long _offset;
|
||||||
|
private ulong _currentSector;
|
||||||
|
|
||||||
|
public int SectorSize
|
||||||
{
|
{
|
||||||
private readonly Stream _baseStream;
|
get;
|
||||||
private readonly long _offset;
|
private set;
|
||||||
private ulong _currentSector;
|
}
|
||||||
|
|
||||||
public int SectorSize {
|
public override bool CanRead => _baseStream.CanRead;
|
||||||
get;
|
public override bool CanSeek => _baseStream.CanSeek;
|
||||||
private set;
|
public override bool CanWrite => _baseStream.CanWrite;
|
||||||
}
|
public override long Length => _baseStream.Length - _offset;
|
||||||
|
|
||||||
public override bool CanRead => _baseStream.CanRead;
|
public override long Position
|
||||||
public override bool CanSeek => _baseStream.CanSeek;
|
{
|
||||||
public override bool CanWrite => _baseStream.CanWrite;
|
get
|
||||||
public override long Length => _baseStream.Length - _offset;
|
|
||||||
|
|
||||||
public override long Position {
|
|
||||||
get {
|
|
||||||
return _baseStream.Position - _offset;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
ValidateSizeMultiple(value);
|
|
||||||
_baseStream.Position = value + _offset;
|
|
||||||
_currentSector = (ulong)(value / SectorSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ulong CurrentSector => _currentSector;
|
|
||||||
|
|
||||||
public SectorStream(Stream baseStream, int sectorSize)
|
|
||||||
: this(baseStream, sectorSize, 0L)
|
|
||||||
{
|
{
|
||||||
|
return _baseStream.Position - _offset;
|
||||||
}
|
}
|
||||||
|
set
|
||||||
public SectorStream(Stream baseStream, int sectorSize, long offset)
|
|
||||||
{
|
|
||||||
SectorSize = sectorSize;
|
|
||||||
_baseStream = baseStream;
|
|
||||||
_offset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ValidateSizeMultiple(long value)
|
|
||||||
{
|
|
||||||
if (value % SectorSize == 0L)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new ArgumentException($"Value needs to be a multiple of {SectorSize}");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void ValidateSize(long value)
|
|
||||||
{
|
|
||||||
if (value == SectorSize)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new ArgumentException($"Value needs to be {SectorSize}");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void ValidateSize(int value)
|
|
||||||
{
|
|
||||||
if (value == SectorSize)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new ArgumentException($"Value needs to be {SectorSize}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Flush()
|
|
||||||
{
|
|
||||||
_baseStream.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Seek(long offset, SeekOrigin origin)
|
|
||||||
{
|
|
||||||
long num;
|
|
||||||
switch (origin)
|
|
||||||
{
|
|
||||||
case SeekOrigin.Begin:
|
|
||||||
num = offset;
|
|
||||||
break;
|
|
||||||
case SeekOrigin.End:
|
|
||||||
num = Length - offset;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
num = Position + offset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Position = num;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetLength(long value)
|
|
||||||
{
|
{
|
||||||
ValidateSizeMultiple(value);
|
ValidateSizeMultiple(value);
|
||||||
_baseStream.SetLength(value);
|
_baseStream.Position = value + _offset;
|
||||||
}
|
_currentSector = (ulong)(value / SectorSize);
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
ValidateSize(count);
|
|
||||||
int result = _baseStream.Read(buffer, offset, count);
|
|
||||||
_currentSector++;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
ValidateSize(count);
|
|
||||||
_baseStream.Write(buffer, offset, count);
|
|
||||||
_currentSector++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ulong CurrentSector => _currentSector;
|
||||||
|
|
||||||
|
public SectorStream(Stream baseStream, int sectorSize)
|
||||||
|
: this(baseStream, sectorSize, 0L)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public SectorStream(Stream baseStream, int sectorSize, long offset)
|
||||||
|
{
|
||||||
|
SectorSize = sectorSize;
|
||||||
|
_baseStream = baseStream;
|
||||||
|
_offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateSizeMultiple(long value)
|
||||||
|
{
|
||||||
|
if (value % SectorSize == 0L)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Value needs to be a multiple of {SectorSize}");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ValidateSize(long value)
|
||||||
|
{
|
||||||
|
if (value == SectorSize)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Value needs to be {SectorSize}");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ValidateSize(int value)
|
||||||
|
{
|
||||||
|
if (value == SectorSize)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"Value needs to be {SectorSize}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
_baseStream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
long num = origin switch
|
||||||
|
{
|
||||||
|
SeekOrigin.Begin => offset,
|
||||||
|
SeekOrigin.End => Length - offset,
|
||||||
|
_ => Position + offset,
|
||||||
|
};
|
||||||
|
Position = num;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
ValidateSizeMultiple(value);
|
||||||
|
_baseStream.SetLength(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
ValidateSize(count);
|
||||||
|
int result = _baseStream.Read(buffer, offset, count);
|
||||||
|
_currentSector++;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
ValidateSize(count);
|
||||||
|
_baseStream.Write(buffer, offset, count);
|
||||||
|
_currentSector++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
101
XTSSharp/Xts.cs
101
XTSSharp/Xts.cs
|
@ -1,66 +1,65 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace XTSSharp
|
namespace XTSSharp;
|
||||||
|
|
||||||
|
public class Xts
|
||||||
{
|
{
|
||||||
public class Xts
|
private readonly SymmetricAlgorithm _key1;
|
||||||
|
private readonly SymmetricAlgorithm _key2;
|
||||||
|
|
||||||
|
protected Xts(Func<SymmetricAlgorithm> create, byte[] key1, byte[] key2)
|
||||||
{
|
{
|
||||||
private readonly SymmetricAlgorithm _key1;
|
if (create == null)
|
||||||
private readonly SymmetricAlgorithm _key2;
|
|
||||||
|
|
||||||
protected Xts(Func<SymmetricAlgorithm> create, byte[] key1, byte[] key2)
|
|
||||||
{
|
{
|
||||||
if (create == null)
|
throw new ArgumentNullException(nameof(create));
|
||||||
{
|
|
||||||
throw new ArgumentNullException("create");
|
|
||||||
}
|
|
||||||
if (key1 == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("key1");
|
|
||||||
}
|
|
||||||
if (key2 == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("key2");
|
|
||||||
}
|
|
||||||
_key1 = create();
|
|
||||||
_key2 = create();
|
|
||||||
if (key1.Length != key2.Length)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Key lengths don't match");
|
|
||||||
}
|
|
||||||
_key1.KeySize = key1.Length * 8;
|
|
||||||
_key2.KeySize = key2.Length * 8;
|
|
||||||
_key1.Key = key1;
|
|
||||||
_key2.Key = key2;
|
|
||||||
_key1.Mode = CipherMode.ECB;
|
|
||||||
_key2.Mode = CipherMode.ECB;
|
|
||||||
_key1.Padding = PaddingMode.None;
|
|
||||||
_key2.Padding = PaddingMode.None;
|
|
||||||
_key1.BlockSize = 128;
|
|
||||||
_key2.BlockSize = 128;
|
|
||||||
}
|
}
|
||||||
|
if (key1 == null)
|
||||||
public XtsCryptoTransform CreateEncryptor()
|
|
||||||
{
|
{
|
||||||
return new XtsCryptoTransform(_key1.CreateEncryptor(), _key2.CreateEncryptor(), false);
|
throw new ArgumentNullException(nameof(key1));
|
||||||
}
|
}
|
||||||
|
if (key2 == null)
|
||||||
public XtsCryptoTransform CreateDecryptor()
|
|
||||||
{
|
{
|
||||||
return new XtsCryptoTransform(_key1.CreateDecryptor(), _key2.CreateEncryptor(), true);
|
throw new ArgumentNullException(nameof(key2));
|
||||||
}
|
}
|
||||||
|
_key1 = create();
|
||||||
protected static byte[] VerifyKey(int expectedSize, byte[] key)
|
_key2 = create();
|
||||||
|
if (key1.Length != key2.Length)
|
||||||
{
|
{
|
||||||
if (key == null)
|
throw new ArgumentException("Key lengths don't match");
|
||||||
{
|
|
||||||
throw new ArgumentNullException("key");
|
|
||||||
}
|
|
||||||
if (key.Length * 8 != expectedSize)
|
|
||||||
{
|
|
||||||
throw new ArgumentException($"Expected key length of {expectedSize} bits, got {key.Length * 8}");
|
|
||||||
}
|
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
|
_key1.KeySize = key1.Length * 8;
|
||||||
|
_key2.KeySize = key2.Length * 8;
|
||||||
|
_key1.Key = key1;
|
||||||
|
_key2.Key = key2;
|
||||||
|
_key1.Mode = CipherMode.ECB;
|
||||||
|
_key2.Mode = CipherMode.ECB;
|
||||||
|
_key1.Padding = PaddingMode.None;
|
||||||
|
_key2.Padding = PaddingMode.None;
|
||||||
|
_key1.BlockSize = 128;
|
||||||
|
_key2.BlockSize = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XtsCryptoTransform CreateEncryptor()
|
||||||
|
{
|
||||||
|
return new XtsCryptoTransform(_key1.CreateEncryptor(), _key2.CreateEncryptor(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XtsCryptoTransform CreateDecryptor()
|
||||||
|
{
|
||||||
|
return new XtsCryptoTransform(_key1.CreateDecryptor(), _key2.CreateEncryptor(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static byte[] VerifyKey(int expectedSize, byte[] key)
|
||||||
|
{
|
||||||
|
if (key == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
}
|
||||||
|
if (key.Length * 8 != expectedSize)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Expected key length of {expectedSize} bits, got {key.Length * 8}");
|
||||||
|
}
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,32 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace XTSSharp
|
namespace XTSSharp;
|
||||||
|
|
||||||
|
public class XtsAes128 : Xts
|
||||||
{
|
{
|
||||||
public class XtsAes128 : Xts
|
private const int KEY_LENGTH = 128;
|
||||||
|
private const int KEY_BYTE_LENGTH = 16;
|
||||||
|
|
||||||
|
protected XtsAes128(Func<SymmetricAlgorithm> create, byte[] key1, byte[] key2)
|
||||||
|
: base(create, VerifyKey(128, key1), VerifyKey(128, key2))
|
||||||
{
|
{
|
||||||
private const int KEY_LENGTH = 128;
|
}
|
||||||
private const int KEY_BYTE_LENGTH = 16;
|
|
||||||
|
|
||||||
protected XtsAes128(Func<SymmetricAlgorithm> create, byte[] key1, byte[] key2)
|
public static Xts Create(byte[] key1, byte[] key2)
|
||||||
: base(create, Xts.VerifyKey(128, key1), Xts.VerifyKey(128, key2))
|
{
|
||||||
{
|
VerifyKey(128, key1);
|
||||||
}
|
VerifyKey(128, key2);
|
||||||
|
return new XtsAes128(Aes.Create, key1, key2);
|
||||||
|
}
|
||||||
|
|
||||||
public static Xts Create(byte[] key1, byte[] key2)
|
public static Xts Create(byte[] key)
|
||||||
{
|
{
|
||||||
Xts.VerifyKey(128, key1);
|
VerifyKey(256, key);
|
||||||
Xts.VerifyKey(128, key2);
|
byte[] array = new byte[16];
|
||||||
return new XtsAes128(Aes.Create, key1, key2);
|
byte[] array2 = new byte[16];
|
||||||
}
|
Buffer.BlockCopy(key, 0, array, 0, 16);
|
||||||
|
Buffer.BlockCopy(key, 16, array2, 0, 16);
|
||||||
public static Xts Create(byte[] key)
|
return new XtsAes128(Aes.Create, array, array2);
|
||||||
{
|
|
||||||
Xts.VerifyKey(256, key);
|
|
||||||
byte[] array = new byte[16];
|
|
||||||
byte[] array2 = new byte[16];
|
|
||||||
Buffer.BlockCopy(key, 0, array, 0, 16);
|
|
||||||
Buffer.BlockCopy(key, 16, array2, 0, 16);
|
|
||||||
return new XtsAes128(Aes.Create, array, array2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,32 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace XTSSharp
|
namespace XTSSharp;
|
||||||
|
|
||||||
|
public class XtsAes256 : Xts
|
||||||
{
|
{
|
||||||
public class XtsAes256 : Xts
|
private const int KEY_LENGTH = 256;
|
||||||
|
private const int KEY_BYTE_LENGTH = 32;
|
||||||
|
|
||||||
|
protected XtsAes256(Func<SymmetricAlgorithm> create, byte[] key1, byte[] key2)
|
||||||
|
: base(create, VerifyKey(256, key1), VerifyKey(256, key2))
|
||||||
{
|
{
|
||||||
private const int KEY_LENGTH = 256;
|
}
|
||||||
private const int KEY_BYTE_LENGTH = 32;
|
|
||||||
|
|
||||||
protected XtsAes256(Func<SymmetricAlgorithm> create, byte[] key1, byte[] key2)
|
public static Xts Create(byte[] key1, byte[] key2)
|
||||||
: base(create, Xts.VerifyKey(256, key1), Xts.VerifyKey(256, key2))
|
{
|
||||||
{
|
VerifyKey(256, key1);
|
||||||
}
|
VerifyKey(256, key2);
|
||||||
|
return new XtsAes256(Aes.Create, key1, key2);
|
||||||
|
}
|
||||||
|
|
||||||
public static Xts Create(byte[] key1, byte[] key2)
|
public static Xts Create(byte[] key)
|
||||||
{
|
{
|
||||||
Xts.VerifyKey(256, key1);
|
VerifyKey(512, key);
|
||||||
Xts.VerifyKey(256, key2);
|
byte[] array = new byte[32];
|
||||||
return new XtsAes256(Aes.Create, key1, key2);
|
byte[] array2 = new byte[32];
|
||||||
}
|
Buffer.BlockCopy(key, 0, array, 0, 32);
|
||||||
|
Buffer.BlockCopy(key, 32, array2, 0, 32);
|
||||||
public static Xts Create(byte[] key)
|
return new XtsAes256(Aes.Create, array, array2);
|
||||||
{
|
|
||||||
Xts.VerifyKey(512, key);
|
|
||||||
byte[] array = new byte[32];
|
|
||||||
byte[] array2 = new byte[32];
|
|
||||||
Buffer.BlockCopy(key, 0, array, 0, 32);
|
|
||||||
Buffer.BlockCopy(key, 32, array2, 0, 32);
|
|
||||||
return new XtsAes256(Aes.Create, array, array2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,142 +1,141 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace XTSSharp
|
namespace XTSSharp;
|
||||||
|
|
||||||
|
public class XtsCryptoTransform : IDisposable
|
||||||
{
|
{
|
||||||
public class XtsCryptoTransform : IDisposable
|
private readonly byte[] _cc = new byte[16];
|
||||||
|
private readonly bool _decrypting;
|
||||||
|
private readonly ICryptoTransform _key1;
|
||||||
|
private readonly ICryptoTransform _key2;
|
||||||
|
private readonly byte[] _pp = new byte[16];
|
||||||
|
private readonly byte[] _t = new byte[16];
|
||||||
|
private readonly byte[] _tweak = new byte[16];
|
||||||
|
|
||||||
|
public XtsCryptoTransform(ICryptoTransform key1, ICryptoTransform key2, bool decrypting)
|
||||||
{
|
{
|
||||||
private readonly byte[] _cc = new byte[16];
|
if (key1 == null)
|
||||||
private readonly bool _decrypting;
|
|
||||||
private readonly ICryptoTransform _key1;
|
|
||||||
private readonly ICryptoTransform _key2;
|
|
||||||
private readonly byte[] _pp = new byte[16];
|
|
||||||
private readonly byte[] _t = new byte[16];
|
|
||||||
private readonly byte[] _tweak = new byte[16];
|
|
||||||
|
|
||||||
public XtsCryptoTransform(ICryptoTransform key1, ICryptoTransform key2, bool decrypting)
|
|
||||||
{
|
{
|
||||||
if (key1 == null)
|
throw new ArgumentNullException(nameof(key1));
|
||||||
{
|
|
||||||
throw new ArgumentNullException("key1");
|
|
||||||
}
|
|
||||||
if (key2 == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("key2");
|
|
||||||
}
|
|
||||||
_key1 = key1;
|
|
||||||
_key2 = key2;
|
|
||||||
_decrypting = decrypting;
|
|
||||||
}
|
}
|
||||||
|
if (key2 == null)
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
_key1.Dispose();
|
throw new ArgumentNullException(nameof(key2));
|
||||||
_key2.Dispose();
|
|
||||||
}
|
}
|
||||||
|
_key1 = key1;
|
||||||
|
_key2 = key2;
|
||||||
|
_decrypting = decrypting;
|
||||||
|
}
|
||||||
|
|
||||||
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset, ulong sector)
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_key1.Dispose();
|
||||||
|
_key2.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset, ulong sector)
|
||||||
|
{
|
||||||
|
FillArrayFromSectorLittleEndian(_tweak, sector);
|
||||||
|
int num = inputCount >> 4;
|
||||||
|
int num2 = inputCount & 0xF;
|
||||||
|
_key2.TransformBlock(_tweak, 0, _tweak.Length, _t, 0);
|
||||||
|
int num3 = (num2 != 0) ? (num - 1) : num;
|
||||||
|
for (int i = 0; i < num3; i++)
|
||||||
{
|
{
|
||||||
FillArrayFromSectorLittleEndian(_tweak, sector);
|
TweakCrypt(inputBuffer, inputOffset, outputBuffer, outputOffset, _t);
|
||||||
int num = inputCount >> 4;
|
inputOffset += 16;
|
||||||
int num2 = inputCount & 0xF;
|
outputOffset += 16;
|
||||||
_key2.TransformBlock(_tweak, 0, _tweak.Length, _t, 0);
|
}
|
||||||
int num3 = (num2 != 0) ? (num - 1) : num;
|
if (num2 > 0)
|
||||||
for (int i = 0; i < num3; i++)
|
{
|
||||||
|
if (_decrypting)
|
||||||
{
|
{
|
||||||
TweakCrypt(inputBuffer, inputOffset, outputBuffer, outputOffset, _t);
|
Buffer.BlockCopy(_t, 0, _cc, 0, 16);
|
||||||
inputOffset += 16;
|
MultiplyByX(_cc);
|
||||||
outputOffset += 16;
|
TweakCrypt(inputBuffer, inputOffset, _pp, 0, _cc);
|
||||||
}
|
int j;
|
||||||
if (num2 > 0)
|
for (j = 0; j < num2; j++)
|
||||||
{
|
|
||||||
if (_decrypting)
|
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(_t, 0, _cc, 0, 16);
|
_cc[j] = inputBuffer[16 + j + inputOffset];
|
||||||
MultiplyByX(_cc);
|
outputBuffer[16 + j + outputOffset] = _pp[j];
|
||||||
TweakCrypt(inputBuffer, inputOffset, _pp, 0, _cc);
|
|
||||||
int j;
|
|
||||||
for (j = 0; j < num2; j++)
|
|
||||||
{
|
|
||||||
_cc[j] = inputBuffer[16 + j + inputOffset];
|
|
||||||
outputBuffer[16 + j + outputOffset] = _pp[j];
|
|
||||||
}
|
|
||||||
for (; j < 16; j++)
|
|
||||||
{
|
|
||||||
_cc[j] = _pp[j];
|
|
||||||
}
|
|
||||||
TweakCrypt(_cc, 0, outputBuffer, outputOffset, _t);
|
|
||||||
}
|
}
|
||||||
else
|
for (; j < 16; j++)
|
||||||
{
|
{
|
||||||
TweakCrypt(inputBuffer, inputOffset, _cc, 0, _t);
|
_cc[j] = _pp[j];
|
||||||
int k;
|
|
||||||
for (k = 0; k < num2; k++)
|
|
||||||
{
|
|
||||||
_pp[k] = inputBuffer[16 + k + inputOffset];
|
|
||||||
outputBuffer[16 + k + outputOffset] = _cc[k];
|
|
||||||
}
|
|
||||||
for (; k < 16; k++)
|
|
||||||
{
|
|
||||||
_pp[k] = _cc[k];
|
|
||||||
}
|
|
||||||
TweakCrypt(_pp, 0, outputBuffer, outputOffset, _t);
|
|
||||||
}
|
}
|
||||||
|
TweakCrypt(_cc, 0, outputBuffer, outputOffset, _t);
|
||||||
}
|
}
|
||||||
return inputCount;
|
else
|
||||||
}
|
|
||||||
|
|
||||||
private static void FillArrayFromSectorBigEndian(byte[] value, ulong sector)
|
|
||||||
{
|
|
||||||
value[7] = (byte)((sector >> 56) & 0xFF);
|
|
||||||
value[6] = (byte)((sector >> 48) & 0xFF);
|
|
||||||
value[5] = (byte)((sector >> 40) & 0xFF);
|
|
||||||
value[4] = (byte)((sector >> 32) & 0xFF);
|
|
||||||
value[3] = (byte)((sector >> 24) & 0xFF);
|
|
||||||
value[2] = (byte)((sector >> 16) & 0xFF);
|
|
||||||
value[1] = (byte)((sector >> 8) & 0xFF);
|
|
||||||
value[0] = (byte)(sector & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void FillArrayFromSectorLittleEndian(byte[] value, ulong sector)
|
|
||||||
{
|
|
||||||
value[8] = (byte)((sector >> 56) & 0xFF);
|
|
||||||
value[9] = (byte)((sector >> 48) & 0xFF);
|
|
||||||
value[10] = (byte)((sector >> 40) & 0xFF);
|
|
||||||
value[11] = (byte)((sector >> 32) & 0xFF);
|
|
||||||
value[12] = (byte)((sector >> 24) & 0xFF);
|
|
||||||
value[13] = (byte)((sector >> 16) & 0xFF);
|
|
||||||
value[14] = (byte)((sector >> 8) & 0xFF);
|
|
||||||
value[15] = (byte)(sector & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TweakCrypt(byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, byte[] t)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
{
|
{
|
||||||
outputBuffer[i + outputOffset] = (byte)(inputBuffer[i + inputOffset] ^ t[i]);
|
TweakCrypt(inputBuffer, inputOffset, _cc, 0, _t);
|
||||||
|
int k;
|
||||||
|
for (k = 0; k < num2; k++)
|
||||||
|
{
|
||||||
|
_pp[k] = inputBuffer[16 + k + inputOffset];
|
||||||
|
outputBuffer[16 + k + outputOffset] = _cc[k];
|
||||||
|
}
|
||||||
|
for (; k < 16; k++)
|
||||||
|
{
|
||||||
|
_pp[k] = _cc[k];
|
||||||
|
}
|
||||||
|
TweakCrypt(_pp, 0, outputBuffer, outputOffset, _t);
|
||||||
}
|
}
|
||||||
_key1.TransformBlock(outputBuffer, outputOffset, 16, outputBuffer, outputOffset);
|
|
||||||
for (int j = 0; j < 16; j++)
|
|
||||||
{
|
|
||||||
outputBuffer[j + outputOffset] = (byte)(outputBuffer[j + outputOffset] ^ t[j]);
|
|
||||||
}
|
|
||||||
MultiplyByX(t);
|
|
||||||
}
|
}
|
||||||
|
return inputCount;
|
||||||
|
}
|
||||||
|
|
||||||
private static void MultiplyByX(byte[] i)
|
private static void FillArrayFromSectorBigEndian(byte[] value, ulong sector)
|
||||||
|
{
|
||||||
|
value[7] = (byte)((sector >> 56) & 0xFF);
|
||||||
|
value[6] = (byte)((sector >> 48) & 0xFF);
|
||||||
|
value[5] = (byte)((sector >> 40) & 0xFF);
|
||||||
|
value[4] = (byte)((sector >> 32) & 0xFF);
|
||||||
|
value[3] = (byte)((sector >> 24) & 0xFF);
|
||||||
|
value[2] = (byte)((sector >> 16) & 0xFF);
|
||||||
|
value[1] = (byte)((sector >> 8) & 0xFF);
|
||||||
|
value[0] = (byte)(sector & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FillArrayFromSectorLittleEndian(byte[] value, ulong sector)
|
||||||
|
{
|
||||||
|
value[8] = (byte)((sector >> 56) & 0xFF);
|
||||||
|
value[9] = (byte)((sector >> 48) & 0xFF);
|
||||||
|
value[10] = (byte)((sector >> 40) & 0xFF);
|
||||||
|
value[11] = (byte)((sector >> 32) & 0xFF);
|
||||||
|
value[12] = (byte)((sector >> 24) & 0xFF);
|
||||||
|
value[13] = (byte)((sector >> 16) & 0xFF);
|
||||||
|
value[14] = (byte)((sector >> 8) & 0xFF);
|
||||||
|
value[15] = (byte)(sector & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TweakCrypt(byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, byte[] t)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
byte b = 0;
|
outputBuffer[i + outputOffset] = (byte)(inputBuffer[i + inputOffset] ^ t[i]);
|
||||||
byte b2 = 0;
|
}
|
||||||
for (int j = 0; j < 16; j++)
|
_key1.TransformBlock(outputBuffer, outputOffset, 16, outputBuffer, outputOffset);
|
||||||
{
|
for (int j = 0; j < 16; j++)
|
||||||
b2 = (byte)(i[j] >> 7);
|
{
|
||||||
i[j] = (byte)(((i[j] << 1) | b) & 0xFF);
|
outputBuffer[j + outputOffset] = (byte)(outputBuffer[j + outputOffset] ^ t[j]);
|
||||||
b = b2;
|
}
|
||||||
}
|
MultiplyByX(t);
|
||||||
if (b2 > 0)
|
}
|
||||||
{
|
|
||||||
i[0] ^= 135;
|
private static void MultiplyByX(byte[] i)
|
||||||
}
|
{
|
||||||
|
byte b = 0;
|
||||||
|
byte b2 = 0;
|
||||||
|
for (int j = 0; j < 16; j++)
|
||||||
|
{
|
||||||
|
b2 = (byte)(i[j] >> 7);
|
||||||
|
i[j] = (byte)(((i[j] << 1) | b) & 0xFF);
|
||||||
|
b = b2;
|
||||||
|
}
|
||||||
|
if (b2 > 0)
|
||||||
|
{
|
||||||
|
i[0] ^= 135;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,74 +1,73 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace XTSSharp
|
namespace XTSSharp;
|
||||||
|
|
||||||
|
public class XtsSectorStream : SectorStream
|
||||||
{
|
{
|
||||||
public class XtsSectorStream : SectorStream
|
public const int DEFAULT_SECTOR_SIZE = 512;
|
||||||
|
private readonly byte[] _tempBuffer;
|
||||||
|
private readonly Xts _xts;
|
||||||
|
private XtsCryptoTransform _decryptor;
|
||||||
|
private XtsCryptoTransform _encryptor;
|
||||||
|
|
||||||
|
public XtsSectorStream(Stream baseStream, Xts xts)
|
||||||
|
: this(baseStream, xts, 512)
|
||||||
{
|
{
|
||||||
public const int DEFAULT_SECTOR_SIZE = 512;
|
}
|
||||||
private readonly byte[] _tempBuffer;
|
|
||||||
private readonly Xts _xts;
|
|
||||||
private XtsCryptoTransform _decryptor;
|
|
||||||
private XtsCryptoTransform _encryptor;
|
|
||||||
|
|
||||||
public XtsSectorStream(Stream baseStream, Xts xts)
|
public XtsSectorStream(Stream baseStream, Xts xts, int sectorSize)
|
||||||
: this(baseStream, xts, 512)
|
: this(baseStream, xts, sectorSize, 0L)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public XtsSectorStream(Stream baseStream, Xts xts, int sectorSize, long offset)
|
||||||
|
: base(baseStream, sectorSize, offset)
|
||||||
|
{
|
||||||
|
_xts = xts;
|
||||||
|
_tempBuffer = new byte[sectorSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
if (_encryptor != null)
|
||||||
{
|
{
|
||||||
|
_encryptor.Dispose();
|
||||||
}
|
}
|
||||||
|
if (_decryptor != null)
|
||||||
public XtsSectorStream(Stream baseStream, Xts xts, int sectorSize)
|
|
||||||
: this(baseStream, xts, sectorSize, 0L)
|
|
||||||
{
|
{
|
||||||
}
|
_decryptor.Dispose();
|
||||||
|
|
||||||
public XtsSectorStream(Stream baseStream, Xts xts, int sectorSize, long offset)
|
|
||||||
: base(baseStream, sectorSize, offset)
|
|
||||||
{
|
|
||||||
_xts = xts;
|
|
||||||
_tempBuffer = new byte[sectorSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
base.Dispose(disposing);
|
|
||||||
if (_encryptor != null)
|
|
||||||
{
|
|
||||||
_encryptor.Dispose();
|
|
||||||
}
|
|
||||||
if (_decryptor != null)
|
|
||||||
{
|
|
||||||
_decryptor.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
ValidateSize(count);
|
|
||||||
if (count != 0)
|
|
||||||
{
|
|
||||||
ulong currentSector = base.CurrentSector;
|
|
||||||
if (_encryptor == null)
|
|
||||||
{
|
|
||||||
_encryptor = _xts.CreateEncryptor();
|
|
||||||
}
|
|
||||||
int count2 = _encryptor.TransformBlock(buffer, offset, count, _tempBuffer, 0, currentSector);
|
|
||||||
base.Write(_tempBuffer, 0, count2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
ValidateSize(count);
|
|
||||||
ulong currentSector = base.CurrentSector;
|
|
||||||
int num = base.Read(_tempBuffer, 0, count);
|
|
||||||
if (num == 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (_decryptor == null)
|
|
||||||
{
|
|
||||||
_decryptor = _xts.CreateDecryptor();
|
|
||||||
}
|
|
||||||
return _decryptor.TransformBlock(_tempBuffer, 0, num, buffer, offset, currentSector);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
ValidateSize(count);
|
||||||
|
if (count != 0)
|
||||||
|
{
|
||||||
|
ulong currentSector = base.CurrentSector;
|
||||||
|
if (_encryptor == null)
|
||||||
|
{
|
||||||
|
_encryptor = _xts.CreateEncryptor();
|
||||||
|
}
|
||||||
|
int count2 = _encryptor.TransformBlock(buffer, offset, count, _tempBuffer, 0, currentSector);
|
||||||
|
base.Write(_tempBuffer, 0, count2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
ValidateSize(count);
|
||||||
|
ulong currentSector = base.CurrentSector;
|
||||||
|
int num = base.Read(_tempBuffer, 0, count);
|
||||||
|
if (num == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (_decryptor == null)
|
||||||
|
{
|
||||||
|
_decryptor = _xts.CreateDecryptor();
|
||||||
|
}
|
||||||
|
return _decryptor.TransformBlock(_tempBuffer, 0, num, buffer, offset, currentSector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace XTSSharp
|
namespace XTSSharp;
|
||||||
|
|
||||||
|
public class XtsStream : RandomAccessSectorStream
|
||||||
{
|
{
|
||||||
public class XtsStream : RandomAccessSectorStream
|
public XtsStream(Stream baseStream, Xts xts)
|
||||||
|
: this(baseStream, xts, 512)
|
||||||
{
|
{
|
||||||
public XtsStream(Stream baseStream, Xts xts)
|
}
|
||||||
: this(baseStream, xts, 512)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public XtsStream(Stream baseStream, Xts xts, int sectorSize)
|
public XtsStream(Stream baseStream, Xts xts, int sectorSize)
|
||||||
: base(new XtsSectorStream(baseStream, xts, sectorSize), true)
|
: base(new XtsSectorStream(baseStream, xts, sectorSize), true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public XtsStream(Stream baseStream, Xts xts, int sectorSize, long offset)
|
public XtsStream(Stream baseStream, Xts xts, int sectorSize, long offset)
|
||||||
: base(new XtsSectorStream(baseStream, xts, sectorSize, offset), true)
|
: base(new XtsSectorStream(baseStream, xts, sectorSize, offset), true)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue