Simplify Guid reading/writing code in DataProtection (#36403)

Simplify Guid reading/writing code in DataProtection.
This commit is contained in:
Aditya Mandaleeka 2021-09-17 16:16:35 -07:00 коммит произвёл GitHub
Родитель bb0cde1935
Коммит 8392779338
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 27 добавлений и 59 удалений

Просмотреть файл

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.AspNetCore.Cryptography;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
@ -128,7 +129,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
fixed (byte* pbRetVal = retVal)
{
WriteBigEndianInteger(pbRetVal, MAGIC_HEADER_V0);
Write32bitAlignedGuid(&pbRetVal[sizeof(uint)], defaultKeyId);
WriteGuid(&pbRetVal[sizeof(uint)], defaultKeyId);
}
// At this point, retVal := { magicHeader || keyId || encryptorSpecificProtectedPayload }
@ -142,36 +143,17 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
}
}
// Helper function to read a GUID from a 32-bit alignment; useful on architectures where unaligned reads
// can result in weird behaviors at runtime.
private static Guid Read32bitAlignedGuid(void* ptr)
private static Guid ReadGuid(void* ptr)
{
Debug.Assert((long)ptr % 4 == 0);
Guid retVal;
if (BitConverter.IsLittleEndian)
{
((int*)&retVal)[0] = ((int*)ptr)[0];
((int*)&retVal)[1] = ((int*)ptr)[1];
((int*)&retVal)[2] = ((int*)ptr)[2];
((int*)&retVal)[3] = ((int*)ptr)[3];
}
else
{
// The first 8 bytes of the Guid hold one 32-bit integer
// and two 16-bit integers that must be byte-swapped.
((byte*)&retVal)[0] = ((byte*)ptr)[3];
((byte*)&retVal)[1] = ((byte*)ptr)[2];
((byte*)&retVal)[2] = ((byte*)ptr)[1];
((byte*)&retVal)[3] = ((byte*)ptr)[0];
((byte*)&retVal)[4] = ((byte*)ptr)[5];
((byte*)&retVal)[5] = ((byte*)ptr)[4];
((byte*)&retVal)[6] = ((byte*)ptr)[7];
((byte*)&retVal)[7] = ((byte*)ptr)[6];
((int*)&retVal)[2] = ((int*)ptr)[2];
((int*)&retVal)[3] = ((int*)ptr)[3];
}
return retVal;
#if NETCOREAPP
// Performs appropriate endianness fixups
return new Guid(new ReadOnlySpan<byte>(ptr, sizeof(Guid)));
#elif NETSTANDARD2_0 || NETFRAMEWORK
Debug.Assert(BitConverter.IsLittleEndian);
return Unsafe.ReadUnaligned<Guid>(ptr);
#else
#error Update target frameworks
#endif
}
private static uint ReadBigEndian32BitInteger(byte* ptr)
@ -233,7 +215,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
fixed (byte* pbInput = protectedData)
{
magicHeaderFromPayload = ReadBigEndian32BitInteger(pbInput);
keyIdFromPayload = Read32bitAlignedGuid(&pbInput[sizeof(uint)]);
keyIdFromPayload = ReadGuid(&pbInput[sizeof(uint)]);
}
// Are the magic header and version information correct?
@ -318,34 +300,20 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
}
}
// Helper function to write a GUID to a 32-bit alignment; useful on ARM where unaligned reads
// can result in weird behaviors at runtime.
private static void Write32bitAlignedGuid(void* ptr, Guid value)
private static void WriteGuid(void* ptr, Guid value)
{
Debug.Assert((long)ptr % 4 == 0);
#if NETCOREAPP
var span = new Span<byte>(ptr, sizeof(Guid));
if (BitConverter.IsLittleEndian)
{
((int*)ptr)[0] = ((int*)&value)[0];
((int*)ptr)[1] = ((int*)&value)[1];
((int*)ptr)[2] = ((int*)&value)[2];
((int*)ptr)[3] = ((int*)&value)[3];
}
else
{
// The first 8 bytes of the Guid hold one 32-bit integer
// and two 16-bit integers that must be byte-swapped.
((byte*)ptr)[0] = ((byte*)&value)[3];
((byte*)ptr)[1] = ((byte*)&value)[2];
((byte*)ptr)[2] = ((byte*)&value)[1];
((byte*)ptr)[3] = ((byte*)&value)[0];
((byte*)ptr)[4] = ((byte*)&value)[5];
((byte*)ptr)[5] = ((byte*)&value)[4];
((byte*)ptr)[6] = ((byte*)&value)[7];
((byte*)ptr)[7] = ((byte*)&value)[6];
((int*)ptr)[2] = ((int*)&value)[2];
((int*)ptr)[3] = ((int*)&value)[3];
}
// Performs appropriate endianness fixups
var success = value.TryWriteBytes(span);
Debug.Assert(success, "Failed to write Guid.");
#elif NETSTANDARD2_0 || NETFRAMEWORK
Debug.Assert(BitConverter.IsLittleEndian);
Unsafe.WriteUnaligned<Guid>(ptr, value);
#else
#error Update target frameworks
#endif
}
private static void WriteBigEndianInteger(byte* ptr, uint value)
@ -402,7 +370,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
// The caller will not mutate it.
fixed (byte* pExistingTemplate = existingTemplate)
{
if (Read32bitAlignedGuid(&pExistingTemplate[sizeof(uint)]) == keyId)
if (ReadGuid(&pExistingTemplate[sizeof(uint)]) == keyId)
{
return existingTemplate;
}
@ -415,7 +383,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
byte[] newTemplate = (byte[])existingTemplate.Clone();
fixed (byte* pNewTemplate = newTemplate)
{
Write32bitAlignedGuid(&pNewTemplate[sizeof(uint)], keyId);
WriteGuid(&pNewTemplate[sizeof(uint)], keyId);
if (isProtecting)
{
Volatile.Write(ref _aadTemplate, newTemplate);