GcmAuthenticatedEncryptorTests.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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 GcmAuthenticatedEncryptorTests
  14. {
  15. [ConditionalFact]
  16. [ConditionalRunTestOnlyOnWindows]
  17. public void Encrypt_Decrypt_RoundTrips()
  18. {
  19. // Arrange
  20. Secret kdk = new Secret(new byte[512 / 8]);
  21. GcmAuthenticatedEncryptor encryptor = new GcmAuthenticatedEncryptor(kdk, CachedAlgorithmHandles.AES_GCM, symmetricAlgorithmKeySizeInBytes: 256 / 8);
  22. ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
  23. ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("aad"));
  24. // Act
  25. byte[] ciphertext = encryptor.Encrypt(plaintext, aad);
  26. byte[] decipheredtext = encryptor.Decrypt(new ArraySegment<byte>(ciphertext), aad);
  27. // Assert
  28. Assert.Equal(plaintext, decipheredtext);
  29. }
  30. [ConditionalFact]
  31. [ConditionalRunTestOnlyOnWindows]
  32. public void Encrypt_Decrypt_Tampering_Fails()
  33. {
  34. // Arrange
  35. Secret kdk = new Secret(new byte[512 / 8]);
  36. GcmAuthenticatedEncryptor encryptor = new GcmAuthenticatedEncryptor(kdk, CachedAlgorithmHandles.AES_GCM, symmetricAlgorithmKeySizeInBytes: 256 / 8);
  37. ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
  38. ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("aad"));
  39. byte[] validCiphertext = encryptor.Encrypt(plaintext, aad);
  40. // Act & assert - 1
  41. // Ciphertext is too short to be a valid payload
  42. byte[] invalidCiphertext_tooShort = new byte[10];
  43. Assert.Throws<CryptographicException>(() =>
  44. {
  45. encryptor.Decrypt(new ArraySegment<byte>(invalidCiphertext_tooShort), aad);
  46. });
  47. // Act & assert - 2
  48. // Ciphertext has been manipulated
  49. byte[] invalidCiphertext_manipulated = (byte[])validCiphertext.Clone();
  50. invalidCiphertext_manipulated[0] ^= 0x01;
  51. Assert.Throws<CryptographicException>(() =>
  52. {
  53. encryptor.Decrypt(new ArraySegment<byte>(invalidCiphertext_manipulated), aad);
  54. });
  55. // Act & assert - 3
  56. // Ciphertext is too long
  57. byte[] invalidCiphertext_tooLong = validCiphertext.Concat(new byte[] { 0 }).ToArray();
  58. Assert.Throws<CryptographicException>(() =>
  59. {
  60. encryptor.Decrypt(new ArraySegment<byte>(invalidCiphertext_tooLong), aad);
  61. });
  62. // Act & assert - 4
  63. // AAD is incorrect
  64. Assert.Throws<CryptographicException>(() =>
  65. {
  66. encryptor.Decrypt(new ArraySegment<byte>(validCiphertext), new ArraySegment<byte>(Encoding.UTF8.GetBytes("different aad")));
  67. });
  68. }
  69. [ConditionalFact]
  70. [ConditionalRunTestOnlyOnWindows]
  71. public void Encrypt_KnownKey()
  72. {
  73. // Arrange
  74. Secret kdk = new Secret(Encoding.UTF8.GetBytes("master key"));
  75. GcmAuthenticatedEncryptor encryptor = new GcmAuthenticatedEncryptor(kdk, CachedAlgorithmHandles.AES_GCM, symmetricAlgorithmKeySizeInBytes: 128 / 8, genRandom: new SequentialGenRandom());
  76. ArraySegment<byte> plaintext = new ArraySegment<byte>(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, 2, 3);
  77. ArraySegment<byte> aad = new ArraySegment<byte>(new byte[] { 7, 6, 5, 4, 3, 2, 1, 0 }, 1, 4);
  78. // Act
  79. byte[] retVal = encryptor.Encrypt(
  80. plaintext: plaintext,
  81. additionalAuthenticatedData: aad,
  82. preBufferSize: 3,
  83. postBufferSize: 4);
  84. // Assert
  85. // retVal := 00 00 00 (preBuffer)
  86. // | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F (keyModifier)
  87. // | 10 11 12 13 14 15 16 17 18 19 1A 1B (nonce)
  88. // | 43 B6 91 (encryptedData)
  89. // | 8D 0D 66 D9 A1 D9 44 2D 5D 8E 41 DA 39 60 9C E8 (authTag)
  90. // | 00 00 00 00 (postBuffer)
  91. string retValAsString = Convert.ToBase64String(retVal);
  92. Assert.Equal("AAAAAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaG0O2kY0NZtmh2UQtXY5B2jlgnOgAAAAA", retValAsString);
  93. }
  94. }
  95. }