File indexing completed on 2024-05-05 05:53:13
0001 /* 0002 * SPDX-License-Identifier: GPL-3.0-or-later 0003 * SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com> 0004 */ 0005 #include "hmac.h" 0006 #include "../logging_p.h" 0007 0008 KEYSMITH_LOGGER(logger, ".hmac") 0009 0010 static QByteArray hmac_stage(QCryptographicHash::Algorithm algorithm, char * const keyBuf, int ksize, int blockSize, const char fillPad, const char xorKey, const QByteArray &message) 0011 { 0012 QCryptographicHash hash(algorithm); 0013 int count; 0014 for (count = 0; count < ksize; ++count) { 0015 keyBuf[count] ^= xorKey; 0016 } 0017 0018 hash.addData(keyBuf, count); 0019 0020 if (ksize < blockSize) { 0021 QByteArray pad(blockSize - ksize, fillPad); 0022 hash.addData(pad); 0023 } 0024 0025 hash.addData(message); 0026 0027 return hash.result(); 0028 } 0029 0030 namespace hmac 0031 { 0032 std::optional<int> blockSize(QCryptographicHash::Algorithm algorithm) 0033 { 0034 switch (algorithm) { 0035 case QCryptographicHash::Md4: 0036 case QCryptographicHash::Md5: 0037 case QCryptographicHash::Sha1: 0038 case QCryptographicHash::Sha224: 0039 case QCryptographicHash::Sha256: 0040 return std::optional<int>(64ULL); 0041 case QCryptographicHash::Sha384: 0042 case QCryptographicHash::Sha512: 0043 return std::optional<int>(128ULL); 0044 case QCryptographicHash::RealSha3_224: 0045 case QCryptographicHash::Keccak_224: 0046 return std::optional<int>(144ULL); 0047 case QCryptographicHash::RealSha3_256: 0048 case QCryptographicHash::Keccak_256: 0049 return std::optional<int>(136ULL); 0050 case QCryptographicHash::RealSha3_384: 0051 case QCryptographicHash::Keccak_384: 0052 return std::optional<int>(104ULL); 0053 case QCryptographicHash::RealSha3_512: 0054 case QCryptographicHash::Keccak_512: 0055 return std::optional<int>(72ULL); 0056 default: 0057 return std::nullopt; 0058 } 0059 } 0060 0061 std::optional<uint> outputSize(QCryptographicHash::Algorithm algorithm) 0062 { 0063 switch (algorithm) { 0064 case QCryptographicHash::Md4: 0065 case QCryptographicHash::Md5: 0066 return std::optional<uint>(16ULL); 0067 case QCryptographicHash::Sha1: 0068 return std::optional<uint>(20ULL); 0069 case QCryptographicHash::Sha224: 0070 case QCryptographicHash::RealSha3_224: 0071 case QCryptographicHash::Keccak_224: 0072 return std::optional<int>(28UL); 0073 case QCryptographicHash::Sha256: 0074 case QCryptographicHash::RealSha3_256: 0075 case QCryptographicHash::Keccak_256: 0076 return std::optional<int>(32UL); 0077 case QCryptographicHash::Sha384: 0078 case QCryptographicHash::RealSha3_384: 0079 case QCryptographicHash::Keccak_384: 0080 return std::optional<int>(48UL); 0081 case QCryptographicHash::Sha512: 0082 case QCryptographicHash::RealSha3_512: 0083 case QCryptographicHash::Keccak_512: 0084 return std::optional<uint>(64UL); 0085 default: 0086 return std::nullopt; 0087 } 0088 } 0089 0090 bool validateKeySize(QCryptographicHash::Algorithm algorithm, int ksize, bool requireSaneKeyLength) 0091 { 0092 std::optional<int> maybeOutputSize = outputSize(algorithm); 0093 return maybeOutputSize && ksize >= 0 && (ksize >= (*maybeOutputSize) || !requireSaneKeyLength); 0094 } 0095 0096 std::optional<QByteArray> compute(QCryptographicHash::Algorithm algorithm, char * rawKey, int ksize, const QByteArray &message, bool requireSaneKeyLength) 0097 { 0098 if (!rawKey) { 0099 return std::nullopt; 0100 } 0101 0102 std::optional<int> maybeBlockSize = blockSize(algorithm); 0103 if (!maybeBlockSize) { 0104 qCDebug(logger) << "Unable to determine block size for hashing algorithm:" << algorithm; 0105 return std::nullopt; 0106 } 0107 0108 if (!validateKeySize(algorithm, ksize, requireSaneKeyLength)) { 0109 qCDebug(logger) 0110 << "Invalid HMAC key size:" << ksize << "for hashing algorithm:" << algorithm 0111 << "Sane key length requirements apply:" << requireSaneKeyLength; 0112 return std::nullopt; 0113 } 0114 0115 int bs = *maybeBlockSize; 0116 QByteArray hashedKey; 0117 0118 if (ksize > bs) { 0119 QCryptographicHash khash(algorithm); 0120 khash.addData(rawKey, ksize); 0121 hashedKey = khash.result(); 0122 rawKey = hashedKey.data(); 0123 ksize = hashedKey.size(); 0124 } 0125 0126 QByteArray inner = hmac_stage(algorithm, rawKey, ksize, bs, '\x36', '\x36', message); 0127 QByteArray result = hmac_stage(algorithm, rawKey, ksize, bs, '\x5c', '\x36' ^ '\x5c', inner); 0128 0129 hashedKey.fill('\x0'); 0130 return std::optional<QByteArray>(result); 0131 } 0132 }