public async Task Should_Throw_Decrypting_Stream_With_Wrong_FileCredentials() { FileCredentials wrongFileCredentials = new FileCredentials { FileHash = "THTjgv2FU7kff/29Vty/IcqKPmOGkL7F35fAzmkfZdI=", Secret = "a+jxJoKPEaz77VCjRvDVcYHfIO3+h+oI+ruZh+KkYa0=", }; IDecrypter decrypter = new Decrypter(); Exception exception; using (Stream encFileStream = new NonSeekableFileReadStream("Files/s_dec5.driver_license-selfie.jpg.enc"), fileStream = new MemoryStream() ) { exception = await Assert.ThrowsAnyAsync <Exception>(() => decrypter.DecryptFileAsync( encFileStream, wrongFileCredentials, fileStream ) ); } Assert.Matches(@"^Data hash mismatch at position \d+\.$", exception.Message); Assert.IsType <PassportDataDecryptionException>(exception); }
public async Task Should_Decrypt_From_Seekable_Stream() { FileCredentials fileCredentials = new FileCredentials { FileHash = "v3q47iscI6TS94CMo7HGQUOxw28LIf82NJBkImzP57c=", Secret = "vF7nut7clg/H/pEaTJigo4mQJ0s8B+HGCWKTWtOTIdo=", }; IDecrypter decrypter = new Decrypter(); Stream encContentStream = new MemoryStream(); using (Stream encFileStream = new NonSeekableFileReadStream("Files/s_dec1.driver_license-selfie.jpg.enc")) { await encFileStream.CopyToAsync(encContentStream); } using (encContentStream) using (Stream contentStream = new MemoryStream()) { encContentStream.Position = 0; // Ensure method starts reading the content fro the beginning await decrypter.DecryptFileAsync( encContentStream, fileCredentials, contentStream ); } }
public async Task Should_decrypt_utility_bill_element_translation() { Update update = _classFixture.Entity; PassportData passportData = update.Message.PassportData; RSA key = EncryptionKey.ReadAsRsa(); EncryptedPassportElement billElement = Assert.Single(passportData.Data, el => el.Type == "utility_bill"); PassportFile translationFile = Assert.Single(billElement.Translation); IDecrypter decrypter = new Decrypter(); Credentials credentials = decrypter.DecryptCredentials(passportData.Credentials, key); FileCredentials fileCredentials = Assert.Single(credentials.SecureData.UtilityBill.Translation); File encryptedFileInfo; using (System.IO.Stream decryptedFile = new System.IO.MemoryStream()) { encryptedFileInfo = await BotClient.DownloadAndDecryptPassportFileAsync( translationFile, fileCredentials, decryptedFile ); Assert.InRange(decryptedFile.Length, translationFile.FileSize - 256, translationFile.FileSize + 256); } Assert.NotEmpty(encryptedFileInfo.FilePath); Assert.NotEmpty(encryptedFileInfo.FileId); Assert.InRange(encryptedFileInfo.FileSize, 1_000, 50_000_000); }
public async Task Should_Throw_Decrypting_Unencrypted_File() { FileCredentials fileCredentials = new FileCredentials { FileHash = "v3q47iscI6TS94CMo7HGQUOxw28LIf82NJBkImzP57c=", Secret = "vF7nut7clg/H/pEaTJigo4mQJ0s8B+HGCWKTWtOTIdo=", }; IDecrypter decrypter = new Decrypter(); Exception exception; using (Stream encFileStream = new NonSeekableFileReadStream("Files/s_dec3.driver_license-selfie.jpg"), fileStream = new MemoryStream() ) { exception = await Assert.ThrowsAnyAsync <Exception>(() => decrypter.DecryptFileAsync( encFileStream, fileCredentials, fileStream ) ); } Assert.Equal("The input data is not a complete block.", exception.Message); Assert.IsType <CryptographicException>(exception); }
public async Task Should_Throw_Decrypting_Mispositioned_Stream() { FileCredentials fileCredentials = new FileCredentials { FileHash = "v3q47iscI6TS94CMo7HGQUOxw28LIf82NJBkImzP57c=", Secret = "vF7nut7clg/H/pEaTJigo4mQJ0s8B+HGCWKTWtOTIdo=", }; IDecrypter decrypter = new Decrypter(); Stream encContentStream = new MemoryStream(); using (Stream encFileStream = new NonSeekableFileReadStream("Files/s_dec4.driver_license-selfie.jpg.enc")) { await encFileStream.CopyToAsync(encContentStream); } Exception exception; using (encContentStream) // Stream position is at the end and not at 0 position using (Stream contentStream = new MemoryStream()) { exception = await Assert.ThrowsAnyAsync <Exception>(() => decrypter.DecryptFileAsync( encContentStream, fileCredentials, contentStream ) ); } Assert.Matches(@"^Data padding length is invalid: \d+\.", exception.Message); Assert.IsType <PassportDataDecryptionException>(exception); }
public void Should_Decrypt_Credentials() { Update update = _classFixture.Entity; PassportData passportData = update.Message.PassportData; RSA key = EncryptionKey.ReadAsRsa(); IDecrypter decrypter = new Decrypter(); Credentials credentials = decrypter.DecryptCredentials( key: key, encryptedCredentials: passportData.Credentials ); Assert.NotNull(credentials); Assert.NotNull(credentials.SecureData); Assert.Equal("Test nonce for id card & utility bill", credentials.Nonce); // decryption of document data in 'identity_card' element requires accompanying DataCredentials Assert.NotNull(credentials.SecureData.IdentityCard); Assert.NotNull(credentials.SecureData.IdentityCard.Data); Assert.NotEmpty(credentials.SecureData.IdentityCard.Data.Secret); Assert.NotEmpty(credentials.SecureData.IdentityCard.Data.DataHash); // decryption of front side of 'identity_card' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.IdentityCard.FrontSide); Assert.NotEmpty(credentials.SecureData.IdentityCard.FrontSide.Secret); Assert.NotEmpty(credentials.SecureData.IdentityCard.FrontSide.FileHash); // decryption of reverse side of 'identity_card' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.IdentityCard.ReverseSide); Assert.NotEmpty(credentials.SecureData.IdentityCard.ReverseSide.Secret); Assert.NotEmpty(credentials.SecureData.IdentityCard.ReverseSide.FileHash); // decryption of selfie of 'identity_card' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.IdentityCard.Selfie); Assert.NotEmpty(credentials.SecureData.IdentityCard.Selfie.Secret); Assert.NotEmpty(credentials.SecureData.IdentityCard.Selfie.FileHash); Assert.Null(credentials.SecureData.IdentityCard.Translation); Assert.Null(credentials.SecureData.IdentityCard.Files); // decryption of file scan in 'utility_bill' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.UtilityBill.Files); FileCredentials billCredentials = Assert.Single(credentials.SecureData.UtilityBill.Files); Assert.NotEmpty(billCredentials.Secret); Assert.NotEmpty(billCredentials.FileHash); // decryption of translation file scan in 'utility_bill' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.UtilityBill.Files); FileCredentials billTranslationFileCredentials = Assert.Single(credentials.SecureData.UtilityBill.Translation); Assert.NotEmpty(billTranslationFileCredentials.Secret); Assert.NotEmpty(billTranslationFileCredentials.FileHash); }
public void Should_Decrypt_Credentials() { RSA key = EncryptionKey.RsaPrivateKey; PassportData passData = GetPassportData(); IDecrypter decrypter = new Decrypter(); Credentials credentials = decrypter.DecryptCredentials( encryptedCredentials: passData.Credentials, key: key ); Assert.NotNull(credentials); Assert.NotNull(credentials.SecureData); Assert.Equal("TEST", credentials.Nonce); // decryption of document data in 'identity_card' element requires accompanying DataCredentials Assert.NotNull(credentials.SecureData.IdentityCard); Assert.NotNull(credentials.SecureData.IdentityCard.Data); Assert.NotEmpty(credentials.SecureData.IdentityCard.Data.Secret); Assert.NotEmpty(credentials.SecureData.IdentityCard.Data.DataHash); // decryption of front side of 'identity_card' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.IdentityCard.FrontSide); Assert.NotEmpty(credentials.SecureData.IdentityCard.FrontSide.Secret); Assert.NotEmpty(credentials.SecureData.IdentityCard.FrontSide.FileHash); // decryption of reverse side of 'identity_card' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.IdentityCard.ReverseSide); Assert.NotEmpty(credentials.SecureData.IdentityCard.ReverseSide.Secret); Assert.NotEmpty(credentials.SecureData.IdentityCard.ReverseSide.FileHash); // decryption of selfie of 'identity_card' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.IdentityCard.Selfie); Assert.NotEmpty(credentials.SecureData.IdentityCard.Selfie.Secret); Assert.NotEmpty(credentials.SecureData.IdentityCard.Selfie.FileHash); Assert.Null(credentials.SecureData.IdentityCard.Translation); Assert.Null(credentials.SecureData.IdentityCard.Files); // decryption of file scan in 'utility_bill' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.UtilityBill.Files); FileCredentials billFileCredentials = Assert.Single(credentials.SecureData.UtilityBill.Files); Assert.NotEmpty(billFileCredentials.Secret); Assert.NotEmpty(billFileCredentials.FileHash); // decryption of translation file scan in 'utility_bill' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.UtilityBill.Files); FileCredentials billTranslationFileCredentials = Assert.Single(credentials.SecureData.UtilityBill.Translation); Assert.NotEmpty(billTranslationFileCredentials.Secret); Assert.NotEmpty(billTranslationFileCredentials.FileHash); }
public void Should_Throw_If_Invalid_Hash(string fileHash) { FileCredentials fileCredentials = new FileCredentials { Secret = "", FileHash = fileHash }; IDecrypter decrypter = new Decrypter(); Assert.ThrowsAny <FormatException>(() => decrypter.DecryptFile(new byte[16], fileCredentials) ); }
public async Task Should_Throw_If_Invalid_Hash(string fileHash) { FileCredentials fileCredentials = new FileCredentials { Secret = "", FileHash = fileHash }; IDecrypter decrypter = new Decrypter(); await Assert.ThrowsAnyAsync <FormatException>(() => decrypter.DecryptFileAsync(new MemoryStream(new byte[16]), fileCredentials, new MemoryStream()) ); }
/// <inheritdoc /> 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 (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 == 0) { throw new ArgumentException("Stream is empty.", nameof(encryptedContent)); } if (encryptedContent.CanSeek && encryptedContent.Length % 16 != 0) { throw new PassportDataDecryptionException("Data length 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($"Hash length is not 32: {dataHash.Length}."); } return(DecryptDataStreamAsync(encryptedContent, dataSecret, dataHash, destination, cancellationToken)); }
public void Should_Throw_If_Invalid_Secret(string secret) { FileCredentials fileCredentials = new FileCredentials { Secret = secret, FileHash = "" }; IDecrypter decrypter = new Decrypter(); Assert.Throws <FormatException>(() => decrypter.DecryptFile(new byte[16], fileCredentials) ); }
public void Should_Throw_If_Empty_Data_Bytes_Length() { IDecrypter decrypter = new Decrypter(); FileCredentials fileCredentials = new FileCredentials { Secret = "", FileHash = "" }; Exception exception = Assert.ThrowsAny <Exception>(() => decrypter.DecryptFile(new byte[0], fileCredentials) ); Assert.Matches(@"^Data array is empty\.\s+Parameter name: encryptedContent$", exception.Message); Assert.IsType <ArgumentException>(exception); }
public void Should_Throw_If_Null_Hash() { IDecrypter decrypter = new Decrypter(); FileCredentials fileCredentials = new FileCredentials { Secret = "" }; Exception exception = Assert.ThrowsAny <Exception>(() => decrypter.DecryptFile(new byte[0], fileCredentials) ); Assert.Matches(@"^Value cannot be null\.\s+Parameter name: FileHash$", exception.Message); Assert.IsType <ArgumentNullException>(exception); }
public async Task Should_Throw_If_Invalid_Hash_Length(string fileHash) { FileCredentials fileCredentials = new FileCredentials { Secret = "", FileHash = fileHash }; IDecrypter decrypter = new Decrypter(); Exception exception = await Assert.ThrowsAnyAsync <Exception>(() => decrypter.DecryptFileAsync(new MemoryStream(new byte[16]), fileCredentials, new MemoryStream()) ); Assert.Matches(@"^Hash length is not 32: \d+\.$", exception.Message); Assert.IsType <PassportDataDecryptionException>(exception); }
public async Task Should_Throw_If_Null_Destination() { IDecrypter decrypter = new Decrypter(); FileCredentials fileCredentials = new FileCredentials { Secret = "", FileHash = "" }; Exception exception = await Assert.ThrowsAnyAsync <Exception>(() => decrypter.DecryptFileAsync(new MemoryStream(), fileCredentials, null) ); Assert.Matches(@"^Value cannot be null\.\s+Parameter name: destination$", exception.Message); Assert.IsType <ArgumentNullException>(exception); }
public async Task Should_Throw_If_Empty_Data_Stream() { FileCredentials fileCredentials = new FileCredentials { Secret = "", FileHash = "" }; IDecrypter decrypter = new Decrypter(); Exception exception = await Assert.ThrowsAnyAsync <Exception>(() => decrypter.DecryptFileAsync(new MemoryStream(), fileCredentials, new MemoryStream()) ); Assert.Matches(@"^Stream is empty\.\s+Parameter name: encryptedContent$", exception.Message); Assert.IsType <ArgumentException>(exception); }
public void Should_Throw_If_Invalid_Data_Bytes_Length() { IDecrypter decrypter = new Decrypter(); FileCredentials fileCredentials = new FileCredentials { Secret = "", FileHash = "" }; Exception exception = Assert.ThrowsAny <Exception>(() => decrypter.DecryptFile(new byte[16 + 1], fileCredentials) ); Assert.Equal("Data length is not divisible by 16: 17.", exception.Message); Assert.IsType <PassportDataDecryptionException>(exception); }
public void Should_Throw_If_Invalid_Hash_Length(string fileHash) { FileCredentials fileCredentials = new FileCredentials { Secret = "", FileHash = fileHash }; IDecrypter decrypter = new Decrypter(); Exception exception = Assert.ThrowsAny <Exception>(() => decrypter.DecryptFile(new byte[16], fileCredentials) ); Assert.Matches(@"^Hash length is not 32: \d+\.$", exception.Message); Assert.IsType <PassportDataDecryptionException>(exception); }
/// <summary> /// Downloads an encrypted Passport file, decrypts it, and writes the content to /// <paramref name="destination"/> stream /// </summary> /// <param name="botClient">Instance of bot client</param> /// <param name="passportFile"></param> /// <param name="fileCredentials"></param> /// <param name="destination"></param> /// <param name="cancellationToken">The cancellation token to cancel operation.</param> /// <returns>File information of the encrypted Passport file on Telegram servers.</returns> /// <exception cref="ArgumentNullException"></exception> public static async Task <File> DownloadAndDecryptPassportFileAsync( this ITelegramBotClient botClient, PassportFile passportFile, FileCredentials fileCredentials, System.IO.Stream destination, CancellationToken cancellationToken = default ) { if (passportFile == null) { throw new ArgumentNullException(nameof(passportFile)); } if (fileCredentials == null) { throw new ArgumentNullException(nameof(fileCredentials)); } if (destination == null) { throw new ArgumentNullException(nameof(destination)); } File fileInfo; var encryptedContentStream = passportFile.FileSize > 0 ? new System.IO.MemoryStream(passportFile.FileSize) : new System.IO.MemoryStream(); using (encryptedContentStream) { fileInfo = await botClient.GetInfoAndDownloadFileAsync( passportFile.FileId, encryptedContentStream, cancellationToken ).ConfigureAwait(false); encryptedContentStream.Position = 0; await new Decrypter().DecryptFileAsync( encryptedContentStream, fileCredentials, destination, cancellationToken ).ConfigureAwait(false); } return(fileInfo); }
public async Task Should_Decrypt_Translation_File() { Update update = _classFixture.Entity; PassportData passportData = update.Message.PassportData; RSA key = EncryptionKey.ReadAsRsa(); EncryptedPassportElement element = passportData.Data.Single(); IDecrypter decrypter = new Decrypter(); Credentials credentials = decrypter.DecryptCredentials(passportData.Credentials, key); for (int i = 0; i < element.Translation.Length; i++) { PassportFile passportFile = element.Translation[i]; FileCredentials fileCredentials = credentials.SecureData.DriverLicense.Translation[i]; byte[] encryptedContent; { File encryptedFileInfo = await BotClient.GetFileAsync(passportFile.FileId); Assert.NotEmpty(encryptedFileInfo.FilePath); Assert.NotEmpty(encryptedFileInfo.FileId); Assert.InRange(encryptedFileInfo.FileSize, 1_000, 50_000_000); using (System.IO.MemoryStream stream = new System.IO.MemoryStream(encryptedFileInfo.FileSize)) { await BotClient.DownloadFileAsync(encryptedFileInfo.FilePath, stream); encryptedContent = stream.ToArray(); } } byte[] translationContent = decrypter.DecryptFile( encryptedContent, fileCredentials ); Assert.NotEmpty(translationContent); string decryptedFilePath = System.IO.Path.GetTempFileName(); await System.IO.File.WriteAllBytesAsync(decryptedFilePath, translationContent); _output.WriteLine("Translation JPEG file is written to \"{0}\".", decryptedFilePath); } }
public async Task Should_Decrypt_Utility_Bill_Element_Translation() { PassportData passportData = GetPassportData(); EncryptedPassportElement billElement = Assert.Single(passportData.Data, el => el.Type == "utility_bill"); Assert.NotNull(billElement.Translation); PassportFile translationFile = Assert.Single(billElement.Translation); Assert.Equal("DgADAQADOwADGV9BRP4b7RLGAtUKAg", translationFile.FileId); Assert.InRange(translationFile.FileDate, new DateTime(2018, 8, 30), new DateTime(2018, 8, 31)); Assert.Equal(0, translationFile.FileSize); IDecrypter decrypter = new Decrypter(); Credentials credentials = decrypter.DecryptCredentials(passportData.Credentials, EncryptionKey.RsaPrivateKey); FileCredentials translationFileCredentials = Assert.Single(credentials.SecureData.UtilityBill.Translation); byte[] encryptedContent = await System.IO.File.ReadAllBytesAsync("Files/utility_bill-translation.jpg.enc"); byte[] content = decrypter.DecryptFile( encryptedContent, translationFileCredentials ); Assert.NotEmpty(content); await System.IO.File.WriteAllBytesAsync("Files/utility_bill-translation.jpg", content); using (System.IO.MemoryStream encryptedFileStream = new System.IO.MemoryStream(encryptedContent), decryptedFileStream = new System.IO.MemoryStream() ) { await decrypter.DecryptFileAsync( encryptedFileStream, translationFileCredentials, decryptedFileStream ); Assert.Equal(content, decryptedFileStream.ToArray()); } }
public async Task Should_Throw_If_Invalid_Seekable_Data_Stream_Length() { IDecrypter decrypter = new Decrypter(); FileCredentials fileCredentials = new FileCredentials { Secret = "", FileHash = "" }; Exception exception; using (Stream encStream = new MemoryStream(new byte[16 - 1])) { exception = await Assert.ThrowsAnyAsync <Exception>(() => decrypter.DecryptFileAsync(encStream, fileCredentials, new MemoryStream()) ); } Assert.Equal("Data length is not divisible by 16: 15.", exception.Message); Assert.IsType <PassportDataDecryptionException>(exception); }
public async Task Should_Throw_If_NonWritable_Destination() { IDecrypter decrypter = new Decrypter(); FileCredentials fileCredentials = new FileCredentials { Secret = "", FileHash = "" }; Exception exception; using (Stream destStream = File.OpenRead("Files/s_dec7.driver_license-selfie.jpg")) { exception = await Assert.ThrowsAnyAsync <Exception>(() => decrypter.DecryptFileAsync(new MemoryStream(new byte[16]), fileCredentials, destStream) ); } Assert.Matches(@"^Stream does not support writing\.\s+Parameter name: destination$", exception.Message); Assert.IsType <ArgumentException>(exception); }
public async Task Should_Decrypt_From_Bytes() { FileCredentials fileCredentials = new FileCredentials { FileHash = "v3q47iscI6TS94CMo7HGQUOxw28LIf82NJBkImzP57c=", Secret = "vF7nut7clg/H/pEaTJigo4mQJ0s8B+HGCWKTWtOTIdo=", }; IDecrypter decrypter = new Decrypter(); byte[] encContent = await File.ReadAllBytesAsync("Files/bytes_dec1.driver_license-selfie.jpg.enc"); byte[] content = decrypter.DecryptFile( encContent, fileCredentials ); Assert.NotEmpty(content); Assert.InRange(content.Length, encContent.Length - 256, encContent.Length - 33); }
public void Should_Decrypt_Credentials() { PassportData passportData = GetPassportData(); IDecrypter decrypter = new Decrypter(); Credentials credentials = decrypter.DecryptCredentials(passportData.Credentials, EncryptionKey.RsaPrivateKey); Assert.NotNull(credentials); Assert.NotNull(credentials.SecureData); Assert.NotEmpty(credentials.Nonce); Assert.Equal("TEST", credentials.Nonce); // decryption of document data in 'driver_license' element requires accompanying DataCredentials Assert.NotNull(credentials.SecureData.DriverLicense); Assert.NotNull(credentials.SecureData.DriverLicense.Data); Assert.NotEmpty(credentials.SecureData.DriverLicense.Data.Secret); Assert.NotEmpty(credentials.SecureData.DriverLicense.Data.DataHash); // decryption of front side file in 'driver_license' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.DriverLicense.FrontSide); Assert.NotEmpty(credentials.SecureData.DriverLicense.FrontSide.Secret); Assert.NotEmpty(credentials.SecureData.DriverLicense.FrontSide.FileHash); // decryption of selfie file in 'driver_license' element requires accompanying FileCredentials Assert.NotNull(credentials.SecureData.DriverLicense.Selfie); Assert.NotEmpty(credentials.SecureData.DriverLicense.Selfie.Secret); Assert.NotEmpty(credentials.SecureData.DriverLicense.Selfie.FileHash); // decryption of translation file in 'driver_license' element requires accompanying FileCredentials Assert.NotEmpty(credentials.SecureData.DriverLicense.Translation); FileCredentials translationFileCredentials = Assert.Single( credentials.SecureData.DriverLicense.Translation ); Assert.NotNull(translationFileCredentials); Assert.NotEmpty(translationFileCredentials.Secret); Assert.NotEmpty(translationFileCredentials.FileHash); }
/// <inheritdoc /> 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 (fileCredentials.Secret is null) { throw new ArgumentNullException(nameof(fileCredentials.Secret)); } if (fileCredentials.FileHash is null) { throw new ArgumentNullException(nameof(fileCredentials.FileHash)); } if (encryptedContent.Length == 0) { throw new ArgumentException("Data array is empty.", nameof(encryptedContent)); } if (encryptedContent.Length % 16 != 0) { throw new PassportDataDecryptionException ($"Data length is not divisible by 16: {encryptedContent.Length}."); } byte[] dataSecret = Convert.FromBase64String(fileCredentials.Secret); byte[] dataHash = Convert.FromBase64String(fileCredentials.FileHash); if (dataHash.Length != 32) { throw new PassportDataDecryptionException($"Hash length is not 32: {dataHash.Length}."); } return(DecryptDataBytes(encryptedContent, dataSecret, dataHash)); }
public async Task Should_Throw_Decrypting_Bytes_With_Wrong_FileCredentials() { FileCredentials wrongFileCredentials = new FileCredentials { FileHash = "THTjgv2FU7kff/29Vty/IcqKPmOGkL7F35fAzmkfZdI=", Secret = "a+jxJoKPEaz77VCjRvDVcYHfIO3+h+oI+ruZh+KkYa0=", }; IDecrypter decrypter = new Decrypter(); byte[] encContent = await File.ReadAllBytesAsync("Files/bytes_dec3.driver_license-selfie.jpg.enc"); Exception exception = Assert.ThrowsAny <Exception>(() => decrypter.DecryptFile( encContent, wrongFileCredentials ) ); Assert.Matches(@"^Data hash mismatch at position \d+\.$", exception.Message); Assert.IsType <PassportDataDecryptionException>(exception); }
public void Should_Throw_Decrypting_Unencrypted_File_Valid_Length() { FileCredentials fileCredentials = new FileCredentials { FileHash = "v3q47iscI6TS94CMo7HGQUOxw28LIf82NJBkImzP57c=", Secret = "vF7nut7clg/H/pEaTJigo4mQJ0s8B+HGCWKTWtOTIdo=", }; IDecrypter decrypter = new Decrypter(); byte[] encContent = new byte[2048]; // data length is divisible by 16 Exception exception = Assert.ThrowsAny <Exception>(() => decrypter.DecryptFile( encContent, fileCredentials ) ); Assert.Matches(@"^Data hash mismatch at position \d+\.$", exception.Message); Assert.IsType <PassportDataDecryptionException>(exception); }
public async Task Should_Throw_Decrypting_Unencrypted_File_Invalid_Length() { FileCredentials fileCredentials = new FileCredentials { FileHash = "v3q47iscI6TS94CMo7HGQUOxw28LIf82NJBkImzP57c=", Secret = "vF7nut7clg/H/pEaTJigo4mQJ0s8B+HGCWKTWtOTIdo=", }; IDecrypter decrypter = new Decrypter(); byte[] encContent = await File.ReadAllBytesAsync("Files/bytes_dec2.driver_license-selfie.jpg"); Exception exception = Assert.ThrowsAny <Exception>(() => decrypter.DecryptFile( encContent, fileCredentials ) ); Assert.Matches(@"^Data length is not divisible by 16: \d+\.$", exception.Message); Assert.IsType <PassportDataDecryptionException>(exception); }
public async Task Should_Decrypt_From_NonSeekable_Stream() { FileCredentials fileCredentials = new FileCredentials { FileHash = "v3q47iscI6TS94CMo7HGQUOxw28LIf82NJBkImzP57c=", Secret = "vF7nut7clg/H/pEaTJigo4mQJ0s8B+HGCWKTWtOTIdo=", }; IDecrypter decrypter = new Decrypter(); using (Stream encFileStream = new NonSeekableFileReadStream("Files/s_dec2.driver_license-selfie.jpg.enc"), fileStream = new MemoryStream() ) { await decrypter.DecryptFileAsync( encFileStream, fileCredentials, fileStream ); } }