From b6499a6c12e3f99c06ff3ced01bdb3c351f436d1 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 11 Oct 2020 23:47:26 -0700 Subject: [PATCH] Rename IsEmpty to IsZeros Renames the IsEmpty() functions that check if an array is all zeros. This helps avoid confusion because Span has an IsEmpty property that returns true if the span's length is 0. The change actually revealed a tiny bug in KeyDerivation where the property was accidentally used instead of the function. --- build/CodeGen/Stage2/KeysCodeGen.cs | 2 +- src/LibHac/Boot/KeyBlob.cs | 4 +- src/LibHac/Boot/Package1.cs | 2 +- src/LibHac/Common/Keys/ExternalKeyWriter.cs | 4 +- src/LibHac/Common/Keys/KeyDerivation.cs | 72 +++++++++---------- src/LibHac/Crypto/KeyTypes.cs | 8 +-- .../FsSystem/IntegrityVerificationStorage.cs | 6 +- src/LibHac/FsSystem/NcaUtils/Nca.cs | 8 +-- src/LibHac/FsSystem/NcaUtils/NcaHeader.cs | 2 +- .../FsSystem/Save/SaveDataFileSystem.cs | 2 +- src/LibHac/Utilities.cs | 6 +- src/LibHac/XciHeader.cs | 2 +- 12 files changed, 59 insertions(+), 59 deletions(-) diff --git a/build/CodeGen/Stage2/KeysCodeGen.cs b/build/CodeGen/Stage2/KeysCodeGen.cs index 89bf7489..4077ba5a 100644 --- a/build/CodeGen/Stage2/KeysCodeGen.cs +++ b/build/CodeGen/Stage2/KeysCodeGen.cs @@ -61,7 +61,7 @@ namespace LibHacBuild.CodeGen.Stage2 sb.AppendSpacerLine(); sb.Append($"private static ReadOnlySpan {name} => new byte[]"); - if (data.IsEmpty()) + if (data.IsZeros()) { sb.AppendLine(" { };"); return; diff --git a/src/LibHac/Boot/KeyBlob.cs b/src/LibHac/Boot/KeyBlob.cs index fc006a2c..ca1d485a 100644 --- a/src/LibHac/Boot/KeyBlob.cs +++ b/src/LibHac/Boot/KeyBlob.cs @@ -30,7 +30,7 @@ namespace LibHac.Boot public readonly ReadOnlySpan ReadOnlyBytes => SpanHelpers.AsReadOnlyByteSpan(in this); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly bool IsEmpty() + public readonly bool IsZeros() { ReadOnlySpan ulongSpan = MemoryMarshal.Cast(ReadOnlyBytes); @@ -70,7 +70,7 @@ namespace LibHac.Boot public readonly ReadOnlySpan ReadOnlyBytes => SpanHelpers.AsReadOnlyByteSpan(in this); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly bool IsEmpty() + public readonly bool IsZeros() { ReadOnlySpan ulongSpan = MemoryMarshal.Cast(ReadOnlyBytes); diff --git a/src/LibHac/Boot/Package1.cs b/src/LibHac/Boot/Package1.cs index 0e93c426..93660663 100644 --- a/src/LibHac/Boot/Package1.cs +++ b/src/LibHac/Boot/Package1.cs @@ -354,7 +354,7 @@ namespace LibHac.Boot // MarikoOemHeader must be read first private bool IsMarikoImpl() { - return MarikoOemHeader.AesMac.IsEmpty() && MarikoOemHeader.Reserved.IsEmpty(); + return MarikoOemHeader.AesMac.IsZeros() && MarikoOemHeader.Reserved.IsZeros(); } /// diff --git a/src/LibHac/Common/Keys/ExternalKeyWriter.cs b/src/LibHac/Common/Keys/ExternalKeyWriter.cs index c284935e..0351846c 100644 --- a/src/LibHac/Common/Keys/ExternalKeyWriter.cs +++ b/src/LibHac/Common/Keys/ExternalKeyWriter.cs @@ -56,7 +56,7 @@ namespace LibHac.Common.Keys if (info.RangeType == RangeType.Single) { Span key = info.Getter(keySet, 0); - if (key.IsEmpty()) + if (key.IsZeros()) continue; if (isNewGroup) @@ -78,7 +78,7 @@ namespace LibHac.Common.Keys for (int i = info.RangeStart; i < info.RangeEnd; i++) { Span key = info.Getter(keySet, i); - if (key.IsEmpty()) + if (key.IsZeros()) continue; if (hasPrintedKey == false) diff --git a/src/LibHac/Common/Keys/KeyDerivation.cs b/src/LibHac/Common/Keys/KeyDerivation.cs index 13bb44d8..d01b8cdc 100644 --- a/src/LibHac/Common/Keys/KeyDerivation.cs +++ b/src/LibHac/Common/Keys/KeyDerivation.cs @@ -26,14 +26,14 @@ namespace LibHac.Common.Keys private static void DeriveKeyBlobKeys(KeySet s) { - if (s.SecureBootKey.IsEmpty() || s.TsecKey.IsEmpty()) return; + if (s.SecureBootKey.IsZeros() || s.TsecKey.IsZeros()) return; - bool haveKeyBlobMacKeySource = !s.MasterKeySource.IsEmpty(); + bool haveKeyBlobMacKeySource = !s.MasterKeySource.IsZeros(); var temp = new AesKey(); for (int i = 0; i < KeySet.UsedKeyBlobCount; i++) { - if (s.KeyBlobKeySources[i].IsEmpty()) continue; + if (s.KeyBlobKeySources[i].IsZeros()) continue; Aes.DecryptEcb128(s.KeyBlobKeySources[i], temp, s.TsecKey); Aes.DecryptEcb128(temp, s.KeyBlobKeys[i], s.SecureBootKey); @@ -50,7 +50,7 @@ namespace LibHac.Common.Keys for (int i = 0; i < KeySet.UsedKeyBlobCount; i++) { - if (s.KeyBlobKeys[i].IsEmpty() || s.KeyBlobMacKeys[i].IsEmpty() || s.EncryptedKeyBlobs[i].IsEmpty()) + if (s.KeyBlobKeys[i].IsZeros() || s.KeyBlobMacKeys[i].IsZeros() || s.EncryptedKeyBlobs[i].IsZeros()) { continue; } @@ -71,7 +71,7 @@ namespace LibHac.Common.Keys { for (int i = 0; i < KeySet.UsedKeyBlobCount; i++) { - if (s.KeyBlobs[i].IsEmpty()) continue; + if (s.KeyBlobs[i].IsZeros()) continue; s.MasterKeks[i] = s.KeyBlobs[i].MasterKek; s.Package1Keys[i] = s.KeyBlobs[i].Package1Key; @@ -80,13 +80,13 @@ namespace LibHac.Common.Keys private static void Derive620Keys(KeySet s) { - bool haveTsecRootKek = !s.TsecRootKek.IsEmpty(); - bool havePackage1MacKek = !s.Package1MacKek.IsEmpty(); - bool havePackage1Kek = !s.Package1Kek.IsEmpty(); + bool haveTsecRootKek = !s.TsecRootKek.IsZeros(); + bool havePackage1MacKek = !s.Package1MacKek.IsZeros(); + bool havePackage1Kek = !s.Package1Kek.IsZeros(); for (int i = KeySet.UsedKeyBlobCount; i < KeySet.KeyRevisionCount; i++) { - if (s.TsecAuthSignatures[i - KeySet.UsedKeyBlobCount].IsEmpty()) + if (s.TsecAuthSignatures[i - KeySet.UsedKeyBlobCount].IsZeros()) continue; if (haveTsecRootKek) @@ -114,7 +114,7 @@ namespace LibHac.Common.Keys { // Key revisions >= 8 all use the same TSEC root key int tsecRootKeyIndex = Math.Min(i, 8) - KeySet.UsedKeyBlobCount; - if (s.TsecRootKeys[tsecRootKeyIndex].IsEmpty() || s.MasterKekSources[i].IsEmpty()) continue; + if (s.TsecRootKeys[tsecRootKeyIndex].IsZeros() || s.MasterKekSources[i].IsZeros()) continue; Aes.DecryptEcb128(s.MasterKekSources[i], s.MasterKeks[i], s.TsecRootKeys[tsecRootKeyIndex]); } @@ -122,11 +122,11 @@ namespace LibHac.Common.Keys private static void DeriveMarikoMasterKeks(KeySet s) { - if (s.MarikoKek.IsEmpty()) return; + if (s.MarikoKek.IsZeros()) return; for (int i = 0; i < KeySet.KeyRevisionCount; i++) { - if (s.MarikoMasterKekSources[i].IsEmpty()) continue; + if (s.MarikoMasterKekSources[i].IsZeros()) continue; Aes.DecryptEcb128(s.MarikoMasterKekSources[i], s.MasterKeks[i], s.MarikoKek); } @@ -134,11 +134,11 @@ namespace LibHac.Common.Keys private static void DeriveMasterKeys(KeySet s) { - if (s.MasterKeySource.IsEmpty()) return; + if (s.MasterKeySource.IsZeros()) return; for (int i = 0; i < KeySet.KeyRevisionCount; i++) { - if (s.MasterKeks[i].IsEmpty()) continue; + if (s.MasterKeks[i].IsZeros()) continue; Aes.DecryptEcb128(s.MasterKeySource, s.MasterKeys[i], s.MasterKeks[i]); } @@ -153,7 +153,7 @@ namespace LibHac.Common.Keys for (int i = keyVectors.Length - 1; i >= 0; i--) { - if (!s.MasterKeys[i].IsEmpty()) + if (!s.MasterKeys[i].IsZeros()) { newestMasterKey = i; break; @@ -196,7 +196,7 @@ namespace LibHac.Common.Keys Aes.DecryptEcb128(keyVectors[0], key, key); // If we don't get zeros, MasterKeys[generation] is incorrect - return key.IsEmpty(); + return key.IsZeros(); } private static ReadOnlySpan MasterKeyVectors(KeySet s) => @@ -240,7 +240,7 @@ namespace LibHac.Common.Keys var kek = new AesKey(); // Derive the device key - if (!s.PerConsoleKeySource.IsEmpty() && !s.KeyBlobKeys[0].IsEmpty()) + if (!s.PerConsoleKeySource.IsZeros() && !s.KeyBlobKeys[0].IsZeros()) { Aes.DecryptEcb128(s.PerConsoleKeySource, s.DeviceKey, s.KeyBlobKeys[0]); } @@ -248,8 +248,8 @@ namespace LibHac.Common.Keys // Derive device-unique save keys for (int i = 0; i < s.DeviceUniqueSaveMacKeySources.Length; i++) { - if (!s.DeviceUniqueSaveMacKekSource.IsEmpty() && !s.DeviceUniqueSaveMacKeySources[i].IsEmpty() && - !s.DeviceKey.IsEmpty()) + if (!s.DeviceUniqueSaveMacKekSource.IsZeros() && !s.DeviceUniqueSaveMacKeySources[i].IsZeros() && + !s.DeviceKey.IsZeros()) { GenerateKek(s.DeviceKey, s.DeviceUniqueSaveMacKekSource, kek, s.AesKekGenerationSource, null); Aes.DecryptEcb128(s.DeviceUniqueSaveMacKeySources[i], s.DeviceUniqueSaveMacKeys[i], kek); @@ -257,44 +257,44 @@ namespace LibHac.Common.Keys } // Derive BIS keys - if (s.DeviceKey.IsEmpty() - || s.BisKekSource.IsEmpty() - || s.AesKekGenerationSource.IsEmpty() - || s.AesKeyGenerationSource.IsEmpty() - || s.RetailSpecificAesKeySource.IsEmpty()) + if (s.DeviceKey.IsZeros() + || s.BisKekSource.IsZeros() + || s.AesKekGenerationSource.IsZeros() + || s.AesKeyGenerationSource.IsZeros() + || s.RetailSpecificAesKeySource.IsZeros()) { return; } // If the user doesn't provide bis_key_source_03 we can assume it's the same as bis_key_source_02 - if (s.BisKeySources[3].IsEmpty() && !s.BisKeySources[2].IsEmpty()) + if (s.BisKeySources[3].IsZeros() && !s.BisKeySources[2].IsZeros()) { s.BisKeySources[3] = s.BisKeySources[2]; } Aes.DecryptEcb128(s.RetailSpecificAesKeySource, kek, s.DeviceKey); - if (!s.BisKeySources[0].IsEmpty()) Aes.DecryptEcb128(s.BisKeySources[0], s.BisKeys[0], kek); + if (!s.BisKeySources[0].IsZeros()) Aes.DecryptEcb128(s.BisKeySources[0], s.BisKeys[0], kek); GenerateKek(s.DeviceKey, s.BisKekSource, kek, s.AesKekGenerationSource, s.AesKeyGenerationSource); for (int i = 1; i < 4; i++) { - if (!s.BisKeySources[i].IsEmpty()) + if (!s.BisKeySources[i].IsZeros()) Aes.DecryptEcb128(s.BisKeySources[i], s.BisKeys[i], kek); } } private static void DerivePerFirmwareKeys(KeySet s) { - bool haveKakSource0 = !s.KeyAreaKeyApplicationSource.IsEmpty(); - bool haveKakSource1 = !s.KeyAreaKeyOceanSource.IsEmpty(); - bool haveKakSource2 = !s.KeyAreaKeySystemSource.IsEmpty(); - bool haveTitleKekSource = !s.TitleKekSource.IsEmpty(); - bool havePackage2KeySource = !s.Package2KeySource.IsEmpty(); + bool haveKakSource0 = !s.KeyAreaKeyApplicationSource.IsZeros(); + bool haveKakSource1 = !s.KeyAreaKeyOceanSource.IsZeros(); + bool haveKakSource2 = !s.KeyAreaKeySystemSource.IsZeros(); + bool haveTitleKekSource = !s.TitleKekSource.IsZeros(); + bool havePackage2KeySource = !s.Package2KeySource.IsZeros(); for (int i = 0; i < KeySet.KeyRevisionCount; i++) { - if (s.MasterKeys[i].IsEmpty()) + if (s.MasterKeys[i].IsZeros()) { continue; } @@ -331,7 +331,7 @@ namespace LibHac.Common.Keys private static void DeriveNcaHeaderKey(KeySet s) { - if (s.HeaderKekSource.IsEmpty() || s.HeaderKeySource.IsEmpty() || s.MasterKeys[0].IsEmpty()) return; + if (s.HeaderKekSource.IsZeros() || s.HeaderKeySource.IsZeros() || s.MasterKeys[0].IsZeros()) return; var headerKek = new AesKey(); @@ -362,7 +362,7 @@ namespace LibHac.Common.Keys } // Derive sd card save key - if (!s.SeedUniqueSaveMacKekSource.IsEmpty() && !s.SeedUniqueSaveMacKeySource.IsEmpty()) + if (!s.SeedUniqueSaveMacKekSource.IsZeros() && !s.SeedUniqueSaveMacKeySource.IsZeros()) { var keySource = new AesKey(); @@ -383,7 +383,7 @@ namespace LibHac.Common.Keys Aes.DecryptEcb128(kekSeed, kek, key); Aes.DecryptEcb128(src, srcKek, kek); - if (!keySeed.IsEmpty) + if (!keySeed.IsZeros()) { Aes.DecryptEcb128(keySeed, dest, srcKek); } diff --git a/src/LibHac/Crypto/KeyTypes.cs b/src/LibHac/Crypto/KeyTypes.cs index 17c2d396..a0efe4b1 100644 --- a/src/LibHac/Crypto/KeyTypes.cs +++ b/src/LibHac/Crypto/KeyTypes.cs @@ -22,7 +22,7 @@ namespace LibHac.Crypto public readonly ReadOnlySpan DataRo64 => SpanHelpers.CreateReadOnlySpan(in _ulong, Size / sizeof(ulong)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly bool IsEmpty() => (DataRo64[0] | DataRo64[1]) == 0; + public readonly bool IsZeros() => (DataRo64[0] | DataRo64[1]) == 0; public static implicit operator Span(in AesKey value) => Unsafe.AsRef(in value).Data; @@ -58,7 +58,7 @@ namespace LibHac.Crypto public static implicit operator ReadOnlySpan(in AesXtsKey value) => value.DataRo; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly bool IsEmpty() => (DataRo64[0] | DataRo64[1] | DataRo64[2] | DataRo64[3]) == 0; + public readonly bool IsZeros() => (DataRo64[0] | DataRo64[1] | DataRo64[2] | DataRo64[3]) == 0; public override readonly string ToString() => DataRo.ToHexString(); } @@ -78,7 +78,7 @@ namespace LibHac.Crypto public readonly ReadOnlySpan DataRo64 => SpanHelpers.CreateReadOnlySpan(in _ulong, Size / sizeof(ulong)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly bool IsEmpty() => (DataRo64[0] | DataRo64[1]) == 0; + public readonly bool IsZeros() => (DataRo64[0] | DataRo64[1]) == 0; public static implicit operator Span(in AesIv value) => Unsafe.AsRef(in value).Data; public static implicit operator ReadOnlySpan(in AesIv value) => value.DataRo; @@ -105,7 +105,7 @@ namespace LibHac.Crypto public readonly ReadOnlySpan DataRo64 => SpanHelpers.CreateReadOnlySpan(in _ulong, Size / sizeof(ulong)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly bool IsEmpty() => (DataRo64[0] | DataRo64[1]) == 0; + public readonly bool IsZeros() => (DataRo64[0] | DataRo64[1]) == 0; public static implicit operator Span(in AesCmac value) => Unsafe.AsRef(in value).Data; public static implicit operator ReadOnlySpan(in AesCmac value) => value.DataRo; diff --git a/src/LibHac/FsSystem/IntegrityVerificationStorage.cs b/src/LibHac/FsSystem/IntegrityVerificationStorage.cs index f59e955e..08290340 100644 --- a/src/LibHac/FsSystem/IntegrityVerificationStorage.cs +++ b/src/LibHac/FsSystem/IntegrityVerificationStorage.cs @@ -63,7 +63,7 @@ namespace LibHac.FsSystem if (Type == IntegrityStorageType.Save) { - if (Utilities.IsEmpty(hashBuffer)) + if (Utilities.IsZeros(hashBuffer)) { destination.Clear(); BlockValidities[blockIndex] = Validity.Valid; @@ -144,7 +144,7 @@ namespace LibHac.FsSystem source.CopyTo(dataBuffer); byte[] hash = DoHash(dataBuffer, 0, toWrite); - if (Type == IntegrityStorageType.Save && source.IsEmpty()) + if (Type == IntegrityStorageType.Save && source.IsZeros()) { Array.Clear(hash, 0, DigestSize); } @@ -207,7 +207,7 @@ namespace LibHac.FsSystem long hashPos = i * DigestSize; HashStorage.Read(hashPos, digest).ThrowIfFailure(); - if (!Utilities.IsEmpty(digest)) continue; + if (!Utilities.IsZeros(digest)) continue; int dataOffset = i * SectorSize; BaseStorage.Fill(SaveDataFileSystem.TrimFillValue, dataOffset, SectorSize); diff --git a/src/LibHac/FsSystem/NcaUtils/Nca.cs b/src/LibHac/FsSystem/NcaUtils/Nca.cs index 67ad92fa..85650784 100644 --- a/src/LibHac/FsSystem/NcaUtils/Nca.cs +++ b/src/LibHac/FsSystem/NcaUtils/Nca.cs @@ -45,7 +45,7 @@ namespace LibHac.FsSystem.NcaUtils int keyRevision = Utilities.GetMasterKeyRevision(Header.KeyGeneration); byte[] keyAreaKey = KeySet.KeyAreaKeys[keyRevision][Header.KeyAreaKeyIndex].DataRo.ToArray(); - if (keyAreaKey.IsEmpty()) + if (keyAreaKey.IsZeros()) { string keyName = $"key_area_key_{KakNames[Header.KeyAreaKeyIndex]}_{keyRevision:x2}"; throw new MissingKeyException("Unable to decrypt NCA section.", keyName, KeyType.Common); @@ -73,7 +73,7 @@ namespace LibHac.FsSystem.NcaUtils throw new MissingKeyException("Missing NCA title key.", rightsId.ToString(), KeyType.Title); } - if (titleKek.IsEmpty()) + if (titleKek.IsZeros()) { string keyName = $"titlekek_{keyRevision:x2}"; throw new MissingKeyException("Unable to decrypt title key.", keyName, KeyType.Common); @@ -112,10 +112,10 @@ namespace LibHac.FsSystem.NcaUtils if (Header.HasRightsId) { return KeySet.ExternalKeySet.Contains(new RightsId(Header.RightsId)) && - !KeySet.TitleKeks[keyRevision].IsEmpty(); + !KeySet.TitleKeks[keyRevision].IsZeros(); } - return !KeySet.KeyAreaKeys[keyRevision][Header.KeyAreaKeyIndex].IsEmpty(); + return !KeySet.KeyAreaKeys[keyRevision][Header.KeyAreaKeyIndex].IsZeros(); } public bool SectionExists(NcaSectionType type) diff --git a/src/LibHac/FsSystem/NcaUtils/NcaHeader.cs b/src/LibHac/FsSystem/NcaUtils/NcaHeader.cs index 9c45b79a..521d8e03 100644 --- a/src/LibHac/FsSystem/NcaUtils/NcaHeader.cs +++ b/src/LibHac/FsSystem/NcaUtils/NcaHeader.cs @@ -107,7 +107,7 @@ namespace LibHac.FsSystem.NcaUtils public Span RightsId => _header.Span.Slice(NcaHeaderStruct.RightsIdOffset, NcaHeaderStruct.RightsIdSize); - public bool HasRightsId => !Utilities.IsEmpty(RightsId); + public bool HasRightsId => !Utilities.IsZeros(RightsId); public Span GetKeyArea() { diff --git a/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs b/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs index ffdb6029..50abb275 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs @@ -262,7 +262,7 @@ namespace LibHac.FsSystem.Save headerStream.Position = 0x108; headerStream.Write(hash, 0, hash.Length); - if (keySet == null || keySet.DeviceUniqueSaveMacKeys[0].IsEmpty()) return ResultFs.PreconditionViolation.Log(); + if (keySet == null || keySet.DeviceUniqueSaveMacKeys[0].IsZeros()) return ResultFs.PreconditionViolation.Log(); var cmacData = new byte[0x200]; var cmac = new byte[0x10]; diff --git a/src/LibHac/Utilities.cs b/src/LibHac/Utilities.cs index ad8f0061..25c29df8 100644 --- a/src/LibHac/Utilities.cs +++ b/src/LibHac/Utilities.cs @@ -67,10 +67,10 @@ namespace LibHac return a1.SequenceEqual(a2); } - public static bool IsEmpty(this byte[] array) => ((ReadOnlySpan)array).IsEmpty(); - public static bool IsEmpty(this Span span) => ((ReadOnlySpan)span).IsEmpty(); + public static bool IsZeros(this byte[] array) => ((ReadOnlySpan)array).IsZeros(); + public static bool IsZeros(this Span span) => ((ReadOnlySpan)span).IsZeros(); - public static bool IsEmpty(this ReadOnlySpan span) + public static bool IsZeros(this ReadOnlySpan span) { for (int i = 0; i < span.Length; i++) { diff --git a/src/LibHac/XciHeader.cs b/src/LibHac/XciHeader.cs index b893c375..90ff047b 100644 --- a/src/LibHac/XciHeader.cs +++ b/src/LibHac/XciHeader.cs @@ -108,7 +108,7 @@ namespace LibHac SelKey = reader.ReadInt32(); LimAreaPage = reader.ReadInt32(); - if (keySet != null && !keySet.XciHeaderKey.IsEmpty()) + if (keySet != null && !keySet.XciHeaderKey.IsZeros()) { byte[] encHeader = reader.ReadBytes(EncryptedHeaderSize); var decHeader = new byte[EncryptedHeaderSize];