NdsForge.NET 1.0.1
Read, validate, edit, compare, and build Nintendo DS and DSi images from .NET
Loading...
Searching...
No Matches
NdsModcryptContext.cs
1namespace NdsForge;
2
7public sealed class NdsModcryptContext
8{
10 private readonly byte[] _key;
12 private readonly byte[] _area1Counter;
14 private readonly byte[] _area2Counter;
15
22 ReadOnlySpan<byte> key,
23 ReadOnlySpan<byte> area1Counter,
24 ReadOnlySpan<byte> area2Counter,
25 NdsModcryptKeyMode keyMode = NdsModcryptKeyMode.SecureNormalKey)
26 {
27 ValidateBlock(key, nameof(key));
28 ValidateBlock(area1Counter, nameof(area1Counter));
29 ValidateBlock(area2Counter, nameof(area2Counter));
30 if (!Enum.IsDefined(keyMode))
31 {
32 throw new ArgumentOutOfRangeException(nameof(keyMode), keyMode, "Unknown modcrypt key provenance.");
33 }
34
35 _key = key.ToArray();
36 _area1Counter = area1Counter.ToArray();
37 _area2Counter = area2Counter.ToArray();
38 KeyMode = keyMode;
39 }
40
43
46 public ReadOnlyMemory<byte> ExportKey() => _key.ToArray();
47
51 public ReadOnlyMemory<byte> ExportCounter(NdsModcryptArea area) => GetCounter(area).ToArray();
52
60 {
61 ArgumentNullException.ThrowIfNull(header);
62 NdsDsiHeader dsi = header.Dsi ??
63 throw new ArgumentException("Modcrypt requires a DSi-enhanced or DSi-exclusive header.", nameof(header));
65 {
66 return new(
67 header.RawData.Span[..16],
68 dsi.Arm9Hmac.Span[..16],
69 dsi.Arm7Hmac.Span[..16],
70 NdsModcryptKeyMode.InsecureHeaderKey);
71 }
72
73 return new(
75 dsi.Arm9Hmac.Span[..16],
76 dsi.Arm7Hmac.Span[..16],
77 NdsModcryptKeyMode.SecureNormalKey);
78 }
79
87 public static NdsModcryptContext FromHeader(NdsHeader header, ReadOnlySpan<byte> secureNormalKey)
88 {
89 ArgumentNullException.ThrowIfNull(header);
90 NdsDsiHeader dsi = header.Dsi ??
91 throw new ArgumentException("Modcrypt requires a DSi-enhanced or DSi-exclusive header.", nameof(header));
93 {
94 throw new ArgumentException(
95 "A header selecting its public modcrypt key cannot accept a secure-key override.",
96 nameof(header));
97 }
98
99 ValidateBlock(secureNormalKey, nameof(secureNormalKey));
100 return new(
101 secureNormalKey,
102 dsi.Arm9Hmac.Span[..16],
103 dsi.Arm7Hmac.Span[..16],
104 NdsModcryptKeyMode.SecureNormalKey);
105 }
106
108 internal ReadOnlyMemory<byte> Key => _key;
109
113 internal ReadOnlyMemory<byte> GetCounter(NdsModcryptArea area) => area switch
114 {
115 NdsModcryptArea.First => _area1Counter,
116 NdsModcryptArea.Second => _area2Counter,
117 _ => throw new ArgumentOutOfRangeException(nameof(area), area, "Unknown modcrypt area."),
118 };
119
123 private static void ValidateBlock(ReadOnlySpan<byte> value, string parameterName)
124 {
125 if (value.Length != NdsModcrypt.BlockSize)
126 {
127 throw new ArgumentException("A modcrypt key or counter must contain exactly sixteen bytes.", parameterName);
128 }
129 }
130}
Projects DSi security, digest, memory, title, and save metadata while preserving the complete extensi...
bool UsesInsecureModcryptKey
Indicates that modcrypt uses the public first sixteen header bytes instead of a securely derived norm...
ReadOnlyMemory< byte > Arm9Hmac
Contains the 20-byte SHA-1 HMAC authenticating the common ARM9 payload; no key-validity claim is impl...
ReadOnlyMemory< byte > Arm7Hmac
Contains the 20-byte SHA-1 HMAC authenticating the common ARM7 payload; no key-validity claim is impl...
Implements the DSi 128-bit KeyX/KeyY scrambler in cartridge-register byte order. It contains only the...
static byte[] DeriveModcryptNormalKey(NdsHeader header)
Derives the secure modcrypt normal key from the common game code and the first sixteen ARM9i HMAC byt...
Projects the common cartridge header into typed fields while retaining every byte needed for lossless...
Definition NdsHeader.cs:5
ReadOnlyMemory< byte > RawData
Preserves reserved and currently unmodeled fields for byte-exact extraction and copy-on-write editing...
Definition NdsHeader.cs:50
NdsModcryptKeyMode KeyMode
Preserves whether the normal key was public header data or supplied by an external secure-key authori...
ReadOnlyMemory< byte > ExportCounter(NdsModcryptArea area)
Returns an independent copy of the initial counter selected for one declared modcrypt area.
ReadOnlyMemory< byte > ExportKey()
Returns an independent copy of the resolved AES key so callers can persist or clear it on their own t...
static NdsModcryptContext FromHeader(NdsHeader header)
Resolves public header-key mode automatically and otherwise derives the normal key from the public mo...
NdsModcryptContext(ReadOnlySpan< byte > key, ReadOnlySpan< byte > area1Counter, ReadOnlySpan< byte > area2Counter, NdsModcryptKeyMode keyMode=NdsModcryptKeyMode.SecureNormalKey)
Copies already resolved key and counter material after enforcing the fixed AES block boundary.
static NdsModcryptContext FromHeader(NdsHeader header, ReadOnlySpan< byte > secureNormalKey)
Uses an explicitly resolved secure normal key instead of applying the built-in modcrypt KeyX/KeyY rec...
NdsModcryptArea
Identifies which DSi modcrypt interval and HMAC-derived initial counter a transformation uses.
@ First
Selects the first interval and the first sixteen bytes of the ARM9 HMAC.
@ Second
Selects the second interval and the first sixteen bytes of the ARM7 HMAC.
NdsModcryptKeyMode
Records whether a modcrypt context came from public header bytes or externally derived secure materia...