1 /******************************************************************************* 2 3 libgcrypt hash-based message authentication code generator utility class. 4 5 Be aware that not all versions of libcgrypt support all hash algorithms; the 6 constructor will throw if the specified algorithm is not supported by the 7 run-time version of libgcrypt. However, if the constructor does not throw, 8 it is safe to assume it will never throw for the same set of parameters 9 (except for the fatal situation that libgcrypt failed allocating memory). 10 11 Requires linking with libgcrypt: 12 -L-lgcrypt 13 14 Copyright: 15 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 16 All rights reserved. 17 18 License: 19 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 20 Alternatively, this file may be distributed under the terms of the Tango 21 3-Clause BSD License (see LICENSE_BSD.txt for details). 22 23 *******************************************************************************/ 24 25 module ocean.util.cipher.gcrypt.HMAC; 26 27 import ocean.util.cipher.gcrypt.core.MessageDigestCore; 28 import ocean.util.cipher.gcrypt.c.md; 29 30 /******************************************************************************/ 31 32 public class HMAC: MessageDigestCore 33 { 34 import ocean.util.cipher.gcrypt.core.Gcrypt: GcryptException; 35 36 /*************************************************************************** 37 38 Constructor. 39 40 Params: 41 algorithm = the hash algorithm to use 42 flags = flags to `gcry_md_open()` 43 44 Throws: 45 `GcryptException` on error. There are two possible error causes: 46 - The parameters are invalid or not supported by the libcrypt 47 of the run-time enviromnent. 48 - libgcrypt failed allocating memory. 49 50 ***************************************************************************/ 51 52 public this ( gcry_md_algos algorithm, gcry_md_flags flags = cast(gcry_md_flags)0, 53 string file = __FILE__, int line = __LINE__ ) 54 { 55 super(algorithm, flags | flags.GCRY_MD_FLAG_HMAC, file, line); 56 } 57 58 /*************************************************************************** 59 60 Calculates the HMAC from the authentication key and the input data. 61 62 Discards the result of a previous hash calculation, invalidating and 63 overwriting a previously returned result. 64 65 An error can be caused only by the parameters passed to the constructor. 66 If this method does not throw, it is safe to assume it will never throw 67 for the same set of constructor parameters. 68 69 The length of the returned hash is the return value of 70 `gcry_md_get_algo_dlen(algorithm)` for the algorithm passed to the 71 constructor of this class. 72 73 An empty `key` and/or empty `input_data` are tolerated. 74 75 Params: 76 key = the HMAC key 77 input_data = the data to hash, which will be concatenated 78 79 Returns: 80 the resuting HMAC. 81 82 Throws: 83 `GcryptException` on error. 84 85 ***************************************************************************/ 86 87 public ubyte[] calculate (const(ubyte)[] key, const(ubyte)[][] input_data ... ) 88 { 89 gcry_md_reset(this.md); 90 91 if (key.length) 92 { 93 GcryptException.throwNewIfGcryptError( 94 gcry_md_setkey(this.md, key.ptr, key.length) 95 ); 96 } 97 98 return this.calculate_(input_data); 99 } 100 } 101 102 /******************************************************************************/ 103 104 version (unittest) 105 { 106 import ocean.core.Test; 107 } 108 109 unittest 110 { 111 // https://tools.ietf.org/html/rfc4231#section-4.2 112 static immutable(ubyte)[] sha224_hmac = [ 113 0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 114 0x19, 0x68, 0x32, 0x10, 0x7c, 0xd4, 0x9d, 115 0xf3, 0x3f, 0x47, 0xb4, 0xb1, 0x16, 0x99, 116 0x12, 0xba, 0x4f, 0x53, 0x68, 0x4b, 0x22 117 ]; 118 119 immutable(ubyte)[20] key = 0x0b; 120 scope hmacgen = new HMAC(gcry_md_algos.GCRY_MD_SHA224); 121 test!("==")( 122 hmacgen.calculate( 123 key, 124 cast(immutable(ubyte)[])"Hi", 125 cast(immutable(ubyte)[])" ", 126 cast(immutable(ubyte)[])"There" 127 ), 128 sha224_hmac 129 ); 130 131 test!("==")( 132 hmacgen.calculate( 133 key, 134 [ 135 cast(immutable(ubyte)[])"Hi", 136 cast(immutable(ubyte)[])" ", 137 cast(immutable(ubyte)[])"There" 138 ] 139 ), 140 sha224_hmac 141 ); 142 }