mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-04 16:10:16 -04:00
ModernKeePassLib custom PCL version
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
KeePass Password Safe - The Open-Source Password Manager
|
||||
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
|
||||
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
|
||||
|
||||
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
|
||||
@@ -18,170 +18,307 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
|
||||
using ModernKeePassLib.Utility;
|
||||
using ModernKeePassLib.Cryptography;
|
||||
using Windows.Security.Cryptography;
|
||||
using Windows.Security.Cryptography.DataProtection;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
using ModernKeePassLib.Cryptography.Cipher;
|
||||
using ModernKeePassLib.Utility;
|
||||
|
||||
#if KeePassLibSD
|
||||
using ModernKeePassLibSD;
|
||||
using KeePassLibSD;
|
||||
#endif
|
||||
|
||||
namespace ModernKeePassLib.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a protected binary, i.e. a byte array that is encrypted
|
||||
/// in memory. A <c>ProtectedBinary</c> object is immutable and
|
||||
/// thread-safe.
|
||||
/// </summary>
|
||||
public sealed class ProtectedBinary : IEquatable<ProtectedBinary>
|
||||
{
|
||||
private static bool m_bProtectionSupported;
|
||||
private IBuffer m_pbDataCrypted;
|
||||
private DataProtectionProvider m_pProvider;
|
||||
private bool m_bProtected;
|
||||
[Flags]
|
||||
public enum PbCryptFlags
|
||||
{
|
||||
None = 0,
|
||||
Encrypt = 1,
|
||||
Decrypt = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A flag specifying whether the <c>ProtectedBinary</c> object has
|
||||
/// turned on in-memory protection or not.
|
||||
/// </summary>
|
||||
public bool IsProtected
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(false, "not yet implemented");
|
||||
public delegate void PbCryptDelegate(byte[] pbData, PbCryptFlags cf,
|
||||
long lID);
|
||||
|
||||
/// <summary>
|
||||
/// Represents a protected binary, i.e. a byte array that is encrypted
|
||||
/// in memory. A <c>ProtectedBinary</c> object is immutable and
|
||||
/// thread-safe.
|
||||
/// </summary>
|
||||
public sealed class ProtectedBinary : IEquatable<ProtectedBinary>
|
||||
{
|
||||
private const int BlockSize = 16;
|
||||
|
||||
private static PbCryptDelegate g_fExtCrypt = null;
|
||||
/// <summary>
|
||||
/// A plugin can provide a custom memory protection method
|
||||
/// by assigning a non-null delegate to this property.
|
||||
/// </summary>
|
||||
public static PbCryptDelegate ExtCrypt
|
||||
{
|
||||
get { return g_fExtCrypt; }
|
||||
set { g_fExtCrypt = value; }
|
||||
}
|
||||
|
||||
// Local copy of the delegate that was used for encryption,
|
||||
// in order to allow correct decryption even when the global
|
||||
// delegate changes
|
||||
private PbCryptDelegate m_fExtCrypt = null;
|
||||
|
||||
private enum PbMemProt
|
||||
{
|
||||
None = 0,
|
||||
ProtectedMemory,
|
||||
Salsa20,
|
||||
ExtCrypt
|
||||
}
|
||||
|
||||
// ProtectedMemory is supported only on Windows 2000 SP3 and higher
|
||||
#if !KeePassLibSD
|
||||
private static bool? g_bProtectedMemorySupported = null;
|
||||
#endif
|
||||
private static bool ProtectedMemorySupported
|
||||
{
|
||||
get
|
||||
{
|
||||
#if KeePassLibSD
|
||||
return false;
|
||||
#elif PCL
|
||||
return false;
|
||||
#if TODO
|
||||
return m_bProtected;
|
||||
#else
|
||||
bool? ob = g_bProtectedMemorySupported;
|
||||
if(ob.HasValue) return ob.Value;
|
||||
|
||||
// Mono does not implement any encryption for ProtectedMemory;
|
||||
// https://sourceforge.net/p/keepass/feature-requests/1907/
|
||||
/*if(NativeLib.IsUnix())
|
||||
{
|
||||
g_bProtectedMemorySupported = false;
|
||||
return false;
|
||||
}*/
|
||||
|
||||
ob = false;
|
||||
try // Test whether ProtectedMemory is supported
|
||||
{
|
||||
// BlockSize * 3 in order to test encryption for multiple
|
||||
// blocks, but not introduce a power of 2 as factor
|
||||
byte[] pb = new byte[ProtectedBinary.BlockSize * 3];
|
||||
for(int i = 0; i < pb.Length; ++i) pb[i] = (byte)i;
|
||||
|
||||
ProtectedMemory.Protect(pb, MemoryProtectionScope.SameProcess);
|
||||
|
||||
for(int i = 0; i < pb.Length; ++i)
|
||||
{
|
||||
if(pb[i] != (byte)i) { ob = true; break; }
|
||||
}
|
||||
}
|
||||
catch(Exception) { } // Windows 98 / ME
|
||||
|
||||
g_bProtectedMemorySupported = ob;
|
||||
return ob.Value;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Length of the stored data.
|
||||
/// </summary>
|
||||
public uint Length
|
||||
{
|
||||
get
|
||||
{
|
||||
private static long g_lCurID = 0;
|
||||
private long m_lID;
|
||||
|
||||
Debug.Assert(false, "not yet implemented");
|
||||
return 0;
|
||||
#if TODO
|
||||
return m_uDataLen;
|
||||
private byte[] m_pbData; // Never null
|
||||
|
||||
// The real length of the data; this value can be different from
|
||||
// m_pbData.Length, as the length of m_pbData always is a multiple
|
||||
// of BlockSize (required for ProtectedMemory)
|
||||
private uint m_uDataLen;
|
||||
|
||||
private bool m_bProtected; // Protection requested by the caller
|
||||
|
||||
private PbMemProt m_mp = PbMemProt.None; // Actual protection
|
||||
|
||||
private object m_objSync = new object();
|
||||
|
||||
private static byte[] g_pbKey32 = null;
|
||||
|
||||
/// <summary>
|
||||
/// A flag specifying whether the <c>ProtectedBinary</c> object has
|
||||
/// turned on memory protection or not.
|
||||
/// </summary>
|
||||
public bool IsProtected
|
||||
{
|
||||
get { return m_bProtected; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Length of the stored data.
|
||||
/// </summary>
|
||||
public uint Length
|
||||
{
|
||||
get { return m_uDataLen; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new, empty protected binary data object.
|
||||
/// Protection is disabled.
|
||||
/// </summary>
|
||||
public ProtectedBinary()
|
||||
{
|
||||
Init(false, new byte[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new protected binary data object.
|
||||
/// </summary>
|
||||
/// <param name="bEnableProtection">If this paremeter is <c>true</c>,
|
||||
/// the data will be encrypted in memory. If it is <c>false</c>, the
|
||||
/// data is stored in plain-text in the process memory.</param>
|
||||
/// <param name="pbData">Value of the protected object.
|
||||
/// The input parameter is not modified and
|
||||
/// <c>ProtectedBinary</c> doesn't take ownership of the data,
|
||||
/// i.e. the caller is responsible for clearing it.</param>
|
||||
public ProtectedBinary(bool bEnableProtection, byte[] pbData)
|
||||
{
|
||||
Init(bEnableProtection, pbData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new protected binary data object. Copy the data from
|
||||
/// a <c>XorredBuffer</c> object.
|
||||
/// </summary>
|
||||
/// <param name="bEnableProtection">Enable protection or not.</param>
|
||||
/// <param name="xbProtected"><c>XorredBuffer</c> object used to
|
||||
/// initialize the <c>ProtectedBinary</c> object.</param>
|
||||
public ProtectedBinary(bool bEnableProtection, XorredBuffer xbProtected)
|
||||
{
|
||||
Debug.Assert(xbProtected != null);
|
||||
if(xbProtected == null) throw new ArgumentNullException("xbProtected");
|
||||
|
||||
byte[] pb = xbProtected.ReadPlainText();
|
||||
Init(bEnableProtection, pb);
|
||||
MemUtil.ZeroByteArray(pb);
|
||||
}
|
||||
|
||||
private void Init(bool bEnableProtection, byte[] pbData)
|
||||
{
|
||||
if(pbData == null) throw new ArgumentNullException("pbData");
|
||||
|
||||
#if KeePassLibSD
|
||||
m_lID = ++g_lCurID;
|
||||
#else
|
||||
m_lID = Interlocked.Increment(ref g_lCurID);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static ProtectedBinary()
|
||||
{
|
||||
m_bProtectionSupported = true;
|
||||
}
|
||||
m_bProtected = bEnableProtection;
|
||||
m_uDataLen = (uint)pbData.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new, empty protected binary data object. Protection
|
||||
/// is disabled.
|
||||
/// </summary>
|
||||
public ProtectedBinary()
|
||||
{
|
||||
Init(false, new byte[0]);
|
||||
}
|
||||
const int bs = ProtectedBinary.BlockSize;
|
||||
int nBlocks = (int)m_uDataLen / bs;
|
||||
if((nBlocks * bs) < (int)m_uDataLen) ++nBlocks;
|
||||
Debug.Assert((nBlocks * bs) >= (int)m_uDataLen);
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new protected binary data object.
|
||||
/// </summary>
|
||||
/// <param name="bEnableProtection">If this paremeter is <c>true</c>,
|
||||
/// the data will be encrypted in memory. If it is <c>false</c>, the
|
||||
/// data is stored in plain-text in the process memory.</param>
|
||||
/// <param name="pbData">Value of the protected object.
|
||||
/// The input parameter is not modified and
|
||||
/// <c>ProtectedBinary</c> doesn't take ownership of the data,
|
||||
/// i.e. the caller is responsible for clearing it.</param>
|
||||
public ProtectedBinary(bool bEnableProtection, byte[] pbData)
|
||||
{
|
||||
Init(bEnableProtection, pbData);
|
||||
}
|
||||
m_pbData = new byte[nBlocks * bs];
|
||||
Array.Copy(pbData, m_pbData, (int)m_uDataLen);
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new protected binary data object. Copy the data from
|
||||
/// a <c>XorredBuffer</c> object.
|
||||
/// </summary>
|
||||
/// <param name="bEnableProtection">Enable protection or not.</param>
|
||||
/// <param name="xbProtected"><c>XorredBuffer</c> object used to
|
||||
/// initialize the <c>ProtectedBinary</c> object.</param>
|
||||
/// <exception cref="System.ArgumentNullException">Thrown if the input
|
||||
/// parameter is <c>null</c>.</exception>
|
||||
public ProtectedBinary(bool bEnableProtection, XorredBuffer xbProtected)
|
||||
{
|
||||
Debug.Assert(xbProtected != null); if (xbProtected == null) throw new ArgumentNullException("xbProtected");
|
||||
Encrypt();
|
||||
}
|
||||
|
||||
byte[] pb = xbProtected.ReadPlainText();
|
||||
Init(bEnableProtection, pb);
|
||||
MemUtil.ZeroByteArray(pb);
|
||||
}
|
||||
private void Encrypt()
|
||||
{
|
||||
Debug.Assert(m_mp == PbMemProt.None);
|
||||
|
||||
private void Init(bool bEnableProtection, byte[] pbData)
|
||||
{
|
||||
String strDescriptor = "LOCAL=user";
|
||||
m_pProvider = new DataProtectionProvider(strDescriptor);
|
||||
// Nothing to do if caller didn't request protection
|
||||
if(!m_bProtected) return;
|
||||
|
||||
EncryptAsync(bEnableProtection, pbData);
|
||||
// ProtectedMemory.Protect throws for data size == 0
|
||||
if(m_pbData.Length == 0) return;
|
||||
|
||||
}
|
||||
PbCryptDelegate f = g_fExtCrypt;
|
||||
if(f != null)
|
||||
{
|
||||
f(m_pbData, PbCryptFlags.Encrypt, m_lID);
|
||||
|
||||
private void EncryptAsync(bool bEnableProtection, byte[] pbData)
|
||||
{
|
||||
IBuffer dataUncrypted = CryptographicBuffer.CreateFromByteArray(pbData);
|
||||
m_fExtCrypt = f;
|
||||
m_mp = PbMemProt.ExtCrypt;
|
||||
return;
|
||||
}
|
||||
|
||||
Task<IBuffer> task = m_pProvider.ProtectAsync(dataUncrypted).AsTask<IBuffer>();
|
||||
task.Wait();
|
||||
#if !PCL
|
||||
if(ProtectedBinary.ProtectedMemorySupported)
|
||||
{
|
||||
ProtectedMemory.Protect(m_pbData, MemoryProtectionScope.SameProcess);
|
||||
|
||||
m_pbDataCrypted = task.Result;
|
||||
// TODO: Here the dataUncrypted buffer should be cleared. Now just count on GarbageCollection to destroy.
|
||||
m_mp = PbMemProt.ProtectedMemory;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
byte[] pbKey32 = g_pbKey32;
|
||||
if(pbKey32 == null)
|
||||
{
|
||||
pbKey32 = CryptoRandom.Instance.GetRandomBytes(32);
|
||||
|
||||
}
|
||||
byte[] pbUpd = Interlocked.Exchange<byte[]>(ref g_pbKey32, pbKey32);
|
||||
if(pbUpd != null) pbKey32 = pbUpd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a copy of the protected data as a byte array.
|
||||
/// Please note that the returned byte array is not protected and
|
||||
/// can therefore been read by any other application.
|
||||
/// Make sure that your clear it properly after usage.
|
||||
/// </summary>
|
||||
/// <returns>Unprotected byte array. This is always a copy of the internal
|
||||
/// protected data and can therefore be cleared safely.</returns>
|
||||
public byte[] ReadData()
|
||||
{
|
||||
if (m_pbDataCrypted == null) return new byte[0];
|
||||
Salsa20Cipher s = new Salsa20Cipher(pbKey32,
|
||||
BitConverter.GetBytes(m_lID));
|
||||
s.Encrypt(m_pbData, m_pbData.Length, true);
|
||||
s.Dispose();
|
||||
m_mp = PbMemProt.Salsa20;
|
||||
}
|
||||
|
||||
// Decrypt the protected message specified on input.
|
||||
private void Decrypt()
|
||||
{
|
||||
if(m_pbData.Length == 0) return;
|
||||
#if !PCL
|
||||
if(m_mp == PbMemProt.ProtectedMemory)
|
||||
ProtectedMemory.Unprotect(m_pbData, MemoryProtectionScope.SameProcess);
|
||||
#endif
|
||||
else if(m_mp == PbMemProt.Salsa20)
|
||||
{
|
||||
Salsa20Cipher s = new Salsa20Cipher(g_pbKey32,
|
||||
BitConverter.GetBytes(m_lID));
|
||||
s.Encrypt(m_pbData, m_pbData.Length, true);
|
||||
s.Dispose();
|
||||
}
|
||||
else if(m_mp == PbMemProt.ExtCrypt)
|
||||
m_fExtCrypt(m_pbData, PbCryptFlags.Decrypt, m_lID);
|
||||
else { Debug.Assert(m_mp == PbMemProt.None); }
|
||||
|
||||
Task<IBuffer> task = m_pProvider.UnprotectAsync(m_pbDataCrypted).AsTask<IBuffer>();
|
||||
task.Wait();
|
||||
m_mp = PbMemProt.None;
|
||||
}
|
||||
|
||||
IBuffer buffUnprotected = task.Result;
|
||||
byte[] strClearText;
|
||||
CryptographicBuffer.CopyToByteArray(buffUnprotected, out strClearText);
|
||||
return strClearText;
|
||||
/// <summary>
|
||||
/// Get a copy of the protected data as a byte array.
|
||||
/// Please note that the returned byte array is not protected and
|
||||
/// can therefore been read by any other application.
|
||||
/// Make sure that your clear it properly after usage.
|
||||
/// </summary>
|
||||
/// <returns>Unprotected byte array. This is always a copy of the internal
|
||||
/// protected data and can therefore be cleared safely.</returns>
|
||||
public byte[] ReadData()
|
||||
{
|
||||
if(m_uDataLen == 0) return new byte[0];
|
||||
|
||||
}
|
||||
byte[] pbReturn = new byte[m_uDataLen];
|
||||
|
||||
/// <summary>
|
||||
/// Read the protected data and return it protected with a sequence
|
||||
/// of bytes generated by a random stream.
|
||||
/// </summary>
|
||||
/// <param name="crsRandomSource">Random number source.</param>
|
||||
/// <returns>Protected data.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">Thrown if the input
|
||||
/// parameter is <c>null</c>.</exception>
|
||||
public byte[] ReadXorredData(CryptoRandomStream crsRandomSource)
|
||||
{
|
||||
Debug.Assert(false, "not yet implemented");
|
||||
return null;
|
||||
#if TODO
|
||||
lock(m_objSync)
|
||||
{
|
||||
Decrypt();
|
||||
Array.Copy(m_pbData, pbReturn, (int)m_uDataLen);
|
||||
Encrypt();
|
||||
}
|
||||
|
||||
return pbReturn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the protected data and return it protected with a sequence
|
||||
/// of bytes generated by a random stream.
|
||||
/// </summary>
|
||||
/// <param name="crsRandomSource">Random number source.</param>
|
||||
public byte[] ReadXorredData(CryptoRandomStream crsRandomSource)
|
||||
{
|
||||
Debug.Assert(crsRandomSource != null);
|
||||
if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource");
|
||||
|
||||
@@ -189,20 +326,19 @@ namespace ModernKeePassLib.Security
|
||||
uint uLen = (uint)pbData.Length;
|
||||
|
||||
byte[] randomPad = crsRandomSource.GetRandomBytes(uLen);
|
||||
Debug.Assert(randomPad.Length == uLen);
|
||||
Debug.Assert(randomPad.Length == pbData.Length);
|
||||
|
||||
for(uint i = 0; i < uLen; ++i)
|
||||
pbData[i] ^= randomPad[i];
|
||||
|
||||
return pbData;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private int? m_hash = null;
|
||||
public override int GetHashCode()
|
||||
{
|
||||
if(m_hash.HasValue) return m_hash.Value;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
Debug.Assert(false, "not yet implemented");
|
||||
return 0;
|
||||
#if TODO
|
||||
int h = (m_bProtected ? 0x7B11D289 : 0);
|
||||
|
||||
byte[] pb = ReadData();
|
||||
@@ -213,20 +349,17 @@ namespace ModernKeePassLib.Security
|
||||
}
|
||||
MemUtil.ZeroByteArray(pb);
|
||||
|
||||
m_hash = h;
|
||||
return h;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as ProtectedBinary);
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as ProtectedBinary);
|
||||
}
|
||||
|
||||
public bool Equals(ProtectedBinary other)
|
||||
{
|
||||
Debug.Assert(false, "not yet implemented");
|
||||
return false;
|
||||
#if TODO
|
||||
public bool Equals(ProtectedBinary other)
|
||||
{
|
||||
if(other == null) return false; // No assert
|
||||
|
||||
if(m_bProtected != other.m_bProtected) return false;
|
||||
@@ -243,7 +376,6 @@ namespace ModernKeePassLib.Security
|
||||
#endif
|
||||
|
||||
return bEq;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
KeePass Password Safe - The Open-Source Password Manager
|
||||
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
|
||||
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
|
||||
|
||||
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
|
||||
@@ -23,10 +23,9 @@ using System.Diagnostics;
|
||||
|
||||
using ModernKeePassLib.Cryptography;
|
||||
using ModernKeePassLib.Utility;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
#if KeePassLibSD
|
||||
using ModernKeePassLibSD;
|
||||
using KeePassLibSD;
|
||||
#endif
|
||||
|
||||
// SecureString objects are limited to 65536 characters, don't use
|
||||
@@ -48,7 +47,7 @@ namespace ModernKeePassLib.Security
|
||||
|
||||
private bool m_bIsProtected;
|
||||
|
||||
private static ProtectedString m_psEmpty = new ProtectedString();
|
||||
private static readonly ProtectedString m_psEmpty = new ProtectedString();
|
||||
public static ProtectedString Empty
|
||||
{
|
||||
get { return m_psEmpty; }
|
||||
@@ -56,7 +55,7 @@ namespace ModernKeePassLib.Security
|
||||
|
||||
/// <summary>
|
||||
/// A flag specifying whether the <c>ProtectedString</c> object
|
||||
/// has turned on in-memory protection or not.
|
||||
/// has turned on memory protection or not.
|
||||
/// </summary>
|
||||
public bool IsProtected
|
||||
{
|
||||
@@ -80,10 +79,6 @@ namespace ModernKeePassLib.Security
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
Debug.Assert(false, "not yet implemented");
|
||||
return 0;
|
||||
#if TODO
|
||||
if(m_nCachedLength >= 0) return m_nCachedLength;
|
||||
|
||||
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
|
||||
@@ -100,7 +95,6 @@ namespace ModernKeePassLib.Security
|
||||
}
|
||||
|
||||
return m_nCachedLength;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,10 +112,9 @@ namespace ModernKeePassLib.Security
|
||||
/// to the value supplied in the parameters.
|
||||
/// </summary>
|
||||
/// <param name="bEnableProtection">If this parameter is <c>true</c>,
|
||||
/// the string will be protected in-memory (encrypted). If it
|
||||
/// the string will be protected in memory (encrypted). If it
|
||||
/// is <c>false</c>, the string will be stored as plain-text.</param>
|
||||
/// <param name="strValue">The initial string value. This
|
||||
/// parameter won't be modified.</param>
|
||||
/// <param name="strValue">The initial string value.</param>
|
||||
public ProtectedString(bool bEnableProtection, string strValue)
|
||||
{
|
||||
Init(bEnableProtection, strValue);
|
||||
@@ -132,7 +125,7 @@ namespace ModernKeePassLib.Security
|
||||
/// to the value supplied in the parameters (UTF-8 encoded string).
|
||||
/// </summary>
|
||||
/// <param name="bEnableProtection">If this parameter is <c>true</c>,
|
||||
/// the string will be protected in-memory (encrypted). If it
|
||||
/// the string will be protected in memory (encrypted). If it
|
||||
/// is <c>false</c>, the string will be stored as plain-text.</param>
|
||||
/// <param name="vUtf8Value">The initial string value, encoded as
|
||||
/// UTF-8 byte array. This parameter won't be modified; the caller
|
||||
@@ -150,10 +143,9 @@ namespace ModernKeePassLib.Security
|
||||
/// <param name="xbProtected"><c>XorredBuffer</c> object containing the
|
||||
/// string in UTF-8 representation. The UTF-8 string must not
|
||||
/// be <c>null</c>-terminated.</param>
|
||||
/// <exception cref="System.ArgumentNullException">Thrown if the input
|
||||
/// parameter is <c>null</c>.</exception>
|
||||
public ProtectedString(bool bEnableProtection, XorredBuffer xbProtected)
|
||||
{
|
||||
Debug.Assert(xbProtected != null);
|
||||
if(xbProtected == null) throw new ArgumentNullException("xbProtected");
|
||||
|
||||
byte[] pb = xbProtected.ReadPlainText();
|
||||
@@ -196,7 +188,6 @@ namespace ModernKeePassLib.Security
|
||||
if(m_strPlainText != null) return m_strPlainText;
|
||||
|
||||
byte[] pb = ReadUtf8();
|
||||
|
||||
string str = ((pb.Length == 0) ? string.Empty :
|
||||
StrUtil.Utf8.GetString(pb, 0, pb.Length));
|
||||
// No need to clear pb
|
||||
@@ -218,11 +209,7 @@ namespace ModernKeePassLib.Security
|
||||
public byte[] ReadUtf8()
|
||||
{
|
||||
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
|
||||
|
||||
if (pBin != null)
|
||||
{
|
||||
return pBin.ReadData();
|
||||
}
|
||||
if(pBin != null) return pBin.ReadData();
|
||||
|
||||
return StrUtil.Utf8.GetBytes(m_strPlainText);
|
||||
}
|
||||
@@ -233,8 +220,6 @@ namespace ModernKeePassLib.Security
|
||||
/// </summary>
|
||||
/// <param name="crsRandomSource">Random number source.</param>
|
||||
/// <returns>Protected string.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">Thrown if the input
|
||||
/// parameter is <c>null</c>.</exception>
|
||||
public byte[] ReadXorredString(CryptoRandomStream crsRandomSource)
|
||||
{
|
||||
Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource");
|
||||
@@ -243,7 +228,7 @@ namespace ModernKeePassLib.Security
|
||||
uint uLen = (uint)pbData.Length;
|
||||
|
||||
byte[] randomPad = crsRandomSource.GetRandomBytes(uLen);
|
||||
Debug.Assert(randomPad.Length == uLen);
|
||||
Debug.Assert(randomPad.Length == pbData.Length);
|
||||
|
||||
for(uint i = 0; i < uLen; ++i)
|
||||
pbData[i] ^= randomPad[i];
|
||||
@@ -260,5 +245,100 @@ namespace ModernKeePassLib.Security
|
||||
MemUtil.ZeroByteArray(pb);
|
||||
return ps;
|
||||
}
|
||||
|
||||
public ProtectedString Insert(int iStart, string strInsert)
|
||||
{
|
||||
if(iStart < 0) throw new ArgumentOutOfRangeException("iStart");
|
||||
if(strInsert == null) throw new ArgumentNullException("strInsert");
|
||||
if(strInsert.Length == 0) return this;
|
||||
|
||||
// Only operate directly with strings when m_bIsProtected is
|
||||
// false, not in the case of non-null m_strPlainText, because
|
||||
// the operation creates a new sequence in memory
|
||||
if(!m_bIsProtected)
|
||||
return new ProtectedString(false, ReadString().Insert(
|
||||
iStart, strInsert));
|
||||
|
||||
UTF8Encoding utf8 = StrUtil.Utf8;
|
||||
|
||||
byte[] pb = ReadUtf8();
|
||||
char[] v = utf8.GetChars(pb);
|
||||
char[] vNew;
|
||||
|
||||
try
|
||||
{
|
||||
if(iStart > v.Length)
|
||||
throw new ArgumentOutOfRangeException("iStart");
|
||||
|
||||
char[] vIns = strInsert.ToCharArray();
|
||||
|
||||
vNew = new char[v.Length + vIns.Length];
|
||||
Array.Copy(v, 0, vNew, 0, iStart);
|
||||
Array.Copy(vIns, 0, vNew, iStart, vIns.Length);
|
||||
Array.Copy(v, iStart, vNew, iStart + vIns.Length,
|
||||
v.Length - iStart);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Array.Clear(v, 0, v.Length);
|
||||
MemUtil.ZeroByteArray(pb);
|
||||
}
|
||||
|
||||
byte[] pbNew = utf8.GetBytes(vNew);
|
||||
ProtectedString ps = new ProtectedString(m_bIsProtected, pbNew);
|
||||
|
||||
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
|
||||
ReadString().Insert(iStart, strInsert));
|
||||
|
||||
Array.Clear(vNew, 0, vNew.Length);
|
||||
MemUtil.ZeroByteArray(pbNew);
|
||||
return ps;
|
||||
}
|
||||
|
||||
public ProtectedString Remove(int iStart, int nCount)
|
||||
{
|
||||
if(iStart < 0) throw new ArgumentOutOfRangeException("iStart");
|
||||
if(nCount < 0) throw new ArgumentOutOfRangeException("nCount");
|
||||
if(nCount == 0) return this;
|
||||
|
||||
// Only operate directly with strings when m_bIsProtected is
|
||||
// false, not in the case of non-null m_strPlainText, because
|
||||
// the operation creates a new sequence in memory
|
||||
if(!m_bIsProtected)
|
||||
return new ProtectedString(false, ReadString().Remove(
|
||||
iStart, nCount));
|
||||
|
||||
UTF8Encoding utf8 = StrUtil.Utf8;
|
||||
|
||||
byte[] pb = ReadUtf8();
|
||||
char[] v = utf8.GetChars(pb);
|
||||
char[] vNew;
|
||||
|
||||
try
|
||||
{
|
||||
if((iStart + nCount) > v.Length)
|
||||
throw new ArgumentException("iStart + nCount");
|
||||
|
||||
vNew = new char[v.Length - nCount];
|
||||
Array.Copy(v, 0, vNew, 0, iStart);
|
||||
Array.Copy(v, iStart + nCount, vNew, iStart, v.Length -
|
||||
(iStart + nCount));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Array.Clear(v, 0, v.Length);
|
||||
MemUtil.ZeroByteArray(pb);
|
||||
}
|
||||
|
||||
byte[] pbNew = utf8.GetBytes(vNew);
|
||||
ProtectedString ps = new ProtectedString(m_bIsProtected, pbNew);
|
||||
|
||||
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
|
||||
ReadString().Remove(iStart, nCount));
|
||||
|
||||
Array.Clear(vNew, 0, vNew.Length);
|
||||
MemUtil.ZeroByteArray(pbNew);
|
||||
return ps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
KeePass Password Safe - The Open-Source Password Manager
|
||||
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
|
||||
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
|
||||
|
||||
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
|
||||
|
Reference in New Issue
Block a user