mac.d 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. module secured.mac;
  2. import std.stdio;
  3. import std.format;
  4. import secured.openssl;
  5. import deimos.openssl.evp;
  6. import secured.hash;
  7. import secured.util;
  8. @safe public ubyte[] hmac(const ubyte[] key, const ubyte[] data) {
  9. return hmac_ex(key, data, HashAlgorithm.Default);
  10. }
  11. @safe public bool hmac_verify(const ubyte[] test, const ubyte[] key, const ubyte[] data) {
  12. ubyte[] hash = hmac_ex(key, data, HashAlgorithm.Default);
  13. return constantTimeEquality(test, hash);
  14. }
  15. @trusted public ubyte[] hmac_ex(const ubyte[] key, const ubyte[] data, HashAlgorithm func)
  16. {
  17. if (key.length > getHashLength(func)) {
  18. throw new CryptographicException(format("HMAC key must be less than or equal to %s bytes in length.", getHashLength(func)));
  19. }
  20. //Create the OpenSSL context
  21. EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
  22. if (mdctx == null) {
  23. throw new CryptographicException("Unable to create OpenSSL context.");
  24. }
  25. scope(exit) {
  26. if(mdctx !is null) {
  27. EVP_MD_CTX_free(mdctx);
  28. }
  29. }
  30. //Initialize the hash algorithm
  31. auto md = getOpenSSLHashAlgorithm(func);
  32. if (EVP_DigestInit_ex(mdctx, md, null) != 1) {
  33. throw new CryptographicException("Unable to create hash context.");
  34. }
  35. //Create the HMAC key context
  36. auto pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, null, key.ptr, cast(int)key.length);
  37. scope(exit) {
  38. if(pkey !is null) {
  39. EVP_PKEY_free(pkey);
  40. }
  41. }
  42. if (EVP_DigestSignInit(mdctx, null, md, null, pkey) != 1) {
  43. throw new CryptographicException("Unable to create HMAC key context.");
  44. }
  45. //Run the provided data through the digest algorithm
  46. if (EVP_DigestSignUpdate(mdctx, data.ptr, data.length) != 1) {
  47. throw new CryptographicException("Error while updating digest.");
  48. }
  49. //Copy the OpenSSL digest to our D buffer.
  50. size_t digestlen = getHashLength(func);
  51. ubyte[] digest = new ubyte[getHashLength(func)];
  52. if (EVP_DigestSignFinal(mdctx, digest.ptr, &digestlen) < 0) {
  53. throw new CryptographicException("Error while retrieving the digest.");
  54. }
  55. return digest;
  56. }
  57. @safe public bool hmac_verify_ex(const ubyte[] test, const ubyte[] key, const ubyte[] data, HashAlgorithm func){
  58. ubyte[] hash = hmac_ex(key, data, func);
  59. return constantTimeEquality(test, hash);
  60. }
  61. unittest {
  62. import std.digest;
  63. ubyte[48] key = [ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
  64. 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
  65. 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF ];
  66. writeln("Testing HMAC Basic:");
  67. ubyte[] verify_basic_hash = hmac(key, cast(ubyte[])"");
  68. assert(hmac_verify(verify_basic_hash, key, cast(ubyte[])""));
  69. writeln(toHexString!(LetterCase.lower)(verify_basic_hash));
  70. writeln("Testing HMAC Extended:");
  71. ubyte[] vec1 = hmac_ex(key, cast(ubyte[])"", HashAlgorithm.SHA2_384);
  72. ubyte[] vec2 = hmac_ex(key, cast(ubyte[])"abc", HashAlgorithm.SHA2_384);
  73. ubyte[] vec3 = hmac_ex(key, cast(ubyte[])"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", HashAlgorithm.SHA2_384);
  74. writeln(toHexString!(LetterCase.lower)(vec1));
  75. writeln(toHexString!(LetterCase.lower)(vec2));
  76. writeln(toHexString!(LetterCase.lower)(vec3));
  77. assert(toHexString!(LetterCase.lower)(vec1) == "440b0d5f59c32cbee090c3d9f524b81a9b9708e9b65a46bbc189842b0ab0759d3bf118acca58eda0813fd346e8ccfde4");
  78. assert(toHexString!(LetterCase.lower)(vec2) == "cb5da1048feb76fd75752dc1b699caba124090feac21adb5b4c0f6600e7b626e08d7415660aa0ee79ca5b83e56669a60");
  79. assert(toHexString!(LetterCase.lower)(vec3) == "460b59c0bd8ae48133431185a4583376738be3116cafce47aff7696bd19501b0cf1f1850c3e5fa2992882997493d1c99");
  80. ubyte[32] keyshort = [ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
  81. 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF ];
  82. ubyte[] verify_hash = hmac_ex(keyshort, cast(ubyte[])"", HashAlgorithm.SHA2_256);
  83. assert(hmac_verify_ex(verify_hash, keyshort, cast(ubyte[])"", HashAlgorithm.SHA2_256));
  84. writeln(toHexString!(LetterCase.lower)(verify_hash));
  85. }