2
KeePass Password Safe - The Open-Source Password Manager
3
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
using System.Collections.Generic;
23
using System.Runtime.InteropServices;
24
using System.Windows.Forms;
25
using System.Threading;
27
using System.Reflection;
28
using System.Diagnostics;
30
using KeePassLib.Utility;
32
namespace KeePassLib.Native
35
/// Interface to native library (library containing fast versions of
36
/// several cryptographic functions).
38
public static class NativeLib
40
private static bool m_bAllowNative = true;
43
/// If this property is set to <c>true</c>, the native library is used.
44
/// If it is <c>false</c>, all calls to functions in this class will fail.
46
public static bool AllowNative
48
get { return m_bAllowNative; }
49
set { m_bAllowNative = value; }
53
/// Determine if the native library is installed.
55
/// <returns>Returns <c>true</c>, if the native library is installed.</returns>
56
public static bool IsLibraryInstalled()
58
byte[] pDummy0 = new byte[32];
59
byte[] pDummy1 = new byte[32];
61
// Save the native state
62
bool bCachedNativeState = m_bAllowNative;
64
// Temporarily allow native functions and try to load the library
65
m_bAllowNative = true;
66
bool bResult = TransformKey256(pDummy0, pDummy1, 16);
68
// Pop native state and return result
69
m_bAllowNative = bCachedNativeState;
73
private static bool? m_bIsUnix = null;
74
public static bool IsUnix()
76
if(m_bIsUnix.HasValue) return m_bIsUnix.Value;
78
PlatformID p = GetPlatformID();
80
// Mono defines Unix as 128 in early .NET versions
82
m_bIsUnix = ((p == PlatformID.Unix) || (p == PlatformID.MacOSX) ||
85
m_bIsUnix = (((int)p == 4) || ((int)p == 6) || ((int)p == 128));
87
return m_bIsUnix.Value;
90
private static PlatformID? m_platID = null;
91
public static PlatformID GetPlatformID()
93
if(m_platID.HasValue) return m_platID.Value;
96
m_platID = PlatformID.Win32NT;
98
m_platID = Environment.OSVersion.Platform;
101
#if (!KeePassLibSD && !KeePassRT)
102
// Mono returns PlatformID.Unix on Mac OS X, workaround this
103
if(m_platID.Value == PlatformID.Unix)
105
if((RunConsoleApp("uname", null) ?? string.Empty).Trim().Equals(
106
"Darwin", StrUtil.CaseIgnoreCmp))
107
m_platID = PlatformID.MacOSX;
111
return m_platID.Value;
114
#if (!KeePassLibSD && !KeePassRT)
115
public static string RunConsoleApp(string strAppPath, string strParams)
117
return RunConsoleApp(strAppPath, strParams, null);
120
public static string RunConsoleApp(string strAppPath, string strParams,
123
return RunConsoleApp(strAppPath, strParams, strStdInput,
124
(AppRunFlags.GetStdOutput | AppRunFlags.WaitForExit));
127
private delegate string RunProcessDelegate();
129
public static string RunConsoleApp(string strAppPath, string strParams,
130
string strStdInput, AppRunFlags f)
132
if(strAppPath == null) throw new ArgumentNullException("strAppPath");
133
if(strAppPath.Length == 0) throw new ArgumentException("strAppPath");
135
bool bStdOut = ((f & AppRunFlags.GetStdOutput) != AppRunFlags.None);
137
RunProcessDelegate fnRun = delegate()
141
ProcessStartInfo psi = new ProcessStartInfo();
143
psi.CreateNoWindow = true;
144
psi.FileName = strAppPath;
145
psi.WindowStyle = ProcessWindowStyle.Hidden;
146
psi.UseShellExecute = false;
147
psi.RedirectStandardOutput = bStdOut;
149
if(strStdInput != null) psi.RedirectStandardInput = true;
151
if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams;
153
Process p = Process.Start(psi);
155
if(strStdInput != null)
157
// Workaround for Mono Process StdIn BOM bug;
158
// https://sourceforge.net/p/keepass/bugs/1219/
159
EnsureNoBom(p.StandardInput);
161
p.StandardInput.Write(strStdInput);
162
p.StandardInput.Close();
165
string strOutput = string.Empty;
166
if(bStdOut) strOutput = p.StandardOutput.ReadToEnd();
168
if((f & AppRunFlags.WaitForExit) != AppRunFlags.None)
170
else if((f & AppRunFlags.GCKeepAlive) != AppRunFlags.None)
172
Thread th = new Thread(delegate()
174
try { p.WaitForExit(); }
175
catch(Exception) { Debug.Assert(false); }
182
catch(Exception) { Debug.Assert(false); }
187
if((f & AppRunFlags.DoEvents) != AppRunFlags.None)
189
List<Form> lDisabledForms = new List<Form>();
190
if((f & AppRunFlags.DisableForms) != AppRunFlags.None)
192
foreach(Form form in Application.OpenForms)
194
if(!form.Enabled) continue;
196
lDisabledForms.Add(form);
197
form.Enabled = false;
201
IAsyncResult ar = fnRun.BeginInvoke(null, null);
203
while(!ar.AsyncWaitHandle.WaitOne(0))
205
Application.DoEvents();
209
string strRet = fnRun.EndInvoke(ar);
211
for(int i = lDisabledForms.Count - 1; i >= 0; --i)
212
lDisabledForms[i].Enabled = true;
220
private static void EnsureNoBom(StreamWriter sw)
222
if(sw == null) { Debug.Assert(false); return; }
223
if(!NativeLib.IsUnix()) return;
227
Encoding enc = sw.Encoding;
228
if(enc == null) { Debug.Assert(false); return; }
229
byte[] pbBom = enc.GetPreamble();
230
if((pbBom == null) || (pbBom.Length == 0)) return;
232
FieldInfo fi = typeof(StreamWriter).GetField("preamble_done",
233
BindingFlags.Instance | BindingFlags.NonPublic);
234
if(fi != null) fi.SetValue(sw, true);
236
catch(Exception) { Debug.Assert(false); }
243
/// <param name="pBuf256">Source and destination buffer.</param>
244
/// <param name="pKey256">Key to use in the transformation.</param>
245
/// <param name="uRounds">Number of transformation rounds.</param>
246
/// <returns>Returns <c>true</c>, if the key was transformed successfully.</returns>
247
public static bool TransformKey256(byte[] pBuf256, byte[] pKey256,
250
if(m_bAllowNative == false) return false;
252
KeyValuePair<IntPtr, IntPtr> kvp = PrepareArrays256(pBuf256, pKey256);
253
bool bResult = false;
257
bResult = NativeMethods.TransformKey(kvp.Key, kvp.Value, uRounds);
259
catch(Exception) { bResult = false; }
261
if(bResult) GetBuffers256(kvp, pBuf256, pKey256);
263
NativeLib.FreeArrays(kvp);
268
/// Benchmark key transformation.
270
/// <param name="uTimeMs">Number of seconds to perform the benchmark.</param>
271
/// <param name="puRounds">Number of transformations done.</param>
272
/// <returns>Returns <c>true</c>, if the benchmark was successful.</returns>
273
public static bool TransformKeyBenchmark256(uint uTimeMs, out ulong puRounds)
277
if(m_bAllowNative == false) return false;
279
try { puRounds = NativeMethods.TransformKeyBenchmark(uTimeMs); }
280
catch(Exception) { return false; }
285
private static KeyValuePair<IntPtr, IntPtr> PrepareArrays256(byte[] pBuf256,
288
Debug.Assert((pBuf256 != null) && (pBuf256.Length == 32));
289
if(pBuf256 == null) throw new ArgumentNullException("pBuf256");
290
if(pBuf256.Length != 32) throw new ArgumentException();
292
Debug.Assert((pKey256 != null) && (pKey256.Length == 32));
293
if(pKey256 == null) throw new ArgumentNullException("pKey256");
294
if(pKey256.Length != 32) throw new ArgumentException();
296
IntPtr hBuf = Marshal.AllocHGlobal(pBuf256.Length);
297
Marshal.Copy(pBuf256, 0, hBuf, pBuf256.Length);
299
IntPtr hKey = Marshal.AllocHGlobal(pKey256.Length);
300
Marshal.Copy(pKey256, 0, hKey, pKey256.Length);
302
return new KeyValuePair<IntPtr, IntPtr>(hBuf, hKey);
305
private static void GetBuffers256(KeyValuePair<IntPtr, IntPtr> kvpSource,
306
byte[] pbDestBuf, byte[] pbDestKey)
308
if(kvpSource.Key != IntPtr.Zero)
309
Marshal.Copy(kvpSource.Key, pbDestBuf, 0, pbDestBuf.Length);
311
if(kvpSource.Value != IntPtr.Zero)
312
Marshal.Copy(kvpSource.Value, pbDestKey, 0, pbDestKey.Length);
315
private static void FreeArrays(KeyValuePair<IntPtr, IntPtr> kvpPointers)
317
if(kvpPointers.Key != IntPtr.Zero)
318
Marshal.FreeHGlobal(kvpPointers.Key);
320
if(kvpPointers.Value != IntPtr.Zero)
321
Marshal.FreeHGlobal(kvpPointers.Value);