/// <summary> /// Creates a new Secret from another secret object. /// </summary> public Secret(ISecret secret) { if (secret == null) { throw new ArgumentNullException(nameof(secret)); } Secret other = secret as Secret; if (other != null) { // Fast-track: simple deep copy scenario. this._localAllocHandle = other._localAllocHandle.Duplicate(); this._plaintextLength = other._plaintextLength; } else { // Copy the secret to a temporary managed buffer, then protect the buffer. // We pin the temp buffer and zero it out when we're finished to limit exposure of the secret. byte[] tempPlaintextBuffer = new byte[secret.Length]; fixed(byte *pbTempPlaintextBuffer = tempPlaintextBuffer) { try { secret.WriteSecretIntoBuffer(new ArraySegment <byte>(tempPlaintextBuffer)); _localAllocHandle = Protect(pbTempPlaintextBuffer, (uint)tempPlaintextBuffer.Length); _plaintextLength = (uint)tempPlaintextBuffer.Length; } finally { UnsafeBufferUtil.SecureZeroMemory(pbTempPlaintextBuffer, tempPlaintextBuffer.Length); } } } }
/// <summary> /// Creates a new Secret from the provided input value, where the input value /// is specified as an array segment. /// </summary> public Secret(ArraySegment <byte> value) { value.Validate(); _localAllocHandle = Protect(value); _plaintextLength = (uint)value.Count; }
public SecureLocalAllocHandle Duplicate() { SecureLocalAllocHandle duplicateHandle = Allocate(_cb); UnsafeBufferUtil.BlockCopy(from: this, to: duplicateHandle, length: _cb); return(duplicateHandle); }
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); }
/// <summary> /// Allocates some amount of memory using LocalAlloc. /// </summary> public static SecureLocalAllocHandle Allocate(IntPtr cb) { SecureLocalAllocHandle newHandle = new SecureLocalAllocHandle(cb); newHandle.AllocateImpl(cb); return(newHandle); }
public ProtectedMemoryBlob(ArraySegment <byte> plaintext) { plaintext.Validate(); _localAllocHandle = Protect(plaintext); _plaintextLength = (uint)plaintext.Count; }
/// <summary> /// Creates a new Secret from the provided input value, where the input value /// is specified as a pointer to unmanaged memory. /// </summary> public Secret(byte *secret, int secretLength) { if (secret == null) { throw new ArgumentNullException(nameof(secret)); } if (secretLength < 0) { throw Error.Common_ValueMustBeNonNegative(nameof(secretLength)); } _localAllocHandle = Protect(secret, (uint)secretLength); _plaintextLength = (uint)secretLength; }
public ProtectedMemoryBlob(byte *plaintext, int plaintextLength) { if (plaintext == null) { throw new ArgumentNullException("plaintext"); } if (plaintextLength < 0) { throw new ArgumentOutOfRangeException("plaintextLength"); } _localAllocHandle = Protect(plaintext, (uint)plaintextLength); _plaintextLength = (uint)plaintextLength; }
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)); }