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 28 import ocean.util.cipher.gcrypt.core.MessageDigestCore; 29 import ocean.transition; 30 import ocean.util.cipher.gcrypt.c.md; 31 32 /******************************************************************************/ 33 34 public class HMAC: MessageDigestCore 35 { 36 import ocean.util.cipher.gcrypt.core.Gcrypt: GcryptException; 37 38 /*************************************************************************** 39 40 Constructor. 41 42 Params: 43 algorithm = the hash algorithm to use 44 flags = flags to `gcry_md_open()` 45 46 Throws: 47 `GcryptException` on error. There are two possible error causes: 48 - The parameters are invalid or not supported by the libcrypt 49 of the run-time enviromnent. 50 - libgcrypt failed allocating memory. 51 52 ***************************************************************************/ 53 54 public this ( gcry_md_algos algorithm, gcry_md_flags flags = cast(gcry_md_flags)0, 55 istring file = __FILE__, int line = __LINE__ ) 56 { 57 super(algorithm, flags | flags.GCRY_MD_FLAG_HMAC, file, line); 58 } 59 60 /*************************************************************************** 61 62 Calculates the HMAC from the authentication key and the input data. 63 64 Discards the result of a previous hash calculation, invalidating and 65 overwriting a previously returned result. 66 67 An error can be caused only by the parameters passed to the constructor. 68 If this method does not throw, it is safe to assume it will never throw 69 for the same set of constructor parameters. 70 71 The length of the returned hash is the return value of 72 `gcry_md_get_algo_dlen(algorithm)` for the algorithm passed to the 73 constructor of this class. 74 75 An empty `key` and/or empty `input_data` are tolerated. 76 77 Params: 78 key = the HMAC key 79 input_data = the data to hash, which will be concatenated 80 81 Returns: 82 the resuting HMAC. 83 84 Throws: 85 `GcryptException` on error. 86 87 ***************************************************************************/ 88 89 public ubyte[] calculate ( Const!(ubyte)[] key, Const!(ubyte)[][] input_data ... ) 90 { 91 gcry_md_reset(this.md); 92 93 if (key.length) 94 { 95 GcryptException.throwNewIfGcryptError( 96 gcry_md_setkey(this.md, key.ptr, key.length) 97 ); 98 } 99 100 return this.calculate_(input_data); 101 } 102 } 103 104 /******************************************************************************/ 105 106 version ( UnitTest ) 107 { 108 import ocean.core.Test; 109 } 110 111 unittest 112 { 113 // https://tools.ietf.org/html/rfc4231#section-4.2 114 static Immut!(ubyte)[] sha224_hmac = [ 115 0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 116 0x19, 0x68, 0x32, 0x10, 0x7c, 0xd4, 0x9d, 117 0xf3, 0x3f, 0x47, 0xb4, 0xb1, 0x16, 0x99, 118 0x12, 0xba, 0x4f, 0x53, 0x68, 0x4b, 0x22 119 ]; 120 121 Immut!(ubyte)[20] key = 0x0b; 122 scope hmacgen = new HMAC(gcry_md_algos.GCRY_MD_SHA224); 123 test!("==")( 124 hmacgen.calculate( 125 key, 126 cast(Immut!(ubyte)[])"Hi", 127 cast(Immut!(ubyte)[])" ", 128 cast(Immut!(ubyte)[])"There" 129 ), 130 sha224_hmac 131 ); 132 133 test!("==")( 134 hmacgen.calculate( 135 key, 136 [ 137 cast(Immut!(ubyte)[])"Hi", 138 cast(Immut!(ubyte)[])" ", 139 cast(Immut!(ubyte)[])"There" 140 ] 141 ), 142 sha224_hmac 143 ); 144 }