public override KdfParameters GetBestParameters(uint uMilliseconds)
{
KdfParameters p = GetDefaultParameters();
ulong uRounds;
// Try native method
if(NativeLib.TransformKeyBenchmark256(uMilliseconds, out uRounds))
{
p.SetUInt64(ParamRounds, uRounds);
return p;
}
if(TransformKeyBenchmarkGCrypt(uMilliseconds, out uRounds))
{
p.SetUInt64(ParamRounds, uRounds);
return p;
}
byte[] pbKey = new byte[32];
byte[] pbNewKey = new byte[32];
for(int i = 0; i < pbKey.Length; ++i)
{
pbKey[i] = (byte)i;
pbNewKey[i] = (byte)i;
}
#if KeePassUAP
KeyParameter kp = new KeyParameter(pbKey);
AesEngine aes = new AesEngine();
aes.Init(true, kp);
#else
byte[] pbIV = new byte[16];
using(SymmetricAlgorithm a = CryptoUtil.CreateAes())
{
if(a.BlockSize != 128) // AES block size
{
Debug.Assert(false);
a.BlockSize = 128;
}
a.KeySize = 256;
a.Mode = CipherMode.ECB;
using(ICryptoTransform t = a.CreateEncryptor(pbKey, pbIV))
{
// !t.CanReuseTransform -- doesn't work with Mono
if((t == null) || (t.InputBlockSize != 16) ||
(t.OutputBlockSize != 16))
{
Debug.Assert(false);
p.SetUInt64(ParamRounds, PwDefs.DefaultKeyEncryptionRounds);
return p;
}
#endif
uRounds = 0;
int tStart = Environment.TickCount;
while(true)
{
for(ulong j = 0; j < BenchStep; ++j)
{
#if KeePassUAP
aes.ProcessBlock(pbNewKey, 0, pbNewKey, 0);
aes.ProcessBlock(pbNewKey, 16, pbNewKey, 16);
#else
t.TransformBlock(pbNewKey, 0, 16, pbNewKey, 0);
t.TransformBlock(pbNewKey, 16, 16, pbNewKey, 16);
#endif
}
uRounds += BenchStep;
if(uRounds < BenchStep) // Overflow check
{
uRounds = ulong.MaxValue;
break;
}
uint tElapsed = (uint)(Environment.TickCount - tStart);
if(tElapsed > uMilliseconds) break;
}
p.SetUInt64(ParamRounds, uRounds);
#if KeePassUAP
aes.Reset();
#else
}
}
#endif
return p;
}
}