Beispiel #1
0
        public static void ChasmSerializer_WriteRead_TreeNodeMap(IChasmSerializer ser)
        {
            var node0    = new TreeNode("a", NodeKind.Blob, s_hasher.HashData("abc"));
            var node1    = new TreeNode("b", NodeKind.Tree, s_hasher.HashData("def"));
            var node2    = new TreeNode("c", NodeKind.Tree, s_hasher.HashData("hij"));
            var expected = new TreeNodeMap(node0, node1, node2);

            using (IMemoryOwner <byte> owner = ser.Serialize(expected))
            {
                TreeNodeMap actual = ser.DeserializeTree(owner.Memory.Span);

                Assert.Equal(expected, actual);
            }
        }
Beispiel #2
0
        public static void When_check_empty()
        {
            var expected = Sha1.Parse(Sha1TestVectors.Empty);

            // Empty Array singleton
            Sha1 actual = s_sha1.HashData(Array.Empty <byte>());

            Assert.Equal(expected, actual);
            Assert.Equal(expected.GetHashCode(), actual.GetHashCode());

            // Empty Array
            actual = s_sha1.HashData(new byte[0]);
            Assert.Equal(expected, actual);
            Assert.Equal(expected.GetHashCode(), actual.GetHashCode());

            // Empty default ArraySegment
            actual = s_sha1.HashData(default(ArraySegment <byte>));
            Assert.Equal(expected, actual);
            Assert.Equal(expected.GetHashCode(), actual.GetHashCode());

            // Empty new ArraySegment
            actual = s_sha1.HashData(new ArraySegment <byte>(new byte[0], 0, 0));
            Assert.Equal(expected, actual);
            Assert.Equal(expected.GetHashCode(), actual.GetHashCode());

            // Empty default Span
            actual = s_sha1.HashData(default(Span <byte>));
            Assert.Equal(expected, actual);
            Assert.Equal(expected.GetHashCode(), actual.GetHashCode());

            // Empty new Span
            actual = s_sha1.HashData(new Span <byte>(new byte[0], 0, 0));
            Assert.Equal(expected, actual);
            Assert.Equal(expected.GetHashCode(), actual.GetHashCode());

            // Empty default ReadOnlySpan
            actual = s_sha1.HashData(default(ReadOnlySpan <byte>));
            Assert.Equal(expected, actual);
            Assert.Equal(expected.GetHashCode(), actual.GetHashCode());

            // Empty new ReadOnlySpan
            actual = s_sha1.HashData(new ReadOnlySpan <byte>(new byte[0], 0, 0));
            Assert.Equal(expected, actual);
            Assert.Equal(expected.GetHashCode(), actual.GetHashCode());

            // Empty String
            actual = s_sha1.HashData(string.Empty);
            Assert.Equal(expected, actual);
            Assert.Equal(expected.GetHashCode(), actual.GetHashCode());
        }
Beispiel #3
0
        public static void TreeId_equality()
        {
            var treeId1 = new TreeId(s_hasher.HashData("abc"));
            var treeId2 = new TreeId(s_hasher.HashData("abc"));
            var treeId3 = new TreeId(s_hasher.HashData("def"));

            Assert.True(treeId1 == treeId2);
            Assert.False(treeId1 != treeId2);
            Assert.True(treeId1.Equals((object)treeId2));

            Assert.Equal(treeId1.Sha1.ToString(), treeId1.ToString());
            Assert.Equal(treeId2.Sha1.ToString(), treeId2.ToString());
            Assert.Equal(treeId3.Sha1.ToString(), treeId3.ToString());

            Assert.Equal(treeId1, treeId2);
            Assert.Equal(treeId1.GetHashCode(), treeId2.GetHashCode());
            Assert.Equal(treeId1.ToString(), treeId2.ToString());

            Assert.NotEqual(treeId3, treeId1);
            Assert.NotEqual(treeId3.GetHashCode(), treeId1.GetHashCode());
            Assert.NotEqual(treeId3.ToString(), treeId1.ToString());
        }
Beispiel #4
0
        public static void BlobId_equality()
        {
            var blobId1 = new BlobId(s_hasher.HashData("abc"));
            var blobId2 = new BlobId(s_hasher.HashData("abc"));
            var blobId3 = new BlobId(s_hasher.HashData("def"));

            Assert.True(blobId1 == blobId2);
            Assert.False(blobId1 != blobId2);
            Assert.True(blobId1.Equals((object)blobId2));
            Assert.False(blobId1.Equals(new object()));

            Assert.Equal(blobId1.Sha1.ToString(), blobId1.ToString());
            Assert.Equal(blobId2.Sha1.ToString(), blobId2.ToString());
            Assert.Equal(blobId3.Sha1.ToString(), blobId3.ToString());

            Assert.Equal(blobId1, blobId2);
            Assert.Equal(blobId1.GetHashCode(), blobId2.GetHashCode());
            Assert.Equal(blobId1.ToString(), blobId2.ToString());

            Assert.NotEqual(blobId3, blobId1);
            Assert.NotEqual(blobId3.GetHashCode(), blobId1.GetHashCode());
            Assert.NotEqual(blobId3.ToString(), blobId1.ToString());
        }
