devolutions-crypto 0.9.2

An abstraction layer for the cryptography used by Devolutions
Documentation
#pragma warning disable SA1600 // Elements should be documented

namespace Devolutions.Crypto.Tests
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    using System;
    using System.IO;

    using Devolutions.Cryptography;

    [TestClass]
    public class TestUtils
    {
        [TestMethod]
        public void Base64StringToByteArray()
        {
            byte[] data = Utils.Base64StringToByteArray(TestData.Base64TestData);
            Assert.AreEqual(Convert.ToBase64String(data), Convert.ToBase64String(TestData.BytesTestData));
        }

        [TestMethod]
        public void ByteArrayToString()
        {
            byte[] data = new byte[] { 0x51, 0x55, 0x4a, 0x44 };
            string dataToUtf8String = Utils.ByteArrayToUtf8String(data);
            Assert.AreEqual(dataToUtf8String, TestData.Base64TestData);
        }

        [TestMethod]
        public void ConstantTimeEqual()
        {
            byte[] x = { 0, 1, 2 };
            byte[] y = { 4, 5, 6 };
            byte[] z = { 0, 1, 2, 3 };

            Assert.IsTrue(Utils.ConstantTimeEquals(x, x));
            Assert.IsTrue(!Utils.ConstantTimeEquals(x, y));
            Assert.IsTrue(!Utils.ConstantTimeEquals(x, z));
            Assert.IsTrue(!Utils.ConstantTimeEquals(y, x));
            Assert.IsTrue(Utils.ConstantTimeEquals(y, y));
            Assert.IsTrue(!Utils.ConstantTimeEquals(y, z));
            Assert.IsTrue(!Utils.ConstantTimeEquals(z, x));
            Assert.IsTrue(!Utils.ConstantTimeEquals(z, y));
            Assert.IsTrue(Utils.ConstantTimeEquals(z, z));
        }

        [TestMethod]
        public void Decode()
        {
            byte[] decodedData = Utils.DecodeFromBase64(TestData.Base64TestData);
            Assert.AreEqual(Convert.ToBase64String(decodedData), Convert.ToBase64String(TestData.BytesTestData));
        }

        [TestMethod]
        public void DecodeUrl()
        {
            byte[] d1 = Utils.DecodeFromBase64Url(TestData.Base64Url1);
            byte[] d2 = Utils.DecodeFromBase64Url(TestData.Base64Url2);
            byte[] d3 = Utils.DecodeFromBase64Url(TestData.Base64Url3);
            Assert.AreEqual(Convert.ToBase64String(d1), Convert.ToBase64String(TestData.Base64UrlBytes1));
            Assert.AreEqual(Convert.ToBase64String(d2), Convert.ToBase64String(TestData.Base64UrlBytes2));
            Assert.AreEqual(Convert.ToBase64String(d3), Convert.ToBase64String(TestData.Base64UrlBytes3));
        }

        [TestMethod]
        public void Encode()
        {
            string y = Utils.EncodeToBase64String(TestData.BytesTestData);
            Assert.AreEqual(y, TestData.Base64TestData);
        }

        [TestMethod]
        public void EncodeUrl()
        {
            string e1 = Utils.EncodeToBase64UrlString(TestData.Base64UrlBytes1);
            string e2 = Utils.EncodeToBase64UrlString(TestData.Base64UrlBytes2);
            string e3 = Utils.EncodeToBase64UrlString(TestData.Base64UrlBytes3);
            Assert.AreEqual(e1, TestData.Base64Url1);
            Assert.AreEqual(e2, TestData.Base64Url2);
            Assert.AreEqual(e3, TestData.Base64Url3);
        }

        [TestMethod]
        public void GetDecodedLength()
        {
            Assert.IsTrue(this.GetDotNetBase64Length(TestData.StringTestData) <= Utils.GetDecodedBase64StringLength(TestData.StringTestData)); // Invalid data
            Assert.IsTrue(Utils.GetDecodedBase64StringLength("====") >= this.GetDotNetBase64Length("===="));
            Assert.IsTrue(Utils.GetDecodedBase64StringLength("=") == this.GetDotNetBase64Length("="));
            Assert.IsTrue(Utils.GetDecodedBase64StringLength("YWxsbw==") == this.GetDotNetBase64Length("YWxsbw=="));
            Assert.IsTrue(Utils.GetDecodedBase64StringLength(null) == this.GetDotNetBase64Length(null));
        }

        public int GetDotNetBase64Length(string base64)
        {
            try
            {
                byte[] test = Convert.FromBase64String(base64);

                return test.Length;
            }
            catch (Exception)
            {
                return 0;
            }
        }

        [TestMethod]
        public void GetEncodedLength()
        {
            int encodedLength = Utils.GetEncodedBase64StringLength(TestData.BytesTestData);
            Assert.AreEqual(4, encodedLength);
        }

        [TestMethod]
        public void ScryptSimple()
        {
            byte[] password = Utils.StringToUtf8ByteArray(TestData.TestPassword);
            byte[] salt = TestData.Salt;

            string hash = Utils.ScryptSimple(password, salt, 10, 8, 1);

            Assert.AreEqual(TestData.ScryptHash, hash);
        }

        [TestMethod]
        public void StringToByteArray()
        {
            byte[] data = new byte[] { 0x51, 0x55, 0x4a, 0x44 };
            Assert.AreEqual(Convert.ToBase64String(Utils.StringToUtf8ByteArray(TestData.Base64TestData)), Convert.ToBase64String(data));
        }

        [TestMethod]
        public void ToBase64String()
        {
            Assert.AreEqual(Utils.EncodeToBase64String(TestData.BytesTestData), TestData.Base64TestData);
        }

        [TestMethod]
        public void ValidateSignature()
        {
            byte[] dataToEncrypt = Utils.StringToUtf8ByteArray(TestData.Base64TestData);
            byte[] password = Utils.StringToUtf8ByteArray(TestData.TestPassword);

            byte[] encryptResult = Managed.Encrypt(dataToEncrypt, password);

            Assert.IsFalse(Utils.ValidateHeader(dataToEncrypt, DataType.Cipher));
            Assert.IsTrue(Utils.ValidateHeader(encryptResult, DataType.Cipher));
        }

        [TestMethod]
        public void ValidateSignatureFromStream_BufferTooSmall()
        {
            Stream stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });

            bool validationResult = Utils.ValidateHeaderFromStream(stream, DataType.Cipher);

            Assert.AreEqual(validationResult, false);
        }

        [TestMethod]
        public void ValidateSignatureFromStream_ClosedStream()
        {
            Stream stream = new ClosedStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

            stream.Close();

            DevolutionsCryptoException exception = null;

            try
            {
                bool validationResult = Utils.ValidateHeaderFromStream(stream, DataType.Cipher);
            }
            catch (DevolutionsCryptoException ex)
            {
                exception = ex;
            }

            // Xamarin has a space between Cannot (Can not)
            bool validException = exception.ManagedException.Message.Contains("Cannot access a closed Stream.")
                || exception.ManagedException.Message.Contains("Can not access a closed Stream.");

            Assert.AreEqual(validException, true);
        }

        [TestMethod]
        public void ValidateSignatureFromStream_OriginalPosition()
        {
            Stream stream = new MemoryStream(TestData.EncryptedData);

            stream.Position = 12;

            bool validationResult = Utils.ValidateHeaderFromStream(stream, DataType.Cipher);

            Assert.AreEqual(stream.Position, 12);
            Assert.AreEqual(validationResult, false);
        }

        [TestMethod]
        public void ValidateSignatureFromStream_UnReadableStream()
        {
            Stream stream = new UnReadableStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

            DevolutionsCryptoException exception = null;

            try
            {
                bool validationResult = Utils.ValidateHeaderFromStream(stream, DataType.Cipher);
            }
            catch (DevolutionsCryptoException ex)
            {
                exception = ex;
            }

            Assert.AreEqual(exception.ManagedError, ManagedError.CanNotReadStream);
        }

        [TestMethod]
        public void ValidateSignatureFromStream_UnseekableStream()
        {
            Stream stream = new UnSeekableStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

            DevolutionsCryptoException exception = null;

            try
            {
                bool validationResult = Utils.ValidateHeaderFromStream(stream, DataType.Cipher);
            }
            catch (DevolutionsCryptoException ex)
            {
                exception = ex;
            }

            Assert.AreEqual(exception.ManagedError, ManagedError.CanNotSeekStream);
        }

        [TestMethod]
        public void ValidateSignatureFromStream_ValidSignature()
        {
            Stream stream = new MemoryStream(TestData.EncryptedData);

            bool validationResult = Utils.ValidateHeaderFromStream(stream, DataType.Cipher);

            Assert.AreEqual(validationResult, true);
        }
    }
}

#pragma warning restore SA1600 // Elements should be documented