https://github.com/timothymeadows/argon2.netcore
Implementation of Argon2 key derivation function designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich. Optimized for PinnedMemory and .NET Core.
https://github.com/timothymeadows/argon2.netcore
Last synced: 4 months ago
JSON representation
Implementation of Argon2 key derivation function designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich. Optimized for PinnedMemory and .NET Core.
- Host: GitHub
- URL: https://github.com/timothymeadows/argon2.netcore
- Owner: TimothyMeadows
- License: mit
- Created: 2020-07-26T02:23:57.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2020-08-13T20:11:34.000Z (almost 6 years ago)
- Last Synced: 2025-08-01T05:34:39.772Z (11 months ago)
- Language: C#
- Homepage:
- Size: 14.6 KB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Argon2.NetCore
[](https://opensource.org/licenses/MIT)
[](https://www.nuget.org/packages/Argon2.NetCore/)
`Argon2.NetCore` is a .NET implementation of the Argon2 password/key derivation function (PHC winner) by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich. This package is optimized to work with [`PinnedMemory`](https://github.com/TimothyMeadows/PinnedMemory) so sensitive material can stay in pinned buffers for better memory-handling control.
---
## Installation
```bash
dotnet add package Argon2.NetCore
```
```powershell
Install-Package Argon2.NetCore
```
NuGet package page:
https://www.nuget.org/packages/Argon2.NetCore/
---
## Quick start
```csharp
using System;
using System.Security.Cryptography;
using Argon2.NetCore;
using PinnedMemory;
var salt = new byte[16];
var secret = new byte[32];
RandomNumberGenerator.Fill(salt);
RandomNumberGenerator.Fill(secret);
using var keyPin = new PinnedMemory(secret, false);
using var argon2 = new Argon2(keyPin, salt)
{
// Argon2i (IndependentAddressing) by default.
// Set DependentAddressing for Argon2d.
Addressing = Argon2.AddressType.IndependentAddressing,
HashLength = 32,
MemoryCost = 65536, // 64 MiB (value is KiB)
TimeCost = 3,
Lanes = 4,
Threads = 2
};
// Optional: include additional context bytes in the hash input.
var message = new byte[] { 0x63, 0x61, 0x77 }; // "caw"
argon2.UpdateBlock(message, 0, message.Length);
using var hash = new PinnedMemory(new byte[argon2.GetLength()]);
argon2.DoFinal(hash, 0);
Console.WriteLine(Convert.ToHexString(hash.ToArray()));
```
Additional sample code is available in `Argon2.NetCore.Examples/Program.cs`.
---
## Constructor
```csharp
Argon2(PinnedMemory key, byte[] salt, byte[] associatedData = null)
```
### Parameters
- `key`: secret key / password bytes (required).
- `salt`: unique random salt bytes (required, minimum 8 bytes).
- `associatedData`: optional associated bytes mixed into derivation.
---
## Configuration options
Set these on the `Argon2` instance before calling `DoFinal`.
- `Addressing`
- `IndependentAddressing` (`Argon2i` behavior; default)
- `DependentAddressing` (`Argon2d` behavior)
- `HashLength` (`int`)
- Number of output bytes.
- Minimum value: `4`.
- `MemoryCost` (`int`)
- Memory cost in **KiB**.
- Example: `65536` = 64 MiB.
- `TimeCost` (`int`)
- Number of iterations/passes over memory.
- `Lanes` (`int`)
- Number of lanes (parallelism level).
- `Threads` (`int`)
- Number of worker threads used by the implementation.
---
## API reference
- `int GetLength()`
- Returns currently configured output length.
- `void Update(byte input)`
- Appends one byte to the message input.
- `void UpdateBlock(byte[] input, int inOff, int len)`
- Appends part of a byte array to the message input.
- `void UpdateBlock(PinnedMemory input, int inOff, int len)`
- Appends a pinned byte buffer to the message input.
- `void DoFinal(PinnedMemory output, int outOff)`
- Computes derived output and writes to the provided pinned output buffer.
- `void Reset()`
- Resets internal state for another run while retaining key/salt.
- `void Dispose()`
- Clears key/salt state and frees resources.
---
## Best practices
### 1. Always use a unique, random salt
- Use at least 16 bytes of cryptographically secure randomness.
- Never reuse a salt for different secrets when avoiding correlation matters.
### 2. Tune cost parameters for your environment
- Start from:
- `MemoryCost`: 64 MiB to 256 MiB (`65536` to `262144` KiB)
- `TimeCost`: `2` to `4`
- `Lanes`: number of physical cores (or a smaller operational cap)
- Benchmark in production-like conditions and target a derivation time that balances security and user latency.
### 3. Prefer Argon2i-style addressing when side-channel concerns matter
- `IndependentAddressing` (default) maps to Argon2i-style memory addressing and is generally safer for password hashing scenarios.
- Use `DependentAddressing` only when you specifically need Argon2d-style behavior.
### 4. Handle secrets as pinned memory where possible
- Keep password/key data in `PinnedMemory` while hashing.
- Dispose of `Argon2` and pinned buffers promptly to reduce lifetime of sensitive data.
### 5. Size output intentionally
- 32 bytes is a common default for key derivation.
- Use larger output (for example 64 bytes) only when your protocol needs it.
### 6. Store metadata alongside derived values
When persisting hashes, store:
- Algorithm identifier (`Argon2` variant/addressing mode)
- `MemoryCost`, `TimeCost`, `Lanes`, `HashLength`
- Salt
- Hash output
This ensures future verification and migration remain possible.
### 7. Validate operational limits
- Very high memory/thread settings can exhaust container/host resources.
- Use load testing to verify worst-case concurrency and avoid denial-of-service through excessive KDF pressure.
---
## Notes
- `DoFinal` requires an output buffer large enough for `HashLength` at the given offset.
- `salt` must be at least 8 bytes.
- Parameter validation throws exceptions for invalid values (e.g., non-positive costs/lanes/threads).
---
## SIMD acceleration
`Argon2.NetCore` now includes SIMD-aware optimizations in the Argon2 block/memory hot paths while preserving compatibility and deterministic output:
- **Vectorized block XOR/copy-XOR paths** in the internal `Block` implementation (`Copy`, `Xor`, `CopyXor`) using `System.Numerics.Vector` where hardware acceleration is available.
- **Faster `FillBlock` / `FillBlockWithXor` setup** by using a single `CopyXor` operation for `refBlock ^ prevBlock` instead of separate copy and XOR passes.
- **Optimized `LoadBlock` / `StoreBlock` transforms** on little-endian runtimes using `MemoryMarshal.Cast` bulk conversion with endian-safe fallback logic.
- **Scalar fallback behavior remains intact**, so functionality is preserved on platforms without SIMD acceleration.
These changes are designed to mirror the performance-oriented approach used in `Blake2b.NetCore` while keeping Argon2 algorithm behavior unchanged.
## License
MIT. See [LICENSE](LICENSE).