Beispiel #5
0
 /// <summary>
 /// Computes the hash value of the specified input stream and signs the resulting hash value.
 /// </summary>
 /// <param name="buffer">The input data for which to compute the hash.</param>
 /// <returns>The DSA signature for the specified data.</returns>
 public byte[] SignData(byte[] buffer)
 {
     byte[] hashVal = SHA1.HashData(buffer);
     return(SignHash(hashVal, null));
 }
Beispiel #6
0
 /// <summary>
 /// Computes the hash value of the specified input stream and signs the resulting hash value.
 /// </summary>
 /// <param name="inputStream">The input data for which to compute the hash.</param>
 /// <returns>The DSA signature for the specified data.</returns>
 public byte[] SignData(Stream inputStream)
 {
     byte[] hashVal = SHA1.HashData(inputStream);
     return(SignHash(hashVal, null));
 }
Beispiel #7
0
 /// <summary>
 /// Verifies the specified signature data by comparing it to the signature computed for the specified data.
 /// </summary>
 /// <param name="rgbData">The data that was signed.</param>
 /// <param name="rgbSignature">The signature data to be verified.</param>
 /// <returns>true if the signature verifies as valid; otherwise, false.</returns>
 public bool VerifyData(byte[] rgbData, byte[] rgbSignature)
 {
     byte[] hashVal = SHA1.HashData(rgbData);
     return(VerifyHash(hashVal, null, rgbSignature));
 }
