Ejemplo n.º 1
0
        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));
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        // 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);
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
 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));
 }
Ejemplo n.º 6
0
        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));
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 11
0
 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);
 }
Ejemplo n.º 12
0
        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);
        }
Ejemplo n.º 14
0
        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);
            }
        }
Ejemplo n.º 15
0
        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;
            }
        }
Ejemplo n.º 16
0
        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);
        }