mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-26 04:22:07 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			122 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #include <AK/ByteBuffer.h>
 | |
| #include <AK/StringBuilder.h>
 | |
| #include <AK/StringView.h>
 | |
| #include <AK/Types.h>
 | |
| #include <AK/Vector.h>
 | |
| 
 | |
| #ifndef KERNEL
 | |
| #    include <AK/DeprecatedString.h>
 | |
| #endif
 | |
| 
 | |
| constexpr static auto IPAD = 0x36;
 | |
| constexpr static auto OPAD = 0x5c;
 | |
| 
 | |
| namespace Crypto::Authentication {
 | |
| 
 | |
| template<typename HashT>
 | |
| class HMAC {
 | |
| public:
 | |
|     using HashType = HashT;
 | |
|     using TagType = typename HashType::DigestType;
 | |
| 
 | |
|     constexpr size_t digest_size() const { return m_inner_hasher.digest_size(); }
 | |
| 
 | |
|     template<typename KeyBufferType, typename... Args>
 | |
|     HMAC(KeyBufferType key, Args... args)
 | |
|         : m_inner_hasher(args...)
 | |
|         , m_outer_hasher(args...)
 | |
|     {
 | |
|         derive_key(key);
 | |
|         reset();
 | |
|     }
 | |
| 
 | |
|     TagType process(u8 const* message, size_t length)
 | |
|     {
 | |
|         reset();
 | |
|         update(message, length);
 | |
|         return digest();
 | |
|     }
 | |
| 
 | |
|     void update(u8 const* message, size_t length)
 | |
|     {
 | |
|         m_inner_hasher.update(message, length);
 | |
|     }
 | |
| 
 | |
|     TagType process(ReadonlyBytes span) { return process(span.data(), span.size()); }
 | |
|     TagType process(StringView string) { return process((u8 const*)string.characters_without_null_termination(), string.length()); }
 | |
| 
 | |
|     void update(ReadonlyBytes span) { return update(span.data(), span.size()); }
 | |
|     void update(StringView string) { return update((u8 const*)string.characters_without_null_termination(), string.length()); }
 | |
| 
 | |
|     TagType digest()
 | |
|     {
 | |
|         m_outer_hasher.update(m_inner_hasher.digest().immutable_data(), m_inner_hasher.digest_size());
 | |
|         auto result = m_outer_hasher.digest();
 | |
|         reset();
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     void reset()
 | |
|     {
 | |
|         m_inner_hasher.reset();
 | |
|         m_outer_hasher.reset();
 | |
|         m_inner_hasher.update(m_key_data, m_inner_hasher.block_size());
 | |
|         m_outer_hasher.update(m_key_data + m_inner_hasher.block_size(), m_outer_hasher.block_size());
 | |
|     }
 | |
| 
 | |
| #ifndef KERNEL
 | |
|     DeprecatedString class_name() const
 | |
|     {
 | |
|         StringBuilder builder;
 | |
|         builder.append("HMAC-"sv);
 | |
|         builder.append(m_inner_hasher.class_name());
 | |
|         return builder.to_deprecated_string();
 | |
|     }
 | |
| #endif
 | |
| 
 | |
| private:
 | |
|     void derive_key(u8 const* key, size_t length)
 | |
|     {
 | |
|         auto block_size = m_inner_hasher.block_size();
 | |
|         // Note: The block size of all the current hash functions is 512 bits.
 | |
|         Vector<u8, 64> v_key;
 | |
|         v_key.resize(block_size);
 | |
|         auto key_buffer = v_key.span();
 | |
|         // m_key_data is zero'd, so copying the data in
 | |
|         // the first few bytes leaves the rest zero, which
 | |
|         // is exactly what we want (zero padding)
 | |
|         if (length > block_size) {
 | |
|             m_inner_hasher.update(key, length);
 | |
|             auto digest = m_inner_hasher.digest();
 | |
|             // FIXME: should we check if the hash function creates more data than its block size?
 | |
|             key_buffer.overwrite(0, digest.immutable_data(), m_inner_hasher.digest_size());
 | |
|         } else {
 | |
|             key_buffer.overwrite(0, key, length);
 | |
|         }
 | |
| 
 | |
|         // fill out the inner and outer padded keys
 | |
|         auto* i_key = m_key_data;
 | |
|         auto* o_key = m_key_data + block_size;
 | |
|         for (size_t i = 0; i < block_size; ++i) {
 | |
|             auto key_byte = key_buffer[i];
 | |
|             i_key[i] = key_byte ^ IPAD;
 | |
|             o_key[i] = key_byte ^ OPAD;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void derive_key(ReadonlyBytes key) { derive_key(key.data(), key.size()); }
 | |
|     void derive_key(StringView key) { derive_key(key.bytes()); }
 | |
| 
 | |
|     HashType m_inner_hasher, m_outer_hasher;
 | |
|     u8 m_key_data[2048];
 | |
| };
 | |
| 
 | |
| }
 | 