Beispiel #8
0
 /// <summary>
 /// Signs a byte array from the specified start point to the specified end point.
 /// </summary>
 /// <param name="buffer">The input data to sign.</param>
 /// <param name="offset">The offset into the array from which to begin using data.</param>
 /// <param name="count">The number of bytes in the array to use as data.</param>
 /// <returns>The DSA signature for the specified data.</returns>
 public byte[] SignData(byte[] buffer, int offset, int count)
 {
     byte[] hashVal = SHA1.HashData(new ReadOnlySpan <byte>(buffer, offset, count));
     return(SignHash(hashVal, null));
 }
        private static unsafe void FillKeyDerivation(
            ReadOnlySpan <byte> password,
            ReadOnlySpan <byte> salt,
            int iterations,
            string hashAlgorithmName,
            Span <byte> destination)
        {
            SafeBCryptKeyHandle keyHandle;
            int hashBlockSizeBytes = GetHashBlockSize(hashAlgorithmName);

            // stackalloc 0 to let compiler know this cannot escape.
            Span <byte>         clearSpan            = stackalloc byte[0];
            ReadOnlySpan <byte> symmetricKeyMaterial = stackalloc byte[0];
            int symmetricKeyMaterialLength;

            if (password.IsEmpty)
            {
                // CNG won't accept a null pointer for the password.
                symmetricKeyMaterial       = stackalloc byte[1];
                symmetricKeyMaterialLength = 0;
                clearSpan = default;
            }
            else if (password.Length <= hashBlockSizeBytes)
            {
                // Password is small enough to use as-is.
                symmetricKeyMaterial       = password;
                symmetricKeyMaterialLength = password.Length;
                clearSpan = default;
            }
            else
            {
                // RFC 2104: "The key for HMAC can be of any length (keys longer than B bytes are
                //     first hashed using H).
                //     We denote by B the byte-length of such
                //     blocks (B=64 for all the above mentioned examples of hash functions)
                //
                // Windows' PBKDF2 will do this up to a point. To ensure we accept arbitrary inputs for
                // PBKDF2, we do the hashing ourselves.
                Span <byte> hashBuffer = stackalloc byte[512 / 8]; // 64 bytes is SHA512, the largest digest handled.
                int         hashBufferSize;

                switch (hashAlgorithmName)
                {
                case HashAlgorithmNames.SHA1:
                    hashBufferSize = SHA1.HashData(password, hashBuffer);
                    break;

                case HashAlgorithmNames.SHA256:
                    hashBufferSize = SHA256.HashData(password, hashBuffer);
                    break;

                case HashAlgorithmNames.SHA384:
                    hashBufferSize = SHA384.HashData(password, hashBuffer);
                    break;

                case HashAlgorithmNames.SHA512:
                    hashBufferSize = SHA512.HashData(password, hashBuffer);
                    break;

                default:
                    Debug.Fail($"Unexpected hash algorithm '{hashAlgorithmName}'");
                    throw new CryptographicException();
                }

                clearSpan                  = hashBuffer.Slice(0, hashBufferSize);
                symmetricKeyMaterial       = clearSpan;
                symmetricKeyMaterialLength = hashBufferSize;
            }

            Debug.Assert(symmetricKeyMaterial.Length > 0);

            NTSTATUS generateKeyStatus;

            if (Interop.BCrypt.PseudoHandlesSupported)
            {
                fixed(byte *pSymmetricKeyMaterial = symmetricKeyMaterial)
                {
                    generateKeyStatus = Interop.BCrypt.BCryptGenerateSymmetricKey(
                        (nuint)BCryptAlgPseudoHandle.BCRYPT_PBKDF2_ALG_HANDLE,
                        out keyHandle,
                        pbKeyObject: IntPtr.Zero,
                        cbKeyObject: 0,
                        pSymmetricKeyMaterial,
                        symmetricKeyMaterialLength,
                        dwFlags: 0);
                }
            }
            else
            {
                if (s_pbkdf2AlgorithmHandle is null)
                {
                    NTSTATUS openStatus = Interop.BCrypt.BCryptOpenAlgorithmProvider(
                        out SafeBCryptAlgorithmHandle pbkdf2AlgorithmHandle,
                        Internal.NativeCrypto.BCryptNative.AlgorithmName.Pbkdf2,
                        null,
                        BCryptOpenAlgorithmProviderFlags.None);

                    if (openStatus != NTSTATUS.STATUS_SUCCESS)
                    {
                        pbkdf2AlgorithmHandle.Dispose();
                        CryptographicOperations.ZeroMemory(clearSpan);
                        throw Interop.BCrypt.CreateCryptographicException(openStatus);
                    }

                    // This might race, and that's okay. Worst case the algorithm is opened
                    // more than once, and the ones that lost will get cleaned up during collection.
                    Interlocked.CompareExchange(ref s_pbkdf2AlgorithmHandle, pbkdf2AlgorithmHandle, null);
                }

                fixed(byte *pSymmetricKeyMaterial = symmetricKeyMaterial)
                {
                    generateKeyStatus = Interop.BCrypt.BCryptGenerateSymmetricKey(
                        s_pbkdf2AlgorithmHandle,
                        out keyHandle,
                        pbKeyObject: IntPtr.Zero,
                        cbKeyObject: 0,
                        pSymmetricKeyMaterial,
                        symmetricKeyMaterialLength,
                        dwFlags: 0);
                }
            }

            CryptographicOperations.ZeroMemory(clearSpan);

            if (generateKeyStatus != NTSTATUS.STATUS_SUCCESS)
            {
                keyHandle.Dispose();
                throw Interop.BCrypt.CreateCryptographicException(generateKeyStatus);
            }

            Debug.Assert(!keyHandle.IsInvalid);

            ulong kdfIterations = (ulong)iterations; // Previously asserted to be positive.

            using (keyHandle)
                fixed(char *pHashAlgorithmName = hashAlgorithmName)
                fixed(byte *pSalt        = salt)
                fixed(byte *pDestination = destination)
                {
                    Span <BCryptBuffer> buffers = stackalloc BCryptBuffer[3];

                    buffers[0].BufferType = CngBufferDescriptors.KDF_ITERATION_COUNT;
                    buffers[0].pvBuffer   = (IntPtr)(&kdfIterations);
                    buffers[0].cbBuffer   = sizeof(ulong);

                    buffers[1].BufferType = CngBufferDescriptors.KDF_SALT;
                    buffers[1].pvBuffer   = (IntPtr)pSalt;
                    buffers[1].cbBuffer   = salt.Length;

                    buffers[2].BufferType = CngBufferDescriptors.KDF_HASH_ALGORITHM;
                    buffers[2].pvBuffer   = (IntPtr)pHashAlgorithmName;

                    // C# spec: "A char* value produced by fixing a string instance always points to a null-terminated string"
                    buffers[2].cbBuffer = checked ((hashAlgorithmName.Length + 1) * sizeof(char)); // Add null terminator.

                    fixed(BCryptBuffer *pBuffers = buffers)
                    {
                        Interop.BCrypt.BCryptBufferDesc bufferDesc;
                        bufferDesc.ulVersion = Interop.BCrypt.BCRYPTBUFFER_VERSION;
                        bufferDesc.cBuffers  = buffers.Length;
                        bufferDesc.pBuffers  = (IntPtr)pBuffers;

                        NTSTATUS deriveStatus = Interop.BCrypt.BCryptKeyDerivation(
                            keyHandle,
                            &bufferDesc,
                            pDestination,
                            destination.Length,
                            out uint resultLength,
                            dwFlags: 0);

                        if (deriveStatus != NTSTATUS.STATUS_SUCCESS)
                        {
                            throw Interop.BCrypt.CreateCryptographicException(deriveStatus);
                        }

                        if (destination.Length != resultLength)
                        {
                            Debug.Fail("PBKDF2 resultLength != destination.Length");
                            throw new CryptographicException();
                        }
                    }
                }
        }