diff --git a/NDecrypt.Core/PartitionKeys.cs b/NDecrypt.Core/PartitionKeys.cs
index 75f300a..65d7c66 100644
--- a/NDecrypt.Core/PartitionKeys.cs
+++ b/NDecrypt.Core/PartitionKeys.cs
@@ -9,61 +9,31 @@ namespace NDecrypt.Core
///
public class PartitionKeys
{
- public byte[] KeyX { get; private set; }
-
- public byte[] KeyX2C { get; }
-
- public byte[] KeyY { get; }
-
public byte[] NormalKey { get; private set; }
public byte[] NormalKey2C { get; }
- ///
- /// Decryption args to use while processing
- ///
- private readonly ThreeDSDecryptArgs _decryptArgs;
-
- ///
- /// Indicates if development images are expected
- ///
- private readonly bool _development;
+ private readonly byte[] KeyY;
///
/// Create a new set of keys for a given partition
///
- /// Decryption args representing available keys
/// RSA-2048 signature from the partition
/// BitMasks from the partition or backup header
- /// CryptoMethod from the partition or backup header
- /// Determine if development keys are used
- public PartitionKeys(ThreeDSDecryptArgs args, byte[]? signature, BitMasks masks, CryptoMethod method, bool development)
+ /// AES hardware constant to use
+ /// KeyX value to assign based on crypto method and development status
+ /// KeyX value to assign based on development status
+ public PartitionKeys(byte[]? signature, BitMasks masks, byte[] hardwareConstant, byte[] keyX, byte[] keyX0x2C)
{
// Validate inputs
if (signature is not null && signature.Length < 16)
throw new ArgumentOutOfRangeException(nameof(signature), $"{nameof(signature)} must be at least 16 bytes");
- // Set fields for future use
- _decryptArgs = args;
- _development = development;
-
- // Set the standard KeyX values
- KeyX = new byte[16];
- KeyX2C = development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C;
-
// Backup headers can't have a KeyY value set
KeyY = new byte[16];
if (signature is not null)
Array.Copy(signature, KeyY, 16);
- // Set the standard normal key values
- NormalKey = new byte[16];
-
- NormalKey2C = KeyX2C.RotateLeft(2);
- NormalKey2C = NormalKey2C.Xor(KeyY);
- NormalKey2C = NormalKey2C.Add(add: _decryptArgs.AESHardwareConstant);
- NormalKey2C = NormalKey2C.RotateLeft(87);
-
// Special case for zero-key
#if NET20 || NET35
if ((masks & BitMasks.FixedCryptoKey) > 0)
@@ -77,46 +47,22 @@ namespace NDecrypt.Core
return;
}
- // Set KeyX values based on crypto method
- switch (method)
- {
- case CryptoMethod.Original:
- Console.WriteLine("Encryption Method: Key 0x2C");
- KeyX = development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C;
- break;
-
- case CryptoMethod.Seven:
- Console.WriteLine("Encryption Method: Key 0x25");
- KeyX = development ? _decryptArgs.DevKeyX0x25 : _decryptArgs.KeyX0x25;
- break;
-
- case CryptoMethod.NineThree:
- Console.WriteLine("Encryption Method: Key 0x18");
- KeyX = development ? _decryptArgs.DevKeyX0x18 : _decryptArgs.KeyX0x18;
- break;
-
- case CryptoMethod.NineSix:
- Console.WriteLine("Encryption Method: Key 0x1B");
- KeyX = development ? _decryptArgs.DevKeyX0x1B : _decryptArgs.KeyX0x1B;
- break;
-
- // This should never happen
- default:
- Console.WriteLine("Encryption Method: UNSUPPORTED");
- break;
- }
-
- // Set the normal key based on the new KeyX value
- NormalKey = KeyX.RotateLeft(2);
+ // Set the standard normal key values
+ NormalKey = keyX.RotateLeft(2);
NormalKey = NormalKey.Xor(KeyY);
- NormalKey = NormalKey.Add(_decryptArgs.AESHardwareConstant);
+ NormalKey = NormalKey.Add(hardwareConstant);
NormalKey = NormalKey.RotateLeft(87);
+
+ NormalKey2C = keyX0x2C.RotateLeft(2);
+ NormalKey2C = NormalKey2C.Xor(KeyY);
+ NormalKey2C = NormalKey2C.Add(hardwareConstant);
+ NormalKey2C = NormalKey2C.RotateLeft(87);
}
///
/// Set RomFS values based on the bit masks
///
- public void SetRomFSValues(BitMasks masks)
+ public void SetRomFSValues(BitMasks masks, byte[] hardwareConstant, byte[] keyX0x2C)
{
// NormalKey has a constant value for zero-key
#if NET20 || NET35
@@ -130,11 +76,9 @@ namespace NDecrypt.Core
}
// Encrypting RomFS for partitions 1 and up always use Key0x2C
- KeyX = _development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C;
-
- NormalKey = KeyX.RotateLeft(2);
+ NormalKey = keyX0x2C.RotateLeft(2);
NormalKey = NormalKey.Xor(KeyY);
- NormalKey = NormalKey.Add(_decryptArgs.AESHardwareConstant);
+ NormalKey = NormalKey.Add(hardwareConstant);
NormalKey = NormalKey.RotateLeft(87);
}
}
diff --git a/NDecrypt.Core/ThreeDSTool.cs b/NDecrypt.Core/ThreeDSTool.cs
index f2d2cfa..445c94c 100644
--- a/NDecrypt.Core/ThreeDSTool.cs
+++ b/NDecrypt.Core/ThreeDSTool.cs
@@ -32,6 +32,40 @@ namespace NDecrypt.Core
_decryptArgs = decryptArgs;
}
+ #region Common
+
+ ///
+ /// Get KeyX value for a crypto method and development status combination
+ ///
+ private byte[] GetKeyXForCryptoMethod(CryptoMethod method)
+ {
+ switch (method)
+ {
+ case CryptoMethod.Original:
+ Console.WriteLine("Encryption Method: Key 0x2C");
+ return _development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C;
+
+ case CryptoMethod.Seven:
+ Console.WriteLine("Encryption Method: Key 0x25");
+ return _development ? _decryptArgs.DevKeyX0x25 : _decryptArgs.KeyX0x25;
+
+ case CryptoMethod.NineThree:
+ Console.WriteLine("Encryption Method: Key 0x18");
+ return _development ? _decryptArgs.DevKeyX0x18 : _decryptArgs.KeyX0x18;
+
+ case CryptoMethod.NineSix:
+ Console.WriteLine("Encryption Method: Key 0x1B");
+ return _development ? _decryptArgs.DevKeyX0x1B : _decryptArgs.KeyX0x1B;
+
+ // This should never happen
+ default:
+ Console.WriteLine("Encryption Method: UNSUPPORTED");
+ return [];
+ }
+ }
+
+ #endregion
+
#region Decrypt
///
@@ -165,12 +199,15 @@ namespace NDecrypt.Core
return;
// Get partition-specific values
- byte[]? rsaSignature = partition.RSA2048Signature;
+ byte[]? signature = partition.RSA2048Signature;
BitMasks masks = cart.GetBitMasks(index);
CryptoMethod method = cart.GetCryptoMethod(index);
// Get the partition keys
- _keysMap[index] = new PartitionKeys(_decryptArgs, rsaSignature, masks, method, _development);
+ byte[] hardwareConstant = _decryptArgs.AESHardwareConstant;
+ byte[] keyX = GetKeyXForCryptoMethod(method);
+ byte[] keyX0x2C = _development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C;
+ _keysMap[index] = new PartitionKeys(signature, masks, hardwareConstant, keyX, keyX0x2C);
}
///
@@ -583,12 +620,15 @@ namespace NDecrypt.Core
return;
// Get partition-specific values
- byte[]? rsaSignature = partition.RSA2048Signature;
+ byte[]? signature = partition.RSA2048Signature;
BitMasks masks = backupHeader.Flags.BitMasks;
CryptoMethod method = backupHeader.Flags.CryptoMethod;
// Get the partition keys
- _keysMap[index] = new PartitionKeys(_decryptArgs, rsaSignature, masks, method, _development);
+ byte[] hardwareConstant = _decryptArgs.AESHardwareConstant;
+ byte[] keyX = GetKeyXForCryptoMethod(method);
+ byte[] keyX0x2C = _development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C;
+ _keysMap[index] = new PartitionKeys(signature, masks, hardwareConstant, keyX, keyX0x2C);
}
///
@@ -820,7 +860,9 @@ namespace NDecrypt.Core
if (index > 0)
{
var backupHeader = cart.BackupHeader;
- _keysMap[index].SetRomFSValues(backupHeader!.Flags!.BitMasks);
+ _keysMap[index].SetRomFSValues(backupHeader.Flags.BitMasks,
+ hardwareConstant: _decryptArgs.AESHardwareConstant,
+ keyX0x2C: _development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C);
}
// Create the RomFS AES cipher for this partition