private static SecureLocalAllocHandle Protect(byte *pbPlaintext, uint cbPlaintext) { // If we're not running on a platform that supports CryptProtectMemory, // shove the plaintext directly into a LocalAlloc handle. Ideally we'd // mark this memory page as non-pageable, but this is fraught with peril. if (!OSVersionUtil.IsWindows()) { SecureLocalAllocHandle handle = SecureLocalAllocHandle.Allocate((IntPtr) checked ((int)cbPlaintext)); UnsafeBufferUtil.BlockCopy(from: pbPlaintext, to: handle, byteCount: cbPlaintext); return(handle); } // We need to make sure we're a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE. uint numTotalBytesToAllocate = cbPlaintext; uint numBytesPaddingRequired = CRYPTPROTECTMEMORY_BLOCK_SIZE - (numTotalBytesToAllocate % CRYPTPROTECTMEMORY_BLOCK_SIZE); if (numBytesPaddingRequired == CRYPTPROTECTMEMORY_BLOCK_SIZE) { numBytesPaddingRequired = 0; // we're already a proper multiple of the block size } checked { numTotalBytesToAllocate += numBytesPaddingRequired; } CryptoUtil.Assert(numTotalBytesToAllocate % CRYPTPROTECTMEMORY_BLOCK_SIZE == 0, "numTotalBytesToAllocate % CRYPTPROTECTMEMORY_BLOCK_SIZE == 0"); // Allocate and copy plaintext data; padding is uninitialized / undefined. SecureLocalAllocHandle encryptedMemoryHandle = SecureLocalAllocHandle.Allocate((IntPtr)numTotalBytesToAllocate); UnsafeBufferUtil.BlockCopy(from: pbPlaintext, to: encryptedMemoryHandle, byteCount: cbPlaintext); // Finally, CryptProtectMemory the whole mess. if (numTotalBytesToAllocate != 0) { MemoryProtection.CryptProtectMemory(encryptedMemoryHandle, byteCount: numTotalBytesToAllocate); } return(encryptedMemoryHandle); }
public void Duplicate_Copies_Data() { // Arrange const string expected = "xyz"; int cbExpected = expected.Length * sizeof(char); var controlHandle = SecureLocalAllocHandle.Allocate((IntPtr)cbExpected); for (int i = 0; i < expected.Length; i++) { ((char *)controlHandle.DangerousGetHandle())[i] = expected[i]; } // Act var duplicateHandle = controlHandle.Duplicate(); // Assert Assert.Equal(expected, new string((char *)duplicateHandle.DangerousGetHandle(), 0, expected.Length)); // contents the same data Assert.NotEqual(controlHandle.DangerousGetHandle(), duplicateHandle.DangerousGetHandle()); // shouldn't just point to the same memory location }
private static LocalAllocHandle LocalAlloc(int cb) { return(SecureLocalAllocHandle.Allocate((IntPtr)cb)); }