/* KeePass Password Safe - The Open-Source Password Manager Copyright (C) 2003-2013 Dominik Reichl Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll 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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; using System.Diagnostics; using Android.Util; using KeePassLib.Utility; using keepass2android; namespace KeePassLib.Native { /// /// Interface to native library (library containing fast versions of /// several cryptographic functions). /// public static class NativeLib { private static bool m_bAllowNative = true; /// /// If this property is set to true, the native library is used. /// If it is false, all calls to functions in this class will fail. /// public static bool AllowNative { get { return m_bAllowNative; } set { m_bAllowNative = value; } } /// /// Determine if the native library is installed. /// /// Returns true, if the native library is installed. public static bool IsLibraryInstalled() { byte[] pDummy0 = new byte[32]; byte[] pDummy1 = new byte[32]; // Save the native state bool bCachedNativeState = m_bAllowNative; // Temporarily allow native functions and try to load the library m_bAllowNative = true; bool bResult = TransformKey256(pDummy0, pDummy1, 16); // Pop native state and return result m_bAllowNative = bCachedNativeState; return bResult; } private static bool? m_bIsUnix = null; public static bool IsUnix() { if(m_bIsUnix.HasValue) return m_bIsUnix.Value; PlatformID p = GetPlatformID(); // Mono defines Unix as 128 in early .NET versions #if !KeePassLibSD m_bIsUnix = ((p == PlatformID.Unix) || (p == PlatformID.MacOSX) || ((int)p == 128)); #else m_bIsUnix = (((int)p == 4) || ((int)p == 6) || ((int)p == 128)); #endif return m_bIsUnix.Value; } private static PlatformID? m_platID = null; public static PlatformID GetPlatformID() { if(m_platID.HasValue) return m_platID.Value; #if KeePassRT m_platID = PlatformID.Win32NT; #else m_platID = Environment.OSVersion.Platform; #endif #if (!KeePassLibSD && !KeePassRT) /*// Mono returns PlatformID.Unix on Mac OS X, workaround this //fails on Anroid if(m_platID.Value == PlatformID.Unix) { if((RunConsoleApp("uname", null) ?? string.Empty).Trim().Equals( "Darwin", StrUtil.CaseIgnoreCmp)) m_platID = PlatformID.MacOSX; }*/ #endif return m_platID.Value; } /// /// Transform a key. /// /// Source and destination buffer. /// Key to use in the transformation. /// Number of transformation rounds. /// Returns true, if the key was transformed successfully. public static bool TransformKey256(byte[] pBuf256, byte[] pKey256, ulong uRounds) { if(m_bAllowNative == false) return false; try { #if !EXCLUDE_KEYTRANSFORM Com.Keepassdroid.Crypto.Finalkey.NativeFinalKey key = new Com.Keepassdroid.Crypto.Finalkey.NativeFinalKey(); byte[] newKey = key.TransformMasterKey(pKey256, pBuf256, (int)uRounds); Array.Copy(newKey, pBuf256, newKey.Length); #else Log.Warn("KP2A", "Transforming key managed!"); return false; #endif } catch(Exception e) { Kp2aLog.Log(e.Message); return false; } return true; } /// /// Benchmark key transformation. /// /// Number of seconds to perform the benchmark. /// Number of transformations done. /// Returns true, if the benchmark was successful. public static bool TransformKeyBenchmark256(uint uTimeMs, out ulong puRounds) { puRounds = 0; if(m_bAllowNative == false) return false; try { puRounds = NativeMethods.TransformKeyBenchmark(uTimeMs); } catch(Exception) { return false; } return true; } private static KeyValuePair PrepareArrays256(byte[] pBuf256, byte[] pKey256) { Debug.Assert((pBuf256 != null) && (pBuf256.Length == 32)); if(pBuf256 == null) throw new ArgumentNullException("pBuf256"); if(pBuf256.Length != 32) throw new ArgumentException(); Debug.Assert((pKey256 != null) && (pKey256.Length == 32)); if(pKey256 == null) throw new ArgumentNullException("pKey256"); if(pKey256.Length != 32) throw new ArgumentException(); IntPtr hBuf = Marshal.AllocHGlobal(pBuf256.Length); Marshal.Copy(pBuf256, 0, hBuf, pBuf256.Length); IntPtr hKey = Marshal.AllocHGlobal(pKey256.Length); Marshal.Copy(pKey256, 0, hKey, pKey256.Length); return new KeyValuePair(hBuf, hKey); } private static void GetBuffers256(KeyValuePair kvpSource, byte[] pbDestBuf, byte[] pbDestKey) { if(kvpSource.Key != IntPtr.Zero) Marshal.Copy(kvpSource.Key, pbDestBuf, 0, pbDestBuf.Length); if(kvpSource.Value != IntPtr.Zero) Marshal.Copy(kvpSource.Value, pbDestKey, 0, pbDestKey.Length); } private static void FreeArrays(KeyValuePair kvpPointers) { if(kvpPointers.Key != IntPtr.Zero) Marshal.FreeHGlobal(kvpPointers.Key); if(kvpPointers.Value != IntPtr.Zero) Marshal.FreeHGlobal(kvpPointers.Value); } } }