26
26
/// Represents an object that is encrypted using a XOR pad until
27
/// it is read. The key XOR pad can be changed without revealing the
28
/// protected data in process memory.
27
/// it is read. <c>XorredBuffer</c> objects are immutable and
30
30
public sealed class XorredBuffer
32
private byte[] m_pbData = new byte[0]; // Never null
33
private byte[] m_pbXorPad = new byte[0]; // Never null
32
private byte[] m_pbData; // Never null
33
private byte[] m_pbXorPad; // Always valid for m_pbData
36
36
/// Length of the protected data in bytes.
45
45
/// and a XOR pad that decrypts the protected data. The
46
46
/// <paramref name="pbProtectedData" /> byte array must have the same size
47
47
/// as the <paramref name="pbXorPad" /> byte array.
48
/// The <c>XorredBuffer</c> object takes ownership of the two byte
49
/// arrays, i.e. the caller must not use or modify them afterwards.
49
51
/// <param name="pbProtectedData">Protected data (XOR pad applied).</param>
50
/// <param name="pbXorPad">XOR pad that is used to decrypt the
51
/// <paramref name="pbData" /> parameter.</param>
52
/// <param name="pbXorPad">XOR pad that can be used to decrypt the
53
/// <paramref name="pbProtectedData" /> parameter.</param>
52
54
/// <exception cref="System.ArgumentNullException">Thrown if one of the input
53
55
/// parameters is <c>null</c>.</exception>
54
56
/// <exception cref="System.ArgumentException">Thrown if the byte arrays are
55
57
/// of different size.</exception>
56
58
public XorredBuffer(byte[] pbProtectedData, byte[] pbXorPad)
58
Debug.Assert(pbProtectedData != null); if(pbProtectedData == null) throw new ArgumentNullException("pbProtectedData");
59
Debug.Assert(pbXorPad != null); if(pbXorPad == null) throw new ArgumentNullException("pbXorPad");
60
if(pbProtectedData == null) { Debug.Assert(false); throw new ArgumentNullException("pbProtectedData"); }
61
if(pbXorPad == null) { Debug.Assert(false); throw new ArgumentNullException("pbXorPad"); }
61
63
Debug.Assert(pbProtectedData.Length == pbXorPad.Length);
62
64
if(pbProtectedData.Length != pbXorPad.Length) throw new ArgumentException();
65
67
m_pbXorPad = pbXorPad;
68
private void Decrypt()
70
Debug.Assert((m_pbData.Length == m_pbXorPad.Length) || (m_pbXorPad.Length == 0));
72
if(m_pbData.Length == m_pbXorPad.Length)
74
for(int i = 0; i < m_pbData.Length; ++i)
75
m_pbData[i] ^= m_pbXorPad[i];
77
m_pbXorPad = new byte[0];
82
/// Decrypt the buffer. The <c>XorredBuffer</c> protection is useless
83
/// after you used this method. The object cannot be re-encrypted.
71
/// Get a copy of the plain-text. The caller is responsible
72
/// for clearing the byte array safely after using it.
85
74
/// <returns>Unprotected plain-text byte array.</returns>
86
75
public byte[] ReadPlainText()
93
/// Change the protection key for this <c>XorredBuffer</c> object.
94
/// The data will first be decrypted using the old key and then
95
/// re-encrypted using the new key. This operation doesn't reveal
96
/// the plain-text in the process memory.
98
/// <param name="pbNewXorPad">New protection pad. Must contain exactly
99
/// the same number of bytes as the length of the currently protected data.
100
/// Use the <c>Length</c> property of the <c>XorredBuffer</c> to query
101
/// the data length and pass a correct number of bytes to <c>ChangeKey</c>.</param>
102
/// <returns>New protected data (encrypted using the new XOR pad).</returns>
103
/// <exception cref="System.ArgumentNullException">Thrown if the input
104
/// parameter is <c>null</c>.</exception>
105
/// <exception cref="System.ArgumentException">Thrown if the input
106
/// byte array doesn't have the correct size.</exception>
107
public byte[] ChangeKey(byte[] pbNewXorPad)
109
Debug.Assert(pbNewXorPad != null); if(pbNewXorPad == null) throw new ArgumentNullException("pbNewXorPad");
111
Debug.Assert(pbNewXorPad.Length == m_pbData.Length);
112
if(pbNewXorPad.Length != m_pbData.Length) throw new ArgumentException();
114
if(m_pbXorPad.Length == m_pbData.Length) // Data is protected
116
for(int i = 0; i < m_pbData.Length; ++i)
117
m_pbData[i] ^= (byte)(m_pbXorPad[i] ^ pbNewXorPad[i]);
119
else // Data is unprotected
121
for(int i = 0; i < m_pbData.Length; ++i)
122
m_pbData[i] ^= pbNewXorPad[i];
125
m_pbXorPad = pbNewXorPad;
129
public bool EqualsValue(XorredBuffer xb)
77
byte[] pbPlain = new byte[m_pbData.Length];
79
for(int i = 0; i < pbPlain.Length; ++i)
80
pbPlain[i] = (byte)(m_pbData[i] ^ m_pbXorPad[i]);
85
/* public bool EqualsValue(XorredBuffer xb)
131
87
if(xb == null) { Debug.Assert(false); throw new ArgumentNullException("xb"); }
133
89
if(xb.m_pbData.Length != m_pbData.Length) return false;
135
bool bDecThis = (m_pbData.Length == m_pbXorPad.Length);
136
bool bDecOther = (xb.m_pbData.Length == xb.m_pbXorPad.Length);
137
91
for(int i = 0; i < m_pbData.Length; ++i)
139
byte bt1 = m_pbData[i];
140
if(bDecThis) bt1 ^= m_pbXorPad[i];
142
byte bt2 = xb.m_pbData[i];
143
if(bDecOther) bt2 ^= xb.m_pbXorPad[i];
93
byte bt1 = (byte)(m_pbData[i] ^ m_pbXorPad[i]);
94
byte bt2 = (byte)(xb.m_pbData[i] ^ xb.m_pbXorPad[i]);
145
96
if(bt1 != bt2) return false;
155
106
if(pb.Length != m_pbData.Length) return false;
157
if(m_pbData.Length == m_pbXorPad.Length)
159
for(int i = 0; i < m_pbData.Length; ++i)
161
if((byte)(m_pbData[i] ^ m_pbXorPad[i]) != pb[i]) return false;
166
108
for(int i = 0; i < m_pbData.Length; ++i)
168
if(m_pbData[i] != pb[i]) return false;
110
if((byte)(m_pbData[i] ^ m_pbXorPad[i]) != pb[i]) return false;
174
/// XOR all bytes in a data buffer with a pad. Both byte arrays must
175
/// be of the same size.
177
/// <param name="pbData">Data to be protected.</param>
178
/// <param name="pbPad">XOR pad.</param>
179
/// <exception cref="System.ArgumentNullException">Thrown if one of the
180
/// parameters is <c>null</c>.</exception>
181
/// <exception cref="System.ArgumentException">Thrown if the length of
182
/// the data array and the pad aren't equal.</exception>
183
[Obsolete("Use MemUtil.XorArray instead.")]
184
public static void XorArrays(byte[] pbData, byte[] pbPad)
186
Debug.Assert(pbData != null); if(pbData == null) throw new ArgumentNullException("pbData");
187
Debug.Assert(pbPad != null); if(pbPad == null) throw new ArgumentNullException("pbPad");
189
Debug.Assert(pbData.Length == pbPad.Length);
190
if(pbData.Length != pbPad.Length) throw new ArgumentException();
192
for(int i = 0; i < pbData.Length; ++i)
193
pbData[i] ^= pbPad[i];