diff --git a/build/CodeGen/results.csv b/build/CodeGen/results.csv
index ef973e5e..f9c257ec 100644
--- a/build/CodeGen/results.csv
+++ b/build/CodeGen/results.csv
@@ -1935,3 +1935,10 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary
428,1041,,,,InvalidPackage1SectionSize,
428,1042,,,,InvalidPackage1MarikoBodySize,
428,1043,,,,InvalidPackage1Pk11Size,
+
+428,2000,2199,,,PreconditionViolation,
+428,2001,2019,,,UnsupportedOperation,
+428,2002,,,,UnsupportedCalculateMacForPackage1,The package1 type doesn't support calculating a MAC over its pk11. Only modern Erista package1s support this.
+
+428,2050,2069,,,KeyNotFound,
+428,2051,,,,Package1MacKeyNotFound,
\ No newline at end of file
diff --git a/src/LibHac/Boot/Package1.cs b/src/LibHac/Boot/Package1.cs
index 58199121..3dab974e 100644
--- a/src/LibHac/Boot/Package1.cs
+++ b/src/LibHac/Boot/Package1.cs
@@ -6,10 +6,12 @@ using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Common.FixedArrays;
using LibHac.Common.Keys;
+using LibHac.Crypto;
using LibHac.Diag;
using LibHac.Fs;
using LibHac.Tools.FsSystem;
using LibHac.Util;
+using AesKey = LibHac.Crypto.AesKey;
namespace LibHac.Boot;
@@ -153,6 +155,35 @@ public class Package1
return Result.Success;
}
+ ///
+ /// Calculates the MAC for a modern Erista pk11.
+ ///
+ /// The buffer where the generated MAC will be placed. Must be at least 16 bytes long.
+ /// : The operation was successful.
+ /// : The package1 type does not support calculating
+ /// a MAC over its pk11.
+ /// : The key used to calculate the MAC was not found
+ /// in the .
+ public Result CalculateModernEristaMac(Span macBuffer)
+ {
+ if (IsMariko || !IsModern)
+ return ResultLibHac.UnsupportedCalculateMacForPackage1.Log();
+
+ AesKey macKey = KeySet.Package1MacKeys[KeyRevision];
+ if (macKey.IsZeros())
+ return ResultLibHac.Package1MacKeyNotFound.Log();
+
+ // Todo: Use a smaller buffer instead of reading the entire thing in at once.
+ byte[] macTarget = new byte[Pk11Size + 0x20];
+
+ Result res = _bodyStorage.Read(0x7000 - 0x20, macTarget);
+ if (res.IsFailure()) return res.Miss();
+
+ Aes.CalculateCmac(macBuffer, macTarget, macKey);
+
+ return Result.Success;
+ }
+
///
/// Read the encrypted section of a Mariko Package1 and try to decrypt it.
///
@@ -336,7 +367,7 @@ public class Package1
Assert.SdkRequires(IsDecrypted);
int pk11Size = Unsafe.SizeOf() + GetSectionSize(Package1Section.WarmBoot) +
- GetSectionSize(Package1Section.Bootloader) + GetSectionSize(Package1Section.SecureMonitor);
+ GetSectionSize(Package1Section.Bootloader) + GetSectionSize(Package1Section.SecureMonitor);
pk11Size = Alignment.AlignUp(pk11Size, 0x10);
diff --git a/src/LibHac/Common/Keys/KeyDerivation.cs b/src/LibHac/Common/Keys/KeyDerivation.cs
index b7a017eb..10556fc2 100644
--- a/src/LibHac/Common/Keys/KeyDerivation.cs
+++ b/src/LibHac/Common/Keys/KeyDerivation.cs
@@ -89,7 +89,7 @@ internal static class KeyDerivation
Encryption,
Signature,
Kek,
-
+
// TSEC directly uses the value generated by this (no key derivation) to encrypt pk11's AES IV that's found
// at 0x6FF0 in package1. When decrypting pk11, TSEC will overwrite the unencrypted IV in package1 with the
// encrypted IV.
diff --git a/src/LibHac/Common/ResultLibHac.cs b/src/LibHac/Common/ResultLibHac.cs
index 78b1e71d..e8d388ad 100644
--- a/src/LibHac/Common/ResultLibHac.cs
+++ b/src/LibHac/Common/ResultLibHac.cs
@@ -92,4 +92,16 @@ public static class ResultLibHac
public static Result.Base InvalidPackage1MarikoBodySize => new Result.Base(ModuleLibHac, 1042);
/// Error code: 2428-1043; Inner value: 0x827ac
public static Result.Base InvalidPackage1Pk11Size => new Result.Base(ModuleLibHac, 1043);
+
+ /// Error code: 2428-2000; Range: 2000-2199; Inner value: 0xfa1ac
+ public static Result.Base PreconditionViolation { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleLibHac, 2000, 2199); }
+ /// Error code: 2428-2001; Range: 2001-2019; Inner value: 0xfa3ac
+ public static Result.Base UnsupportedOperation { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleLibHac, 2001, 2019); }
+ /// The package1 type doesn't support calculating a MAC over its pk11. Only modern Erista package1s support this.
Error code: 2428-2002; Inner value: 0xfa5ac
+ public static Result.Base UnsupportedCalculateMacForPackage1 => new Result.Base(ModuleLibHac, 2002);
+
+ /// Error code: 2428-2050; Range: 2050-2069; Inner value: 0x1005ac
+ public static Result.Base KeyNotFound { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleLibHac, 2050, 2069); }
+ /// Error code: 2428-2051; Inner value: 0x1007ac
+ public static Result.Base Package1MacKeyNotFound => new Result.Base(ModuleLibHac, 2051);
}
\ No newline at end of file
diff --git a/src/hactoolnet/ProcessPackage.cs b/src/hactoolnet/ProcessPackage.cs
index ca614a67..b39c70a3 100644
--- a/src/hactoolnet/ProcessPackage.cs
+++ b/src/hactoolnet/ProcessPackage.cs
@@ -1,4 +1,5 @@
-using System.IO;
+using System;
+using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using LibHac;
@@ -82,7 +83,22 @@ internal static class ProcessPackage
if (!package1.IsMariko && package1.IsModern)
{
- PrintItem(sb, colLen, " PK11 MAC:", package1.Pk11Mac.ItemsRo.ToArray());
+ string validity = "";
+
+ Span mac = stackalloc byte[0x10];
+ Result res = package1.CalculateModernEristaMac(mac);
+
+ if (res.IsFailure())
+ {
+ if (!ResultLibHac.Package1MacKeyNotFound.Includes(res))
+ res.ThrowIfFailure();
+ }
+ else
+ {
+ validity = mac.SequenceEqual(package1.Pk11Mac) ? " (Valid)" : " (Invalid)";
+ }
+
+ PrintItem(sb, colLen, $" PK11 MAC:{validity}", package1.Pk11Mac.ItemsRo.ToArray());
}
if (package1.IsDecrypted)
@@ -91,7 +107,7 @@ internal static class ProcessPackage
if (!package1.IsMariko)
{
- PrintItem(sb, colLen, " Key Revision:", $"{package1.KeyRevision:x2} ({Utilities.GetKeyRevisionSummary(package1.KeyRevision)})");
+ PrintItem(sb, colLen, " Key Revision:", $"{package1.KeyRevision:x2}");
}
PrintItem(sb, colLen, " PK11 Size:", $"{package1.Pk11Size:x8}");