private static bool GCryptRun16(byte[] pbData16, byte[] pbKey32, ref ulong uRounds, uint uTimeMs) { IntPtr h = IntPtr.Zero; try { if (NativeMethods.gcry_cipher_open(ref h, NativeMethods.GCRY_CIPHER_AES256, NativeMethods.GCRY_CIPHER_MODE_CBC, 0) != 0) { Debug.Assert(false); return(false); } using (NativeBufferEx nbKey = new NativeBufferEx(pbKey32, true, true, 16)) { if (NativeMethods.gcry_cipher_setkey(h, nbKey.Data, new IntPtr(32)) != 0) { Debug.Assert(false); return(false); } } using (NativeBufferEx nbData = new NativeBufferEx(pbData16, true, true, 16)) { if (NativeMethods.gcry_cipher_setiv(h, nbData.Data, new IntPtr(16)) != 0) { Debug.Assert(false); return(false); } } using (NativeBufferEx nbZero = new NativeBufferEx(GCryptBufBlocks << 4, true, false, true, 16)) { using (NativeBufferEx nbBuf = new NativeBufferEx(GCryptBufBlocks << 4, false, true, true, 16)) { if (uTimeMs == 0) { if (!GCryptEncrypt(h, nbZero.Data, nbBuf.Data, uRounds, pbData16)) { return(false); } } else { const ulong uStep = 4096; // Cf. GCryptBufBlocks int tStart = Environment.TickCount; while ((uint)(Environment.TickCount - tStart) < uTimeMs) { if (!GCryptEncrypt(h, nbZero.Data, nbBuf.Data, uStep, null)) { return(false); } uRounds += uStep; if (uRounds < uStep) // Overflow { uRounds = unchecked (ulong.MaxValue - 8UL); break; } } } } } return(true); } catch (Exception) { Debug.Assert(false); } finally { if (h != IntPtr.Zero) { try { NativeMethods.gcry_cipher_close(h); } catch (Exception) { Debug.Assert(false); } } } return(false); }
private byte[] Argon2Native(byte[] pbMsg, byte[] pbSalt, uint uParallel, ulong uMem, ulong uIt, int cbOut, uint uVersion, byte[] pbSecretKey, byte[] pbAssocData) { NativeBufferEx nbMsg = null, nbSalt = null, nbHash = null; try { // Secret key and assoc. data are unsupported by 'argon2_hash' if ((pbSecretKey != null) && (pbSecretKey.Length != 0)) { return(null); } if ((pbAssocData != null) && (pbAssocData.Length != 0)) { return(null); } int iType; if (m_t == Argon2Type.D) { iType = 0; } else if (m_t == Argon2Type.ID) { iType = 2; } else { Debug.Assert(false); return(null); } nbMsg = new NativeBufferEx(pbMsg, true, true, 1); IntPtr cbMsg = new IntPtr(pbMsg.Length); nbSalt = new NativeBufferEx(pbSalt, true, true, 1); IntPtr cbSalt = new IntPtr(pbSalt.Length); uint m = checked ((uint)(uMem / NbBlockSize)); uint t = checked ((uint)uIt); nbHash = new NativeBufferEx(cbOut, true, true, true, 1); IntPtr cbHash = new IntPtr(cbOut); bool b = false; if (NativeLib.IsUnix()) { if (!MonoWorkarounds.IsRequired(100004)) { return(null); } try { b = (NativeMethods.argon2_hash_u0(t, m, uParallel, nbMsg.Data, cbMsg, nbSalt.Data, cbSalt, nbHash.Data, cbHash, IntPtr.Zero, IntPtr.Zero, iType, uVersion) == 0); } catch (DllNotFoundException) { } catch (Exception) { Debug.Assert(false); } if (!b) { b = (NativeMethods.argon2_hash_u1(t, m, uParallel, nbMsg.Data, cbMsg, nbSalt.Data, cbSalt, nbHash.Data, cbHash, IntPtr.Zero, IntPtr.Zero, iType, uVersion) == 0); } } else // Windows { if (IntPtr.Size == 4) { b = (NativeMethods.argon2_hash_w32(t, m, uParallel, nbMsg.Data, cbMsg, nbSalt.Data, cbSalt, nbHash.Data, cbHash, IntPtr.Zero, IntPtr.Zero, iType, uVersion) == 0); } else { b = (NativeMethods.argon2_hash_w64(t, m, uParallel, nbMsg.Data, cbMsg, nbSalt.Data, cbSalt, nbHash.Data, cbHash, IntPtr.Zero, IntPtr.Zero, iType, uVersion) == 0); } } if (b) { byte[] pbHash = new byte[cbOut]; nbHash.CopyTo(pbHash); return(pbHash); } } catch (DllNotFoundException) { } catch (Exception) { Debug.Assert(false); } finally { if (nbMsg != null) { nbMsg.Dispose(); } if (nbSalt != null) { nbSalt.Dispose(); } if (nbHash != null) { nbHash.Dispose(); } } return(null); }