private unsafe IntPtr Digest(ProtectedMemory protectedMemory) { Init(protectedMemory.ContentLength, out int contentLength, out int blockCount, out int allocatedSize, out IntPtr hMessageBuffer); byte *messageBuffer = (byte *)hMessageBuffer; using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedMemory)) { if ((contentLength & 1) == 1) { byte *pProtectedMemory = (byte *)access.Handle; for (int i = 0; i < contentLength; i++) { messageBuffer[i] = pProtectedMemory[i]; } } else { ushort *pProtectedMemory = (ushort *)access.Handle; ushort *pMessageBuffer = (ushort *)hMessageBuffer; for (int i = 0; i < (contentLength / 2); i++) { pMessageBuffer[i] = pProtectedMemory[i]; } } } // append padding messageBuffer[contentLength] = 0x80; return(Compute(hMessageBuffer, allocatedSize, contentLength, blockCount)); }
public unsafe bool Equals(ProtectedStringBlock other) { if (Length != other.Length) { return(false); } using ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedMemory); using ProtectedMemoryAccess otherAccess = new ProtectedMemoryAccess(other.protectedMemory); byte *memory = (byte *)access.Handle; byte *otherMemory = (byte *)otherAccess.Handle; byte lastByte = 0; for (int i = 0; i < protectedMemory.Size; i++) { if (memory[i] != otherMemory[i]) { return(false); } if (memory[i] == 0 && lastByte == 0) { // null terminator reached return(true); } lastByte = memory[i]; } return(true); }
// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. private unsafe void KeyExpansion(ProtectedMemory protectedKey) { IntPtr hBuffer = Marshal.AllocHGlobal(4); byte * buffer = (byte *)hBuffer; using ProtectedMemoryAccess roundKeyAccess = new ProtectedMemoryAccess(protectedRoundKey); uint *roundKey = (uint *)roundKeyAccess.Handle; using (ProtectedMemoryAccess keyAccess = new ProtectedMemoryAccess(protectedKey)) { uint *key = (uint *)keyAccess.Handle; // The first round key is the key itself. for (int i = 0; i < Nk; i++) { roundKey[i] = key[i]; } } for (int i = Nk; i < Nb * (Nr + 1); i++) { *(uint *)buffer = roundKey[i - 1]; if ((i & 0x7) == 0) // if (i % 8 == 0) { RotateWord(buffer); SubWord(buffer); buffer[0] ^= RoundConstants[i / Nk]; } if ((i & 0x7) == 0x4) // if (i % 8 == 4) { SubWord(buffer); } roundKey[i] = roundKey[i - Nk] ^ buffer[0]; } Marshal.FreeHGlobal(hBuffer); }
internal unsafe void AesCbcDecryptBuffer(ref byte[] buffer) { IntPtr hIvBuffer = Marshal.AllocHGlobal(AesBlockLength); byte * ivBuffer = (byte *)hIvBuffer; using ProtectedMemoryAccess roundKeyAccess = new ProtectedMemoryAccess(protectedRoundKey); fixed(byte *pBuffer = buffer) { byte *roundKey = (byte *)roundKeyAccess.Handle; State state = new State(pBuffer); fixed(byte *originalIv = iv) { byte *iv = originalIv; for (int i = 0; i < buffer.Length; i += AesBlockLength) { Unsafe.CopyBlock(ivBuffer, state.Buffer, AesBlockLength); InverseCipher(state, roundKey); XorWithIv(state.Buffer, iv); Unsafe.CopyBlock(iv, ivBuffer, AesBlockLength); state.Buffer += AesBlockLength; } } } Marshal.FreeHGlobal(hIvBuffer); }
public bool Compare(ProtectedMemory protectedMemory, string hash) { ExtractHeader(hash, out int n, out int r, out int p, out byte[] salt, out byte[] expectedHash); using ProtectedMemory protectedResult = ComputeHashProtected(protectedMemory, n, r, p, expectedHash.Length, salt); byte[] result = new byte[expectedHash.Length]; using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedResult)) { Marshal.Copy(access.Handle, result, 0, result.Length); } return(SafeEquals(result, expectedHash)); }
public ProtectedMemory ComputeHashProtected(ProtectedMemory protectedMemory, int n, int r, int p, int desiredKeyLength, byte[] salt) { IntPtr hash = Digest(protectedMemory, salt, n, r, p, desiredKeyLength); ProtectedMemory protectedResult = ProtectedMemory.Allocate(desiredKeyLength); using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedResult)) { MarshalExtensions.Copy(hash, 0, access.Handle, 0, desiredKeyLength); } MarshalExtensions.ZeroFree(hash, desiredKeyLength); return(protectedResult); }
public ProtectedMemory ComputeHashProtected(ProtectedMemory protectedMemory) { IntPtr pHash = Digest(protectedMemory); ProtectedMemory result = ProtectedMemory.Allocate(digestLength); using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedMemory)) { MarshalExtensions.Copy(pHash, 0, access.Handle, 0, digestLength); } MarshalExtensions.ZeroMemory(pHash, digestLength); Marshal.FreeHGlobal(pHash); return(result); }
private unsafe ProtectedMemory DeriveAesKey(ProtectedMemory key) { using ProtectedMemory protectedBuffer = ProtectedMemory.Allocate(64); key.CopyTo(0, protectedBuffer, 0, 64); using (ProtectedMemoryAccess bufferAccess = new ProtectedMemoryAccess(protectedBuffer)) { ulong *buffer = (ulong *)bufferAccess.Handle; for (int i = 0; i < 64 / sizeof(ulong); i++) { buffer[i] ^= 0x36; } } Blake2bProtectedCryptoProvider blake2b = new Blake2bProtectedCryptoProvider(); return(blake2b.ComputeHashProtected(protectedBuffer, 32)); }
internal static unsafe int Apply(ProtectedMemory protectedMemory, uint dataLength, byte modulus) { byte paddedBytes = (byte)(modulus - (dataLength & (modulus - 1))); if (dataLength + paddedBytes > protectedMemory.ContentLength) { throw new ArgumentException("Buffer is to small to apply padding!", nameof(protectedMemory)); } using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedMemory)) { byte *buffer = (byte *)access.Handle; for (int i = 0; i < paddedBytes; i++) { buffer[dataLength + i] = paddedBytes; } } return(paddedBytes); }
public unsafe override ProtectedMemory ComputeHashProtected(ProtectedMemory protectedMemory) { IntPtr pHash = Digest(protectedMemory); ProtectedMemory result = ProtectedMemory.Allocate(digestLength); using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(result)) { ushort *source = (ushort *)pHash; ushort *destination = (ushort *)access.Handle; for (int i = 0; i < (digestLength / 2); i++) { destination[i] = source[i]; } } byte[] zeros = new byte[digestLength]; Marshal.Copy(zeros, 0, pHash, digestLength); Marshal.FreeHGlobal(pHash); return(result); }
public unsafe (IntPtr, int) ComputeHmacUnsafe(ProtectedMemory key, byte *message, int messageLength) { if (key.ContentLength > blockSize) { using ProtectedMemory reducedKey = ComputeHashProtected(key); return(ComputeHmacUnsafe(reducedKey, message, messageLength)); } using ProtectedMemory paddedKey = ProtectedMemory.Allocate(blockSize); key.CopyTo(0, paddedKey, 0, key.ContentLength); using ProtectedMemory outerKeyPadded = ProtectedMemory.Allocate(blockSize); using ProtectedMemory innerKeyPadded = ProtectedMemory.Allocate(blockSize); paddedKey.CopyTo(0, outerKeyPadded, 0, blockSize); paddedKey.CopyTo(0, innerKeyPadded, 0, blockSize); using (ProtectedMemoryAccess outerKeyAccess = new ProtectedMemoryAccess(outerKeyPadded)) { byte *outerKeyData = (byte *)outerKeyAccess.Handle; for (int i = 0; i < blockSize; i++) { outerKeyData[i] ^= 0x5c; } } using (ProtectedMemoryAccess innerKeyAccess = new ProtectedMemoryAccess(innerKeyPadded)) { byte *innerKeyData = (byte *)innerKeyAccess.Handle; for (int i = 0; i < blockSize; i++) { innerKeyData[i] ^= 0x36; } } using ProtectedMemory innerInput = ProtectedMemory.Allocate(blockSize + messageLength); innerKeyPadded.CopyTo(0, innerInput, 0, blockSize); using (ProtectedMemoryAccess innerAccess = new ProtectedMemoryAccess(innerInput)) { Unsafe.CopyBlock((byte *)innerAccess.Handle + blockSize, message, (uint)messageLength); } using ProtectedMemory innerHash = ComputeHashProtected(innerInput); using ProtectedMemory input = ProtectedMemory.Allocate(blockSize + digestLength); outerKeyPadded.CopyTo(0, input, 0, blockSize); innerHash.CopyTo(0, input, blockSize, digestLength); return(Digest(input), digestLength); }
internal static unsafe bool Validate(ProtectedMemory protectedMemory, uint dataLength, byte modulus) { byte expectedPaddingBytes = (byte)(modulus - (dataLength % modulus)); if (dataLength + expectedPaddingBytes > protectedMemory.ContentLength) { return(false); } using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedMemory)) { byte *buffer = (byte *)access.Handle; for (int i = 0; i < expectedPaddingBytes; i++) { if (buffer[dataLength + i] != expectedPaddingBytes) { return(false); } } } return(true); }
private unsafe IntPtr Digest(int digestLength, ProtectedMemory protectedMemory) { Blake2bHashState blake2 = default; blake2.Init(digestLength, null); int length = protectedMemory.ContentLength; IntPtr hInput = Marshal.AllocHGlobal(length); using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedMemory)) { MarshalExtensions.Copy(access.Handle, 0, hInput, 0, length); } byte *input = (byte *)hInput; blake2.Update(input, length); MarshalExtensions.ZeroMemory(hInput, length); Marshal.FreeHGlobal(hInput); IntPtr hash = blake2.Finish(); blake2.Free(); return(hash); }
internal unsafe void AesCbcEncryptBuffer(ProtectedMemory protectedBuffer) { fixed(byte *originalIv = iv) { byte *iv = originalIv; using ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedBuffer); using ProtectedMemoryAccess roundKeyAccess = new ProtectedMemoryAccess(protectedRoundKey); byte *buffer = (byte *)access.Handle; byte *roundKey = (byte *)roundKeyAccess.Handle; State state = new State(buffer); for (int i = 0; i < protectedBuffer.ContentLength; i += AesBlockLength) { XorWithIv(state.Buffer, iv); Cipher(state, roundKey); iv = state.Buffer; state.Buffer += AesBlockLength; } Marshal.Copy(new IntPtr(iv), this.iv, 0, this.iv.Length); } }
internal void Init(int digestLength, ProtectedMemory key) { uint keyLength = key == null ? 0u : (uint)(key?.ContentLength); hHash = Marshal.AllocHGlobal(HashSize); hash = (ulong *)hHash; hBlock = Marshal.AllocHGlobal(BlockSize); block = (byte *)hBlock; if (digestLength == 0 || (uint)digestLength > HashSize) { throw new ArgumentOutOfRangeException(nameof(digestLength), "Value must be between 1 and " + HashSize); } if (keyLength > MaxKeyBytes) { throw new ArgumentException("Key must be between 0 and " + MaxKeyBytes + " bytes in length", nameof(key)); } outlen = (uint)digestLength; fixed(byte *pIv = iv) { Unsafe.CopyBlock(hash, pIv, HashSize); } hash[0] ^= 0x01010000u ^ (keyLength << 8) ^ outlen; if (keyLength != 0) { MarshalExtensions.ZeroMemory(hBlock, BlockSize); using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(key)) { Unsafe.CopyBlockUnaligned(block, (byte *)access.Handle, keyLength); } c = BlockSize; } }
internal static unsafe int GetContentLength(ProtectedMemory protectedMemory, byte modulus) { int bufferSize = protectedMemory.ContentLength; /* test for valid buffer size */ if (((uint)bufferSize & (modulus - 1)) != 0 || bufferSize < modulus) { return(0); } byte paddingValue = protectedMemory[bufferSize - 1]; /* test for valid padding value */ if (paddingValue < 1 || paddingValue > modulus) { return(0); } /* buffer must be at least padding_value + 1 in size */ if (bufferSize < paddingValue + 1) { return(0); } bufferSize--; using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedMemory)) { byte *buffer = (byte *)access.Handle; for (int count = 1; count < paddingValue; count++) { bufferSize--; if (buffer[bufferSize] != paddingValue) { return(0); } } } return(bufferSize); }
private IntPtr Digest(ProtectedMemory protectedMemory) { // convert string msg into 512-bit blocks (array of 16 32-bit integers) [§5.2.1] int contentLength = protectedMemory.ContentLength; double length = (contentLength / 4) + 3; // length (in 32-bit integers) of content length + ‘1’ + appended length int blockCount = (int)Math.Ceiling(length / 16d); // number of 16-integer (512-bit) blocks required to hold 'l' ints int allocatedSize = blockCount * 16 * sizeof(int); IntPtr messageBuffer = Marshal.AllocHGlobal(allocatedSize); MarshalExtensions.ZeroMemory(messageBuffer, allocatedSize); using (ProtectedMemoryAccess access = new ProtectedMemoryAccess(protectedMemory)) { MarshalExtensions.Copy(access.Handle, 0, messageBuffer, 0, contentLength); } // append padding Marshal.WriteByte(messageBuffer + contentLength, 0x80); IntPtr buffer = Marshal.AllocHGlobal(allocatedSize); MarshalExtensions.ZeroMemory(buffer, allocatedSize); for (int i = 0; i < blockCount; i++) { IntPtr rowPointer = messageBuffer + (i * 64); // encode 4 chars per integer (64 per block), big-endian encoding for (int j = 0; j < 16; j++) { int value = MarshalExtensions.ReadInt32BigEndian(rowPointer + (j * sizeof(int))); Marshal.WriteInt32(buffer + (sizeof(int) * ((i * 16) + j)), value); } } // zero-free message buffer MarshalExtensions.ZeroMemory(messageBuffer, allocatedSize); Marshal.FreeHGlobal(messageBuffer); // add length (in bits) into final pair of 32-bit integers (big-endian) long len = contentLength * 8; int lenHi = (int)(len >> 32); int lenLo = (int)len; Marshal.WriteInt32(buffer + allocatedSize - sizeof(long), lenHi); Marshal.WriteInt32(buffer + allocatedSize - sizeof(int), lenLo); // allocate message schedule IntPtr messageScheduleBuffer = Marshal.AllocHGlobal(msgSchedBufSize); // allocate memory for hash and copy constants. IntPtr pHash = Marshal.AllocHGlobal(digestLength); byte[] managedHash = new byte[H.Length * sizeof(uint)]; Buffer.BlockCopy(H, 0, managedHash, 0, managedHash.Length); Marshal.Copy(managedHash, 0, pHash, managedHash.Length); // HASH COMPUTATION for (int i = 0; i < blockCount; i++) { // prepare message schedule for (int j = 0; j < 16; j++) { int value = Marshal.ReadInt32(buffer + (sizeof(int) * ((i * 16) + j))); Marshal.WriteInt32(messageScheduleBuffer + (j * sizeof(int)), value); } for (int j = 16; j < 64; j++) { uint value = sigma1((uint)Marshal.ReadInt32(messageScheduleBuffer + ((j - 2) * sizeof(int)))) + (uint)Marshal.ReadInt32(messageScheduleBuffer + ((j - 7) * sizeof(int))) + sigma0((uint)Marshal.ReadInt32(messageScheduleBuffer + ((j - 15) * sizeof(int)))) + (uint)Marshal.ReadInt32(messageScheduleBuffer + ((j - 16) * sizeof(int))); Marshal.WriteInt32(messageScheduleBuffer + (j * sizeof(int)), (int)value); } // initialize working variables a, b, c, d, e, f, g, h with previous hash value uint a = (uint)Marshal.ReadInt32(pHash + (0 * sizeof(int))); uint b = (uint)Marshal.ReadInt32(pHash + (1 * sizeof(int))); uint c = (uint)Marshal.ReadInt32(pHash + (2 * sizeof(int))); uint d = (uint)Marshal.ReadInt32(pHash + (3 * sizeof(int))); uint e = (uint)Marshal.ReadInt32(pHash + (4 * sizeof(int))); uint f = (uint)Marshal.ReadInt32(pHash + (5 * sizeof(int))); uint g = (uint)Marshal.ReadInt32(pHash + (6 * sizeof(int))); uint h = (uint)Marshal.ReadInt32(pHash + (7 * sizeof(int))); // main loop for (int j = 0; j < 64; j++) { uint t1 = h + sum1(e) + Ch(e, f, g) + K[j] + (uint)Marshal.ReadInt32(messageScheduleBuffer + (j * sizeof(int))); uint t2 = sum0(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; } // compute the new intermediate hash value Marshal.WriteInt32(pHash + (0 * sizeof(int)), (int)((uint)Marshal.ReadInt32(pHash + (0 * sizeof(int))) + a)); Marshal.WriteInt32(pHash + (1 * sizeof(int)), (int)((uint)Marshal.ReadInt32(pHash + (1 * sizeof(int))) + b)); Marshal.WriteInt32(pHash + (2 * sizeof(int)), (int)((uint)Marshal.ReadInt32(pHash + (2 * sizeof(int))) + c)); Marshal.WriteInt32(pHash + (3 * sizeof(int)), (int)((uint)Marshal.ReadInt32(pHash + (3 * sizeof(int))) + d)); Marshal.WriteInt32(pHash + (4 * sizeof(int)), (int)((uint)Marshal.ReadInt32(pHash + (4 * sizeof(int))) + e)); Marshal.WriteInt32(pHash + (5 * sizeof(int)), (int)((uint)Marshal.ReadInt32(pHash + (5 * sizeof(int))) + f)); Marshal.WriteInt32(pHash + (6 * sizeof(int)), (int)((uint)Marshal.ReadInt32(pHash + (6 * sizeof(int))) + g)); Marshal.WriteInt32(pHash + (7 * sizeof(int)), (int)((uint)Marshal.ReadInt32(pHash + (7 * sizeof(int))) + h)); } MarshalExtensions.Int32LittleEndianArrayToBigEndian(pHash, digestLength); // zero-free used buffers MarshalExtensions.ZeroMemory(messageScheduleBuffer, msgSchedBufSize); Marshal.FreeHGlobal(messageScheduleBuffer); MarshalExtensions.ZeroMemory(buffer, allocatedSize); Marshal.FreeHGlobal(buffer); // return pointer to computed hash (needs to be freed by caller). return(pHash); }