エリックの答えにコメントするのに十分な評判ポイントがないので、この投稿をしなければなりません.
GCHandle.Alloc(workArray, ...)
私の意見では、Eric のコードは正しく行われていないため、問題があります。null
値を固定するのではworkArray
なく、数行下に作成される実際の配列を固定する必要があります。
さらにhandle.Free()
、 をスローできるため、少なくともバイナリ文字列がゼロを指すようにするInvalidOperationException
ために、それを後に配置することをお勧めします。Marshal.ZeroFreeBSTR(...)
bstr
修正されたコードは次のようになります。
public static T Process<T>(this SecureString src, Func<byte[], T> func)
{
IntPtr bstr = IntPtr.Zero;
byte[] workArray = null;
GCHandle? handle = null; // Change no. 1
try
{
/*** PLAINTEXT EXPOSURE BEGINS HERE ***/
bstr = Marshal.SecureStringToBSTR(src);
unsafe
{
byte* bstrBytes = (byte*)bstr;
workArray = new byte[src.Length * 2];
handle = GCHandle.Alloc(workArray, GCHandleType.Pinned); // Change no. 2
for (int i = 0; i < workArray.Length; i++)
workArray[i] = *bstrBytes++;
}
return func(workArray);
}
finally
{
if (workArray != null)
for (int i = 0; i < workArray.Length; i++)
workArray[i] = 0;
if (bstr != IntPtr.Zero)
Marshal.ZeroFreeBSTR(bstr);
handle?.Free(); // Change no. 3 (Edit: no try-catch but after Marshal.ZeroFreeBSTR)
/*** PLAINTEXT EXPOSURE ENDS HERE ***/
}
}
これらの変更により、正しいbyte
配列がメモリに固定されます (変更番号 1 と 2)。さらに、例外がスローされた場合に、暗号化されていないバイナリ文字列がメモリにロードされたままになることを回避しhandle?.Free()
ます (変更番号 3)。