Skip to content

Commit

Permalink
Unit test file decryption
Browse files Browse the repository at this point in the history
  • Loading branch information
poulad committed Sep 2, 2018
1 parent 77f9cff commit 23f2797
Show file tree
Hide file tree
Showing 3 changed files with 404 additions and 25 deletions.
56 changes: 32 additions & 24 deletions src/Telegram.Bot.Extensions.Passport/Decryption/Decrypter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,53 +89,60 @@ DataCredentials dataCredentials
}

/// <inheritdoc />
public Task DecryptFileAsync(
Stream encryptedContent,
FileCredentials fileCredentials,
Stream destination,
CancellationToken cancellationToken = default
public byte[] DecryptFile(
byte[] encryptedContent,
FileCredentials fileCredentials
)
{
if (encryptedContent is null)
throw new ArgumentNullException(nameof(encryptedContent));
if (fileCredentials is null)
throw new ArgumentNullException(nameof(fileCredentials));
if (!encryptedContent.CanRead)
throw new ArgumentException("Stream does not support reading.", nameof(encryptedContent));
if (encryptedContent.CanSeek && encryptedContent.Length % 16 != 0)
if (encryptedContent.Length % 16 != 0)
throw new PassportDataDecryptionException($"Invalid data length: {encryptedContent.Length}");
if (!destination.CanWrite)
throw new ArgumentException("Stream does not support writing.", nameof(destination));

byte[] dataSecret = Convert.FromBase64String(fileCredentials.Secret);
byte[] dataHash = Convert.FromBase64String(fileCredentials.FileHash);

if (dataHash.Length != 32)
throw new PassportDataDecryptionException($"Invalid hash length: {dataHash.Length}");

return DecryptDataStreamAsync(encryptedContent, dataSecret, dataHash, destination, cancellationToken);
return DecryptDataBytes(encryptedContent, dataSecret, dataHash);
}

/// <inheritdoc />
public byte[] DecryptFile(
byte[] encryptedContent,
FileCredentials fileCredentials
public Task DecryptFileAsync(
Stream encryptedContent,
FileCredentials fileCredentials,
Stream destination,
CancellationToken cancellationToken = default
)
{
if (encryptedContent is null)
throw new ArgumentNullException(nameof(encryptedContent));
if (fileCredentials is null)
throw new ArgumentNullException(nameof(fileCredentials));
if (encryptedContent.Length % 16 != 0)
throw new PassportDataDecryptionException($"Invalid data length: {encryptedContent.Length}");
if (fileCredentials.Secret is null)
throw new ArgumentNullException(nameof(fileCredentials.Secret));
if (fileCredentials.FileHash is null)
throw new ArgumentNullException(nameof(fileCredentials.FileHash));
if (destination is null)
throw new ArgumentNullException(nameof(destination));
if (!encryptedContent.CanRead)
throw new ArgumentException("Stream does not support reading.", nameof(encryptedContent));
if (encryptedContent.CanSeek && encryptedContent.Length % 16 != 0)
throw new PassportDataDecryptionException
($"Length of padded data is not divisible by 16: {encryptedContent.Length}.");
if (!destination.CanWrite)
throw new ArgumentException("Stream does not support writing.", nameof(destination));

byte[] dataSecret = Convert.FromBase64String(fileCredentials.Secret);
byte[] dataHash = Convert.FromBase64String(fileCredentials.FileHash);

if (dataHash.Length != 32)
throw new PassportDataDecryptionException($"Invalid hash length: {dataHash.Length}");
throw new PassportDataDecryptionException($"file hash has invalid length: {dataHash.Length}.");

return DecryptDataBytes(encryptedContent, dataSecret, dataHash);
return DecryptDataStreamAsync(encryptedContent, dataSecret, dataHash, destination, cancellationToken);
}

private static async Task DecryptDataStreamAsync(
Expand All @@ -157,8 +164,8 @@ CancellationToken cancellationToken
aes.IV = dataIv;
aes.Padding = PaddingMode.None;

using (var decryptor = aes.CreateDecryptor())
using (CryptoStream aesStream = new CryptoStream(data, decryptor, CryptoStreamMode.Read))
using (var decrypter = aes.CreateDecryptor())
using (CryptoStream aesStream = new CryptoStream(data, decrypter, CryptoStreamMode.Read))
using (var sha256 = SHA256.Create())
using (CryptoStream shaStream = new CryptoStream(aesStream, sha256, CryptoStreamMode.Read))
{
Expand All @@ -168,11 +175,12 @@ CancellationToken cancellationToken

byte paddingLength = paddingBuffer[0];
if (paddingLength < 32)
throw new PassportDataDecryptionException("Invalid data padding length");
throw new PassportDataDecryptionException($"Data has invalid padding length: {paddingLength}.");

int actualDataLength = read - paddingLength;
if (actualDataLength < 1)
throw new PassportDataDecryptionException("Invalid data");
// ToDo test
throw new PassportDataDecryptionException($"Data has invalid length: {actualDataLength}.");

await destination.WriteAsync(paddingBuffer, paddingLength, actualDataLength, cancellationToken)
.ConfigureAwait(false);
Expand All @@ -187,7 +195,7 @@ await shaStream.CopyToAsync(destination, defaultBufferSize, cancellationToken)
for (int i = 0; i < hash.Length; i++)
{
if (hash[i] != paddedDataHash[i])
throw new PassportDataDecryptionException("Data hash mismatch");
throw new PassportDataDecryptionException($"Data hash mismatch at position {i}.");
}
}
}
Expand Down Expand Up @@ -235,7 +243,7 @@ private static byte[] DecryptDataBytes(byte[] data, byte[] secret, byte[] hash)
for (int i = 0; i < hash.Length; i++)
{
if (hash[i] != paddedDataHash[i])
throw new PassportDataDecryptionException("Data hash mismatch");
throw new PassportDataDecryptionException("Data hash mismatch.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ await BotClient.SendTextMessageAsync(

RSA key = EncryptionKey.ReadAsRsa();
IDecrypter decrypter = new Decrypter();
Credentials credentials = decrypter.DecryptCredentials(key, passportUpdate.Message.PassportData.Credentials);
Credentials credentials =
decrypter.DecryptCredentials(key, passportUpdate.Message.PassportData.Credentials);

Assert.Equal("Test nonce for identity card", credentials.Nonce);

Expand Down
Loading

0 comments on commit 23f2797

Please sign in to comment.