Poly1305KeyGenerator.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
  8. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Generators
  9. {
  10. /// <summary>
  11. /// Generates keys for the Poly1305 MAC.
  12. /// </summary>
  13. /// <remarks>
  14. /// Poly1305 keys are 256 bit keys consisting of a 128 bit secret key used for the underlying block
  15. /// cipher followed by a 128 bit {@code r} value used for the polynomial portion of the Mac. <br/>
  16. /// The {@code r} value has a specific format with some bits required to be cleared, resulting in an
  17. /// effective 106 bit key. <br/>
  18. /// A separately generated 256 bit key can be modified to fit the Poly1305 key format by using the
  19. /// {@link #clamp(byte[])} method to clear the required bits.
  20. /// </remarks>
  21. /// <seealso cref="Poly1305"/>
  22. public class Poly1305KeyGenerator
  23. : CipherKeyGenerator
  24. {
  25. private const byte R_MASK_LOW_2 = (byte)0xFC;
  26. private const byte R_MASK_HIGH_4 = (byte)0x0F;
  27. /// <summary>
  28. /// Initialises the key generator.
  29. /// </summary>
  30. /// <remarks>
  31. /// Poly1305 keys are always 256 bits, so the key length in the provided parameters is ignored.
  32. /// </remarks>
  33. protected override void engineInit(KeyGenerationParameters param)
  34. {
  35. // Poly1305 keys are always 256 bits
  36. this.random = param.Random;
  37. this.strength = 32;
  38. }
  39. /// <summary>
  40. /// Generates a 256 bit key in the format required for Poly1305 - e.g.
  41. /// <code>k[0] ... k[15], r[0] ... r[15]</code> with the required bits in <code>r</code> cleared
  42. /// as per <see cref="Clamp(byte[])"/>.
  43. /// </summary>
  44. protected override byte[] engineGenerateKey()
  45. {
  46. byte[] key = base.engineGenerateKey();
  47. Clamp(key);
  48. return key;
  49. }
  50. /// <summary>
  51. /// Modifies an existing 32 byte key value to comply with the requirements of the Poly1305 key by
  52. /// clearing required bits in the <code>r</code> (second 16 bytes) portion of the key.<br/>
  53. /// Specifically:
  54. /// <ul>
  55. /// <li>r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})</li>
  56. /// <li>r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252})</li>
  57. /// </ul>
  58. /// </summary>
  59. /// <param name="key">a 32 byte key value <code>k[0] ... k[15], r[0] ... r[15]</code></param>
  60. public static void Clamp(byte[] key)
  61. {
  62. /*
  63. * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl.
  64. */
  65. if (key.Length != 32)
  66. throw new ArgumentException("Poly1305 key must be 256 bits.");
  67. /*
  68. * r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})
  69. */
  70. key[3] &= R_MASK_HIGH_4;
  71. key[7] &= R_MASK_HIGH_4;
  72. key[11] &= R_MASK_HIGH_4;
  73. key[15] &= R_MASK_HIGH_4;
  74. /*
  75. * r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}).
  76. */
  77. key[4] &= R_MASK_LOW_2;
  78. key[8] &= R_MASK_LOW_2;
  79. key[12] &= R_MASK_LOW_2;
  80. }
  81. /// <summary>
  82. /// Checks a 32 byte key for compliance with the Poly1305 key requirements, e.g.
  83. /// <code>k[0] ... k[15], r[0] ... r[15]</code> with the required bits in <code>r</code> cleared
  84. /// as per <see cref="Clamp(byte[])"/>.
  85. /// </summary>
  86. /// <param name="key">Key.</param>
  87. /// <exception cref="System.ArgumentException">if the key is of the wrong length, or has invalid bits set
  88. /// in the <code>r</code> portion of the key.</exception>
  89. public static void CheckKey(byte[] key)
  90. {
  91. if (key.Length != 32)
  92. throw new ArgumentException("Poly1305 key must be 256 bits.");
  93. CheckMask(key[3], R_MASK_HIGH_4);
  94. CheckMask(key[7], R_MASK_HIGH_4);
  95. CheckMask(key[11], R_MASK_HIGH_4);
  96. CheckMask(key[15], R_MASK_HIGH_4);
  97. CheckMask(key[4], R_MASK_LOW_2);
  98. CheckMask(key[8], R_MASK_LOW_2);
  99. CheckMask(key[12], R_MASK_LOW_2);
  100. }
  101. private static void CheckMask(byte b, byte mask)
  102. {
  103. if ((b & (~mask)) != 0)
  104. throw new ArgumentException("Invalid format for r portion of Poly1305 key.");
  105. }
  106. }
  107. }
  108. #pragma warning restore
  109. #endif