#pragma warning disable SA1600
namespace Devolutions.Crypto.Tests
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using Devolutions.Cryptography;
using System.Text;
[TestClass]
public class TestUtils
{
[TestMethod]
public void Base64StringToByteArray()
{
byte[]? data = Utils.Base64StringToByteArray(TestData.Base64TestData);
Assert.IsNotNull(data);
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.IsFalse(Utils.ConstantTimeEquals(x, y));
Assert.IsFalse(Utils.ConstantTimeEquals(x, z));
Assert.IsFalse(Utils.ConstantTimeEquals(y, x));
Assert.IsTrue(Utils.ConstantTimeEquals(y, y));
Assert.IsFalse(Utils.ConstantTimeEquals(y, z));
Assert.IsFalse(Utils.ConstantTimeEquals(z, x));
Assert.IsFalse(Utils.ConstantTimeEquals(z, y));
Assert.IsTrue(Utils.ConstantTimeEquals(z, z));
}
[TestMethod]
public void Decode()
{
byte[]? decodedData = Utils.DecodeFromBase64(TestData.Base64TestData);
Assert.IsNotNull(decodedData);
Assert.AreEqual(Convert.ToBase64String(decodedData), Convert.ToBase64String(TestData.BytesTestData));
byte[]? decodeDataNoPad = Utils.DecodeFromBase64(TestData.Base64TestDataNoPad);
Assert.IsNotNull(decodeDataNoPad);
Assert.AreEqual(Encoding.UTF8.GetString(decodeDataNoPad), TestData.StringTestDataNoPad);
byte[]? decodeDataInvalid = Utils.DecodeFromBase64("====");
Assert.IsNull(decodeDataInvalid);
byte[]? decodeDataInvalid2 = Utils.DecodeFromBase64("=");
Assert.IsNull(decodeDataInvalid2);
}
[TestMethod]
public void DecodeUrl()
{
byte[]? d1 = Utils.DecodeFromBase64Url(TestData.Base64Url1);
byte[]? d2 = Utils.DecodeFromBase64Url(TestData.Base64Url2);
byte[]? d3 = Utils.DecodeFromBase64Url(TestData.Base64Url3);
Assert.IsNotNull(d1);
Assert.IsNotNull(d2);
Assert.IsNotNull(d3);
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)); Assert.IsTrue(Utils.GetDecodedBase64StringLength(TestData.Base64TestDataNoPad) >= this.GetDotNetBase64Length(TestData.Base64TestDataNoPad));
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)
{
if (base64 == null)
{
return 0;
}
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;
}
Assert.IsNotNull(exception);
Assert.IsNotNull(exception.ManagedException);
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.IsNotNull(exception);
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.IsNotNull(exception);
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