CbcAuthenticatedEncryptorTests.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Copyright (c) .NET Foundation. All rights reserved.
  2. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  3. using System;
  4. using System.Linq;
  5. using System.Security.Cryptography;
  6. using System.Text;
  7. using Microsoft.AspNetCore.Cryptography.Cng;
  8. using Microsoft.AspNetCore.DataProtection.Test.Shared;
  9. using Microsoft.AspNetCore.Testing.xunit;
  10. using Xunit;
  11. namespace Microsoft.AspNetCore.DataProtection.Cng
  12. {
  13. public class CbcAuthenticatedEncryptorTests
  14. {
  15. [ConditionalFact]
  16. [ConditionalRunTestOnlyOnWindows]
  17. public void Encrypt_Decrypt_RoundTrips()
  18. {
  19. // Arrange
  20. Secret kdk = new Secret(new byte[512 / 8]);
  21. CbcAuthenticatedEncryptor encryptor = new CbcAuthenticatedEncryptor(kdk,
  22. symmetricAlgorithmHandle: CachedAlgorithmHandles.AES_CBC,
  23. symmetricAlgorithmKeySizeInBytes: 256 / 8,
  24. hmacAlgorithmHandle: CachedAlgorithmHandles.HMAC_SHA256);
  25. ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
  26. ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("aad"));
  27. // Act
  28. byte[] ciphertext = encryptor.Encrypt(plaintext, aad);
  29. byte[] decipheredtext = encryptor.Decrypt(new ArraySegment<byte>(ciphertext), aad);
  30. // Assert
  31. Assert.Equal(plaintext, decipheredtext);
  32. }
  33. [ConditionalFact]
  34. [ConditionalRunTestOnlyOnWindows]
  35. public void Encrypt_Decrypt_Tampering_Fails()
  36. {
  37. // Arrange
  38. Secret kdk = new Secret(new byte[512 / 8]);
  39. CbcAuthenticatedEncryptor encryptor = new CbcAuthenticatedEncryptor(kdk,
  40. symmetricAlgorithmHandle: CachedAlgorithmHandles.AES_CBC,
  41. symmetricAlgorithmKeySizeInBytes: 256 / 8,
  42. hmacAlgorithmHandle: CachedAlgorithmHandles.HMAC_SHA256);
  43. ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
  44. ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("aad"));
  45. byte[] validCiphertext = encryptor.Encrypt(plaintext, aad);
  46. // Act & assert - 1
  47. // Ciphertext is too short to be a valid payload
  48. byte[] invalidCiphertext_tooShort = new byte[10];
  49. Assert.Throws<CryptographicException>(() =>
  50. {
  51. encryptor.Decrypt(new ArraySegment<byte>(invalidCiphertext_tooShort), aad);
  52. });
  53. // Act & assert - 2
  54. // Ciphertext has been manipulated
  55. byte[] invalidCiphertext_manipulated = (byte[])validCiphertext.Clone();
  56. invalidCiphertext_manipulated[0] ^= 0x01;
  57. Assert.Throws<CryptographicException>(() =>
  58. {
  59. encryptor.Decrypt(new ArraySegment<byte>(invalidCiphertext_manipulated), aad);
  60. });
  61. // Act & assert - 3
  62. // Ciphertext is too long
  63. byte[] invalidCiphertext_tooLong = validCiphertext.Concat(new byte[] { 0 }).ToArray();
  64. Assert.Throws<CryptographicException>(() =>
  65. {
  66. encryptor.Decrypt(new ArraySegment<byte>(invalidCiphertext_tooLong), aad);
  67. });
  68. // Act & assert - 4
  69. // AAD is incorrect
  70. Assert.Throws<CryptographicException>(() =>
  71. {
  72. encryptor.Decrypt(new ArraySegment<byte>(validCiphertext), new ArraySegment<byte>(Encoding.UTF8.GetBytes("different aad")));
  73. });
  74. }
  75. [ConditionalFact]
  76. [ConditionalRunTestOnlyOnWindows]
  77. public void Encrypt_KnownKey()
  78. {
  79. // Arrange
  80. Secret kdk = new Secret(Encoding.UTF8.GetBytes("master key"));
  81. CbcAuthenticatedEncryptor encryptor = new CbcAuthenticatedEncryptor(kdk,
  82. symmetricAlgorithmHandle: CachedAlgorithmHandles.AES_CBC,
  83. symmetricAlgorithmKeySizeInBytes: 256 / 8,
  84. hmacAlgorithmHandle: CachedAlgorithmHandles.HMAC_SHA256,
  85. genRandom: new SequentialGenRandom());
  86. ArraySegment<byte> plaintext = new ArraySegment<byte>(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, 2, 3);
  87. ArraySegment<byte> aad = new ArraySegment<byte>(new byte[] { 7, 6, 5, 4, 3, 2, 1, 0 }, 1, 4);
  88. // Act
  89. byte[] retVal = encryptor.Encrypt(
  90. plaintext: plaintext,
  91. additionalAuthenticatedData: aad,
  92. preBufferSize: 3,
  93. postBufferSize: 4);
  94. // Assert
  95. // retVal := 00 00 00 (preBuffer)
  96. // | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F (keyModifier)
  97. // | 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F (IV)
  98. // | B7 EA 3E 32 58 93 A3 06 03 89 C6 66 03 63 08 4B (encryptedData)
  99. // | 9D 8A 85 C7 0F BD 98 D8 7F 72 E7 72 3E B5 A6 26 (HMAC)
  100. // | 6C 38 77 F7 66 19 A2 C9 2C BB AD DA E7 62 00 00
  101. // | 00 00 00 00 (postBuffer)
  102. string retValAsString = Convert.ToBase64String(retVal);
  103. Assert.Equal("AAAAAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh+36j4yWJOjBgOJxmYDYwhLnYqFxw+9mNh/cudyPrWmJmw4d/dmGaLJLLut2udiAAAAAAAA", retValAsString);
  104. }
  105. }
  106. }