private bool AddKeyValue(byte[] key, TValue value) { // lock(cs) required. var table = this.hashTable; var hash = unchecked ((int)FarmHash.Hash64(key)); var h = hash & (table.Length - 1); if (table[h] == null) { var item = new Item(key, value, hash); System.Threading.Volatile.Write(ref table[h], item); } else { var i = table[h] !; while (true) { if (key.SequenceEqual(i.Key) == true) { // Identical return(false); } if (i.Next == null) { // Last item. break; } i = i.Next; } var item = new Item(key, value, hash); System.Threading.Volatile.Write(ref i.Next, item); } return(true); }
public static int GetHashCode(byte[] bytes, int offset, int count) { if (Is32Bit) { return(unchecked ((int)FarmHash.Hash32(bytes, offset, count))); } else { return(unchecked ((int)FarmHash.Hash64(bytes, offset, count))); } }
/// <summary> /// Decrypts data using the specified password. /// </summary> /// <param name="encrypted">The encrypted data.</param> /// <param name="password">The password.</param> /// <param name="data">The decrypted data.</param> /// <returns><see langword="true"/> if the decryption was successful; otherwise, <see langword="false"/>.</returns> public static bool TryDecrypt(ReadOnlySpan <byte> encrypted, ReadOnlySpan <byte> password, out Memory <byte> data) { data = default; if (encrypted.Length < SaltLength) { return(false); } // Hash: Sha3_384 => Key(32) + IV(16) var keyIV = GetKeyIV(encrypted.Slice(0, SaltLength), password); // AES byte[] decrypted; using (var aes = Aes.Create()) { aes.Key = keyIV.Slice(0, aes.KeySize / 8).ToArray(); if (keyIV.Length != ((aes.KeySize / 8) + (aes.BlockSize / 8))) { throw new InvalidOperationException(); } // Salt[8], Encrypted[8 + 8 + DataLength] (Random[8], Checksum[8 = FarmHash64], Data[DataLength]) try { decrypted = aes.DecryptCbc(encrypted.Slice(SaltLength), keyIV.Slice(aes.KeySize / 8), DefaultPaddingMode); } catch { return(false); } } var dataPosition = RandomLength + ChecksumLength; if (decrypted.Length < dataPosition) { return(false); } // Checksum: FarmHash64 var checksum = FarmHash.Hash64(decrypted.AsSpan(dataPosition)); if (BitConverter.ToUInt64(decrypted.AsSpan(RandomLength)) != checksum) { return(false); } data = decrypted.AsMemory(dataPosition); return(true); }
/// <summary> /// Encrypts data using the specified password. /// </summary> /// <param name="data">The data to encrypt.</param> /// <param name="password">The password.</param> /// <returns>The encrypted data.</returns> public static byte[] Encrypt(ReadOnlySpan <byte> data, ReadOnlySpan <byte> password) { // Salt: Random[SaltLength], Random: Random[RandomLength] var randomBuffer = RandomNumberGenerator.GetBytes(SaltLength + RandomLength); var salt = randomBuffer.AsSpan(0, SaltLength); var random = randomBuffer.AsSpan(SaltLength, RandomLength); // Hash: Sha3_384 => Key(32) + IV(16) var keyIV = GetKeyIV(salt, password); // Checksum: FarmHash64 var checksum = FarmHash.Hash64(data); // AES byte[] buffer; using (var aes = Aes.Create()) { aes.Key = keyIV.Slice(0, aes.KeySize / 8).ToArray(); var plainLength = RandomLength + ChecksumLength + data.Length; var cipherLength = aes.GetCiphertextLengthCbc(plainLength, DefaultPaddingMode); if (keyIV.Length != ((aes.KeySize / 8) + (aes.BlockSize / 8))) { throw new InvalidOperationException(); } // Salt[8], Encrypted[8 + 8 + DataLength] (Random[8], Checksum[8 = FarmHash64], Data[DataLength]) var bufferLength = SaltLength + cipherLength; buffer = new byte[bufferLength]; var bufferSpan = buffer.AsSpan(); salt.CopyTo(bufferSpan); bufferSpan = bufferSpan.Slice(SaltLength); random.CopyTo(bufferSpan); bufferSpan = bufferSpan.Slice(RandomLength); BitConverter.TryWriteBytes(bufferSpan, checksum); bufferSpan = bufferSpan.Slice(ChecksumLength); data.CopyTo(bufferSpan); // Encrypt var written = aes.EncryptCbc(buffer.AsSpan(SaltLength, plainLength), keyIV.Slice(aes.KeySize / 8), buffer.AsSpan(SaltLength), DefaultPaddingMode); Debug.Assert(written == cipherLength, "Encrypted length mismatch."); } return(buffer); }
public bool TryGetValue(ReadOnlySpan <byte> key, [MaybeNullWhen(false)] out TValue value) { var table = this.hashTable; var hash = unchecked ((int)FarmHash.Hash64(key)); var item = table[hash & (table.Length - 1)]; while (item != null) { if (key.SequenceEqual(item.Key) == true) { // Identical. alternative: (key == item.Key). value = item.Value; return(true); } item = item.Next; } value = default; return(false); }
public void TestHashUpdate() { const int N = 1_000_000; var random = new Random(42); var data = new byte[N]; random.NextBytes(data); // CRC-32 var crc32 = new Crc32(); for (var n = 0; n < 1000; n++) { var span = data.AsSpan(0, n); var h = BitConverter.ToUInt32(crc32.GetHash(span)); var h2 = Crc32.Hash32(span); Assert.Equal(h, h2); } this.TestHashUpdate_do(crc32, data, random); // Adler-32 var adler32 = new Adler32(); for (var n = 0; n < 1000; n++) { var span = data.AsSpan(0, n); var h = BitConverter.ToUInt32(adler32.GetHash(span)); var h2 = Adler32.Hash32(span); Assert.Equal(h, h2); } this.TestHashUpdate_do(adler32, data, random); // FarmHash var farm = new FarmHash(); for (var n = 0; n < 1000; n++) { var span = data.AsSpan(0, n); var h = BitConverter.ToUInt64(farm.GetHash(span)); var h2 = FarmHash.Hash64(span); Assert.Equal(h, h2); } this.TestHashUpdate_do(farm, data, random); // xxHash32 var xxh32 = new XXHash32(); for (var n = 0; n < 1000; n++) { var span = data.AsSpan(0, n); var h = BitConverter.ToUInt32(xxh32.GetHash(span)); var h2 = XXHash32.Hash32(span); Assert.Equal(h, h2); } this.TestHashUpdate_do(xxh32, data, random); // xxHash64 var xxh64 = new XxHash64(); for (var n = 0; n < 1000; n++) { var span = data.AsSpan(0, n); var h = BitConverter.ToUInt64(xxh64.GetHash(span)); var h2 = XxHash64.Hash64(span); Assert.Equal(h, h2); } this.TestHashUpdate_do(xxh64, data, random); // Sha1 using var sha1 = new Arc.Crypto.Sha1(); this.TestHashUpdate_do(sha1, data, random); // Sha2_256 using var sha2_256 = new Arc.Crypto.Sha2_256(); this.TestHashUpdate_do(sha2_256, data, random); // Sha2_384 using var sha2_384 = new Arc.Crypto.Sha2_384(); this.TestHashUpdate_do(sha2_384, data, random); // Sha2_512 using var sha2_512 = new Arc.Crypto.Sha2_512(); this.TestHashUpdate_do(sha2_512, data, random); // Sha3_256 var sha3_256 = new Arc.Crypto.Sha3_256(); this.TestHashUpdate_do(sha3_256, data, random); // Sha3_384 var sha3_384 = new Arc.Crypto.Sha3_384(); this.TestHashUpdate_do(sha3_384, data, random); // Sha3_512 var sha3_512 = new Arc.Crypto.Sha3_512(); this.TestHashUpdate_do(sha3_512, data, random); }