fix HMAC in PassStoreContentChunk

This commit is contained in:
2025-12-01 00:37:06 +03:00
parent 3492fa1cd0
commit fecab564b7

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.IO; using System.IO;
using System.Security.Cryptography; using System.Security.Cryptography;
@@ -37,7 +38,7 @@ public class PassStoreContentChunk
try try
{ {
chunkLen = rd.ReadUInt16(); chunkLen = rd.ReadUInt16();
chunkLen = (chunkLen << 8) | rd.ReadByte(); chunkLen = chunkLen | (rd.ReadByte() << 16);
} }
catch (EndOfStreamException) catch (EndOfStreamException)
{ {
@@ -52,16 +53,28 @@ public class PassStoreContentChunk
byte[] storedHmac = new byte[HMAC_SIZE]; byte[] storedHmac = new byte[HMAC_SIZE];
str.Read(storedHmac, 0, HMAC_SIZE); str.Read(storedHmac, 0, HMAC_SIZE);
HMACSHA3_512 hmac = new(key); SHA3_512 hasher = SHA3_512.Create();
hmac.TransformBlock(chunk, (int)str.Position, Math.Min(chunkLen, chunk.Length - (int)str.Position), null, 0); byte[] innerKey = key.Select(x => (byte)(x ^ 0x36)).ToArray();
byte[] outerKey = key.Select(x => (byte)(x ^ 0x5c)).ToArray();
hasher.TransformBlock(innerKey, 0, innerKey.Length, null, 0);
Array.Fill<byte>(innerKey, 0); // erase key after use
hasher.TransformBlock(chunk, (int)str.Position, chunk.Length - (int)str.Position, null, 0);
byte[] encodedOrdinal = new byte[sizeof(int)]; byte[] encodedOrdinal = new byte[sizeof(int)];
BinaryPrimitives.WriteInt32LittleEndian(new Span<byte>(encodedOrdinal), chunkOrdinal); BinaryPrimitives.WriteInt32LittleEndian(new Span<byte>(encodedOrdinal), chunkOrdinal);
hmac.TransformBlock(encodedOrdinal, 0, encodedOrdinal.Length, null, 0);
byte[] actualHmac = hmac.Hash!; hasher.TransformFinalBlock(encodedOrdinal, 0, encodedOrdinal.Length);
byte[] innerHash = hasher.Hash!;
if (!storedHmac.Equals(actualHmac)) hasher = SHA3_512.Create();
hasher.TransformBlock(outerKey, 0, outerKey.Length, null, 0);
Array.Fill<byte>(outerKey, 0);
hasher.TransformFinalBlock(innerHash, 0, innerHash.Length);
byte[] actualHmac = hasher.Hash!;
if (!storedHmac.SequenceEqual(actualHmac))
{ {
throw PassStoreFileException.ContentHMACMismatch; throw PassStoreFileException.ContentHMACMismatch;
} }