This commit is contained in:
Philipp Crocoll
2020-12-07 10:43:46 +01:00
parent b7e4bf0be5
commit eee24819d5
7 changed files with 323 additions and 92 deletions

View File

@@ -367,5 +367,27 @@ namespace KeePassLib.Cryptography
Debug.Assert(iPos == pbRes.Length); Debug.Assert(iPos == pbRes.Length);
return pbRes; return pbRes;
} }
private static int g_iWeakSeed = 0;
public static Random NewWeakRandom()
{
long s64 = DateTime.UtcNow.ToBinary();
int s32 = (int)((s64 >> 32) ^ s64);
lock (g_oSyncRoot)
{
unchecked
{
g_iWeakSeed += 0x78A8C4B7; // Prime number
s32 ^= g_iWeakSeed;
}
}
// Prevent overflow in the Random constructor of .NET 2.0
if (s32 == int.MinValue) s32 = int.MaxValue;
return new Random(s32);
}
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2020 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -20,28 +20,67 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text; using System.Text;
#if !KeePassUAP #if !KeePassUAP
using System.Security.Cryptography; using System.Security.Cryptography;
#endif #endif
using KeePassLib.Native;
using KeePassLib.Utility; using KeePassLib.Utility;
namespace KeePassLib.Cryptography namespace KeePassLib.Cryptography
{ {
public static class CryptoUtil public static class CryptoUtil
{ {
private static bool? g_obProtData = null;
public static bool IsProtectedDataSupported
{
get
{
if (g_obProtData.HasValue) return g_obProtData.Value;
bool b = false;
try
{
Random r = CryptoRandom.NewWeakRandom();
byte[] pbData = new byte[137];
r.NextBytes(pbData);
byte[] pbEnt = new byte[41];
r.NextBytes(pbEnt);
byte[] pbEnc = ProtectedData.Protect(pbData, pbEnt,
DataProtectionScope.CurrentUser);
if ((pbEnc != null) && !MemUtil.ArraysEqual(pbEnc, pbData))
{
byte[] pbDec = ProtectedData.Unprotect(pbEnc, pbEnt,
DataProtectionScope.CurrentUser);
if ((pbDec != null) && MemUtil.ArraysEqual(pbDec, pbData))
b = true;
}
}
catch (Exception) { Debug.Assert(false); }
Debug.Assert(b); // Should be supported on all systems
g_obProtData = b;
return b;
}
}
public static byte[] HashSha256(byte[] pbData) public static byte[] HashSha256(byte[] pbData)
{ {
if(pbData == null) throw new ArgumentNullException("pbData"); if (pbData == null) throw new ArgumentNullException("pbData");
return HashSha256(pbData, 0, pbData.Length); return HashSha256(pbData, 0, pbData.Length);
} }
public static byte[] HashSha256(byte[] pbData, int iOffset, int cbCount) public static byte[] HashSha256(byte[] pbData, int iOffset, int cbCount)
{ {
if(pbData == null) throw new ArgumentNullException("pbData"); if (pbData == null) throw new ArgumentNullException("pbData");
#if DEBUG #if DEBUG
byte[] pbCopy = new byte[pbData.Length]; byte[] pbCopy = new byte[pbData.Length];
@@ -49,7 +88,7 @@ namespace KeePassLib.Cryptography
#endif #endif
byte[] pbHash; byte[] pbHash;
using(SHA256Managed h = new SHA256Managed()) using (SHA256Managed h = new SHA256Managed())
{ {
pbHash = h.ComputeHash(pbData, iOffset, cbCount); pbHash = h.ComputeHash(pbData, iOffset, cbCount);
} }
@@ -66,6 +105,22 @@ namespace KeePassLib.Cryptography
return pbHash; return pbHash;
} }
internal static byte[] HashSha256(string strFilePath)
{
byte[] pbHash = null;
using (FileStream fs = new FileStream(strFilePath, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
using (SHA256Managed h = new SHA256Managed())
{
pbHash = h.ComputeHash(fs);
}
}
return pbHash;
}
/// <summary> /// <summary>
/// Create a cryptographic key of length <paramref name="cbOut" /> /// Create a cryptographic key of length <paramref name="cbOut" />
/// (in bytes) from <paramref name="pbIn" />. /// (in bytes) from <paramref name="pbIn" />.
@@ -73,34 +128,34 @@ namespace KeePassLib.Cryptography
public static byte[] ResizeKey(byte[] pbIn, int iInOffset, public static byte[] ResizeKey(byte[] pbIn, int iInOffset,
int cbIn, int cbOut) int cbIn, int cbOut)
{ {
if(pbIn == null) throw new ArgumentNullException("pbIn"); if (pbIn == null) throw new ArgumentNullException("pbIn");
if(cbOut < 0) throw new ArgumentOutOfRangeException("cbOut"); if (cbOut < 0) throw new ArgumentOutOfRangeException("cbOut");
if(cbOut == 0) return MemUtil.EmptyByteArray; if (cbOut == 0) return MemUtil.EmptyByteArray;
byte[] pbHash; byte[] pbHash;
if(cbOut <= 32) pbHash = HashSha256(pbIn, iInOffset, cbIn); if (cbOut <= 32) pbHash = HashSha256(pbIn, iInOffset, cbIn);
else else
{ {
using(SHA512Managed h = new SHA512Managed()) using (SHA512Managed h = new SHA512Managed())
{ {
pbHash = h.ComputeHash(pbIn, iInOffset, cbIn); pbHash = h.ComputeHash(pbIn, iInOffset, cbIn);
} }
} }
if(cbOut == pbHash.Length) return pbHash; if (cbOut == pbHash.Length) return pbHash;
byte[] pbRet = new byte[cbOut]; byte[] pbRet = new byte[cbOut];
if(cbOut < pbHash.Length) if (cbOut < pbHash.Length)
Array.Copy(pbHash, pbRet, cbOut); Array.Copy(pbHash, pbRet, cbOut);
else else
{ {
int iPos = 0; int iPos = 0;
ulong r = 0; ulong r = 0;
while(iPos < cbOut) while (iPos < cbOut)
{ {
Debug.Assert(pbHash.Length == 64); Debug.Assert(pbHash.Length == 64);
using(HMACSHA256 h = new HMACSHA256(pbHash)) using (HMACSHA256 h = new HMACSHA256(pbHash))
{ {
byte[] pbR = MemUtil.UInt64ToBytes(r); byte[] pbR = MemUtil.UInt64ToBytes(r);
byte[] pbPart = h.ComputeHash(pbR); byte[] pbPart = h.ComputeHash(pbR);
@@ -125,5 +180,75 @@ namespace KeePassLib.Cryptography
MemUtil.ZeroByteArray(pbHash); MemUtil.ZeroByteArray(pbHash);
return pbRet; return pbRet;
} }
#if !KeePassUAP
private static bool? g_obAesCsp = null;
internal static SymmetricAlgorithm CreateAes()
{
if (g_obAesCsp.HasValue)
return (g_obAesCsp.Value ? CreateAesCsp() : new RijndaelManaged());
SymmetricAlgorithm a = CreateAesCsp();
g_obAesCsp = (a != null);
return (a ?? new RijndaelManaged());
}
private static SymmetricAlgorithm CreateAesCsp()
{
try
{
// On Windows, the CSP implementation is only minimally
// faster (and for key derivations it's not used anyway,
// as KeePass uses a native implementation based on
// CNG/BCrypt, which is much faster)
if (!NativeLib.IsUnix()) return null;
string strFqn = Assembly.CreateQualifiedName(
"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"System.Security.Cryptography.AesCryptoServiceProvider");
Type t = Type.GetType(strFqn);
if (t == null) return null;
return (Activator.CreateInstance(t) as SymmetricAlgorithm);
}
catch (Exception) { Debug.Assert(false); }
return null;
}
#endif
public static byte[] ProtectData(byte[] pb, byte[] pbOptEntropy,
DataProtectionScope s)
{
return ProtectDataPriv(pb, true, pbOptEntropy, s);
}
public static byte[] UnprotectData(byte[] pb, byte[] pbOptEntropy,
DataProtectionScope s)
{
return ProtectDataPriv(pb, false, pbOptEntropy, s);
}
private static byte[] ProtectDataPriv(byte[] pb, bool bProtect,
byte[] pbOptEntropy, DataProtectionScope s)
{
if (pb == null) throw new ArgumentNullException("pb");
if ((pbOptEntropy != null) && (pbOptEntropy.Length == 0))
pbOptEntropy = null;
if (CryptoUtil.IsProtectedDataSupported)
{
if (bProtect)
return ProtectedData.Protect(pb, pbOptEntropy, s);
return ProtectedData.Unprotect(pb, pbOptEntropy, s);
}
Debug.Assert(false);
byte[] pbCopy = new byte[pb.Length];
Array.Copy(pb, pbCopy, pb.Length);
return pbCopy;
}
} }
} }

View File

@@ -46,6 +46,8 @@ namespace KeePassLib.Cryptography.KeyDerivation
private const ulong NbBlockSizeInQW = NbBlockSize / 8UL; private const ulong NbBlockSizeInQW = NbBlockSize / 8UL;
private const ulong NbSyncPoints = 4; private const ulong NbSyncPoints = 4;
private const ulong NbAddressesInBlock = 128;
private const int NbPreHashDigestLength = 64; private const int NbPreHashDigestLength = 64;
private const int NbPreHashSeedLength = NbPreHashDigestLength + 8; private const int NbPreHashSeedLength = NbPreHashDigestLength + 8;
@@ -56,6 +58,7 @@ namespace KeePassLib.Cryptography.KeyDerivation
private sealed class Argon2Ctx private sealed class Argon2Ctx
{ {
public Argon2Type Type = Argon2Type.D;
public uint Version = 0; public uint Version = 0;
public ulong Lanes = 0; public ulong Lanes = 0;
@@ -89,9 +92,9 @@ namespace KeePassLib.Cryptography.KeyDerivation
} }
} }
private static byte[] Argon2d(byte[] pbMsg, byte[] pbSalt, uint uParallel, private byte[] Argon2Transform(byte[] pbMsg, byte[] pbSalt, uint uParallel,
ulong uMem, ulong uIt, int cbOut, uint uVersion, byte[] pbSecretKey, ulong uMem, ulong uIt, int cbOut, uint uVersion, byte[] pbSecretKey,
byte[] pbAssocData) byte[] pbAssocData)
{ {
pbSecretKey = (pbSecretKey ?? MemUtil.EmptyByteArray); pbSecretKey = (pbSecretKey ?? MemUtil.EmptyByteArray);
pbAssocData = (pbAssocData ?? MemUtil.EmptyByteArray); pbAssocData = (pbAssocData ?? MemUtil.EmptyByteArray);
@@ -101,6 +104,7 @@ namespace KeePassLib.Cryptography.KeyDerivation
#endif #endif
Argon2Ctx ctx = new Argon2Ctx(); Argon2Ctx ctx = new Argon2Ctx();
ctx.Type = m_t;
ctx.Version = uVersion; ctx.Version = uVersion;
ctx.Lanes = uParallel; ctx.Lanes = uParallel;
@@ -137,7 +141,7 @@ namespace KeePassLib.Cryptography.KeyDerivation
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
MemUtil.UInt32ToBytesEx(uVersion, pbBuf, 0); MemUtil.UInt32ToBytesEx(uVersion, pbBuf, 0);
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
MemUtil.UInt32ToBytesEx(0, pbBuf, 0); // Argon2d type = 0 MemUtil.UInt32ToBytesEx((uint)m_t, pbBuf, 0);
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
MemUtil.UInt32ToBytesEx((uint)pbMsg.Length, pbBuf, 0); MemUtil.UInt32ToBytesEx((uint)pbMsg.Length, pbBuf, 0);
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
@@ -487,18 +491,43 @@ namespace KeePassLib.Cryptography.KeyDerivation
private static void FillSegmentThr(object o) private static void FillSegmentThr(object o)
{ {
Argon2ThreadInfo ti = (o as Argon2ThreadInfo); Argon2ThreadInfo ti = (o as Argon2ThreadInfo);
if(ti == null) { Debug.Assert(false); return; } if (ti == null) { Debug.Assert(false); return; }
try try
{ {
Argon2Ctx ctx = ti.Context; Argon2Ctx ctx = ti.Context;
if(ctx == null) { Debug.Assert(false); return; } if (ctx == null) { Debug.Assert(false); return; }
Debug.Assert(ctx.Version >= MinVersion); Debug.Assert(ctx.Version >= MinVersion);
bool bCanXor = (ctx.Version >= 0x13U); bool bCanXor = (ctx.Version >= 0x13U);
ulong[] pbR = new ulong[NbBlockSizeInQW];
ulong[] pbTmp = new ulong[NbBlockSizeInQW];
ulong[] pbAddrInputZero = null;
bool bDataIndependentAddr = ((ctx.Type == Argon2Type.ID) &&
(ti.Pass == 0) && (ti.Slice < (NbSyncPoints / 2)));
if (bDataIndependentAddr)
{
pbAddrInputZero = new ulong[NbBlockSizeInQW * 3];
const int iInput = (int)NbBlockSizeInQW;
pbAddrInputZero[iInput] = ti.Pass;
pbAddrInputZero[iInput + 1] = ti.Lane;
pbAddrInputZero[iInput + 2] = ti.Slice;
pbAddrInputZero[iInput + 3] = ctx.MemoryBlocks;
pbAddrInputZero[iInput + 4] = ctx.TCost;
pbAddrInputZero[iInput + 5] = (ulong)ctx.Type;
}
ulong uStart = 0; ulong uStart = 0;
if((ti.Pass == 0) && (ti.Slice == 0)) uStart = 2; if ((ti.Pass == 0) && (ti.Slice == 0))
{
uStart = 2;
if (bDataIndependentAddr)
NextAddresses(pbAddrInputZero, pbR, pbTmp);
}
ulong uCur = (ti.Lane * ctx.LaneLength) + (ti.Slice * ulong uCur = (ti.Lane * ctx.LaneLength) + (ti.Slice *
ctx.SegmentLength) + uStart; ctx.SegmentLength) + uStart;
@@ -506,17 +535,23 @@ namespace KeePassLib.Cryptography.KeyDerivation
ulong uPrev = (((uCur % ctx.LaneLength) == 0) ? ulong uPrev = (((uCur % ctx.LaneLength) == 0) ?
(uCur + ctx.LaneLength - 1UL) : (uCur - 1UL)); (uCur + ctx.LaneLength - 1UL) : (uCur - 1UL));
ulong[] pbR = new ulong[NbBlockSizeInQW]; for (ulong i = uStart; i < ctx.SegmentLength; ++i)
ulong[] pbTmp = new ulong[NbBlockSizeInQW];
for(ulong i = uStart; i < ctx.SegmentLength; ++i)
{ {
if((uCur % ctx.LaneLength) == 1) if ((uCur % ctx.LaneLength) == 1)
uPrev = uCur - 1UL; uPrev = uCur - 1UL;
ulong uPseudoRand = ctx.Mem[uPrev * NbBlockSizeInQW]; ulong uPseudoRand;
if (bDataIndependentAddr)
{
ulong iMod = i % NbAddressesInBlock;
if (iMod == 0)
NextAddresses(pbAddrInputZero, pbR, pbTmp);
uPseudoRand = pbAddrInputZero[iMod];
}
else uPseudoRand = ctx.Mem[uPrev * NbBlockSizeInQW];
ulong uRefLane = (uPseudoRand >> 32) % ctx.Lanes; ulong uRefLane = (uPseudoRand >> 32) % ctx.Lanes;
if((ti.Pass == 0) && (ti.Slice == 0)) if ((ti.Pass == 0) && (ti.Slice == 0))
uRefLane = ti.Lane; uRefLane = ti.Lane;
ti.Index = i; ti.Index = i;
@@ -536,11 +571,12 @@ namespace KeePassLib.Cryptography.KeyDerivation
MemUtil.ZeroArray<ulong>(pbR); MemUtil.ZeroArray<ulong>(pbR);
MemUtil.ZeroArray<ulong>(pbTmp); MemUtil.ZeroArray<ulong>(pbTmp);
if (pbAddrInputZero != null) MemUtil.ZeroArray<ulong>(pbAddrInputZero);
} }
catch(Exception) { Debug.Assert(false); } catch (Exception) { Debug.Assert(false); }
try { ti.Finished.Set(); } try { ti.Finished.Set(); }
catch(Exception) { Debug.Assert(false); } catch (Exception) { Debug.Assert(false); }
} }
#if ARGON2_B2ROUND_ARRAYS #if ARGON2_B2ROUND_ARRAYS
@@ -610,6 +646,19 @@ namespace KeePassLib.Cryptography.KeyDerivation
XorBlock(pMem, uNext, pbR, 0); XorBlock(pMem, uNext, pbR, 0);
} }
private static void NextAddresses(ulong[] pbAddrInputZero, ulong[] pbR,
ulong[] pbTmp)
{
// pbAddrInputZero contains an address block, an input block and a zero block
const ulong uAddr = 0;
const ulong uInput = NbBlockSizeInQW;
const ulong uZero = NbBlockSizeInQW * 2;
++pbAddrInputZero[uInput + 6];
FillBlock(pbAddrInputZero, uZero, uInput, uAddr, false, pbR, pbTmp);
FillBlock(pbAddrInputZero, uZero, uAddr, uAddr, false, pbR, pbTmp);
}
private static byte[] FinalHash(Argon2Ctx ctx, int cbOut, Blake2b h) private static byte[] FinalHash(Argon2Ctx ctx, int cbOut, Blake2b h)
{ {
ulong[] pqBlockHash = new ulong[NbBlockSizeInQW]; ulong[] pqBlockHash = new ulong[NbBlockSizeInQW];

View File

@@ -25,11 +25,22 @@ using System.Text;
namespace KeePassLib.Cryptography.KeyDerivation namespace KeePassLib.Cryptography.KeyDerivation
{ {
public sealed partial class Argon2Kdf : KdfEngine public enum Argon2Type
{
// The values must be the same as in the Argon2 specification
D = 0,
ID = 2
}
public sealed partial class Argon2Kdf : KdfEngine
{ {
private static readonly PwUuid g_uuid = new PwUuid(new byte[] {
0xEF, 0x63, 0x6D, 0xDF, 0x8C, 0x29, 0x44, 0x4B,
0x91, 0xF7, 0xA9, 0xA4, 0x03, 0xE3, 0x0A, 0x0C }); private static readonly PwUuid g_uuidD = new PwUuid(new byte[] {
0xEF, 0x63, 0x6D, 0xDF, 0x8C, 0x29, 0x44, 0x4B,
0x91, 0xF7, 0xA9, 0xA4, 0x03, 0xE3, 0x0A, 0x0C });
private static readonly PwUuid g_uuidID = new PwUuid(new byte[] {
0x9E, 0x29, 0x8B, 0x19, 0x56, 0xDB, 0x47, 0x73,
0xB2, 0x3D, 0xFC, 0x3E, 0xC6, 0xF0, 0xA1, 0xE6 });
public const string ParamSalt = "S"; // Byte[] public const string ParamSalt = "S"; // Byte[]
public const string ParamParallelism = "P"; // UInt32 public const string ParamParallelism = "P"; // UInt32
@@ -55,28 +66,37 @@ namespace KeePassLib.Cryptography.KeyDerivation
internal const uint MinParallelism = 1; internal const uint MinParallelism = 1;
internal const uint MaxParallelism = (1 << 24) - 1; internal const uint MaxParallelism = (1 << 24) - 1;
internal const ulong DefaultIterations = 2; internal const ulong DefaultIterations = 2;
internal const ulong DefaultMemory = 1024 * 1024; // 1 MB internal const ulong DefaultMemory = 64 * 1024 * 1024; // 64 MB
internal const uint DefaultParallelism = 2; internal const uint DefaultParallelism = 2;
public override PwUuid Uuid private readonly Argon2Type m_t;
{
get { return g_uuid; }
}
public override string Name public override PwUuid Uuid
{ {
get { return "Argon2"; } get { return ((m_t == Argon2Type.D) ? g_uuidD : g_uuidID); }
} }
public override string Name
{
get { return ((m_t == Argon2Type.D) ? "Argon2d" : "Argon2id"); }
}
public Argon2Kdf() : this(Argon2Type.D)
{
}
public Argon2Kdf(Argon2Type t)
{
if ((t != Argon2Type.D) && (t != Argon2Type.ID))
throw new NotSupportedException();
m_t = t;
}
public override byte[] GetSeed(KdfParameters p) public override byte[] GetSeed(KdfParameters p)
{ return p.GetByteArray(ParamSalt); } { return p.GetByteArray(ParamSalt); }
public Argon2Kdf() public override KdfParameters GetDefaultParameters()
{
}
public override KdfParameters GetDefaultParameters()
{ {
KdfParameters p = base.GetDefaultParameters(); KdfParameters p = base.GetDefaultParameters();
@@ -92,7 +112,7 @@ namespace KeePassLib.Cryptography.KeyDerivation
public override void Randomize(KdfParameters p) public override void Randomize(KdfParameters p)
{ {
if(p == null) { Debug.Assert(false); return; } if(p == null) { Debug.Assert(false); return; }
Debug.Assert(g_uuid.Equals(p.KdfUuid)); Debug.Assert(p.KdfUuid.Equals(this.Uuid));
byte[] pb = CryptoRandom.Instance.GetRandomBytes(32); byte[] pb = CryptoRandom.Instance.GetRandomBytes(32);
p.SetByteArray(ParamSalt, pb); p.SetByteArray(ParamSalt, pb);
@@ -128,46 +148,59 @@ namespace KeePassLib.Cryptography.KeyDerivation
byte[] pbSecretKey = p.GetByteArray(ParamSecretKey); byte[] pbSecretKey = p.GetByteArray(ParamSecretKey);
byte[] pbAssocData = p.GetByteArray(ParamAssocData); byte[] pbAssocData = p.GetByteArray(ParamAssocData);
if (pbSecretKey != null) { byte[] pbRet;
throw new ArgumentOutOfRangeException("Unsupported configuration: non-null pbSecretKey");
if (m_t == Argon2Type.ID)
{
pbRet = Argon2Transform(pbMsg, pbSalt, uPar, uMem,
uIt, 32, v, pbSecretKey, pbAssocData);
}
else
{
if (pbSecretKey != null)
{
throw new ArgumentOutOfRangeException("Unsupported configuration: non-null pbSecretKey");
}
if (pbAssocData != null)
{
throw new ArgumentOutOfRangeException("Unsupported configuration: non-null pbAssocData");
}
/*
byte[] pbRet = Argon2d(pbMsg, pbSalt, uPar, uMem, uIt,
32, v, pbSecretKey, pbAssocData);
*/
IntPtr msgPtr = Marshal.AllocHGlobal(pbMsg.Length);
IntPtr saltPtr = Marshal.AllocHGlobal(pbSalt.Length);
IntPtr retPtr = Marshal.AllocHGlobal(32);
Marshal.Copy(pbMsg, 0, msgPtr, pbMsg.Length);
Marshal.Copy(pbSalt, 0, saltPtr, pbSalt.Length);
const UInt32 Argon2_d = 0;
int ret = argon2_hash(
(UInt32)uIt, (UInt32)(uMem / 1024), uPar,
msgPtr, (IntPtr)pbMsg.Length,
saltPtr, (IntPtr)pbSalt.Length,
retPtr, (IntPtr)32,
(IntPtr)0, (IntPtr)0, Argon2_d, v);
if (ret != 0)
{
throw new Exception("argon2_hash failed with " + ret);
}
pbRet = new byte[32];
Marshal.Copy(retPtr, pbRet, 0, 32);
Marshal.FreeHGlobal(msgPtr);
Marshal.FreeHGlobal(saltPtr);
Marshal.FreeHGlobal(retPtr);
} }
if (pbAssocData != null) { if(uMem > (100UL * 1024UL * 1024UL)) GC.Collect();
throw new ArgumentOutOfRangeException("Unsupported configuration: non-null pbAssocData");
}
/*
byte[] pbRet = Argon2d(pbMsg, pbSalt, uPar, uMem, uIt,
32, v, pbSecretKey, pbAssocData);
*/
IntPtr msgPtr = Marshal.AllocHGlobal(pbMsg.Length);
IntPtr saltPtr = Marshal.AllocHGlobal(pbSalt.Length);
IntPtr retPtr = Marshal.AllocHGlobal(32);
Marshal.Copy(pbMsg, 0, msgPtr, pbMsg.Length);
Marshal.Copy(pbSalt, 0, saltPtr, pbSalt.Length);
const UInt32 Argon2_d = 0;
int ret = argon2_hash(
(UInt32)uIt, (UInt32)(uMem / 1024), uPar,
msgPtr, (IntPtr)pbMsg.Length,
saltPtr, (IntPtr)pbSalt.Length,
retPtr, (IntPtr)32,
(IntPtr)0, (IntPtr)0, Argon2_d, v);
if (ret != 0) {
throw new Exception("argon2_hash failed with " + ret);
}
byte[] pbRet = new byte[32];
Marshal.Copy(retPtr, pbRet, 0, 32);
Marshal.FreeHGlobal(msgPtr);
Marshal.FreeHGlobal(saltPtr);
Marshal.FreeHGlobal(retPtr);
if(uMem > (100UL * 1024UL * 1024UL)) GC.Collect();
return pbRet; return pbRet;
} }

View File

@@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2020 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2020 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -41,10 +41,11 @@ namespace KeePassLib.Cryptography.KeyDerivation
private static void EnsureInitialized() private static void EnsureInitialized()
{ {
if(g_l.Count > 0) return; if(g_l.Count != 0) return;
g_l.Add(new AesKdf()); g_l.Add(new AesKdf());
g_l.Add(new Argon2Kdf()); g_l.Add(new Argon2Kdf(Argon2Type.D));
g_l.Add(new Argon2Kdf(Argon2Type.ID));
} }
internal static KdfParameters GetDefaultParameters() internal static KdfParameters GetDefaultParameters()

View File

@@ -50,6 +50,7 @@
<HintPath>..\ProtoBuf\protobuf-net.dll</HintPath> <HintPath>..\ProtoBuf\protobuf-net.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Security" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="Mono.Android" /> <Reference Include="Mono.Android" />