| 
							- /*
 -  * Carla sha1 utils
 -  * Copyright (C) 2023 Filipe Coelho <falktx@falktx.com>
 -  *
 -  * This program is free software; you can redistribute it and/or
 -  * modify it under the terms of the GNU General Public License as
 -  * published by the Free Software Foundation; either version 2 of
 -  * the License, or any later version.
 -  *
 -  * This program is distributed in the hope that it will be useful,
 -  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 -  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 -  * GNU General Public License for more details.
 -  *
 -  * For a full copy of the GNU General Public License see the doc/GPL.txt file.
 -  */
 - 
 - #ifndef CARLA_SHA1_UTILS_HPP_INCLUDED
 - #define CARLA_SHA1_UTILS_HPP_INCLUDED
 - 
 - #include "CarlaUtils.hpp"
 - 
 - #if defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ ==  __ORDER_BIG_ENDIAN__))
 - # define CARLA_SHA1_BIG_ENDIAN
 - #endif
 - 
 - /*!
 -  * Simple, single-use SHA1 class.
 -  * Must be discarded after use.
 -  *
 -  * Based on libcrypt by Wei Dai and other contributors (originally in the public domain)
 -  */
 - class CarlaSha1 {
 -     static constexpr const size_t BLOCK_LENGTH = 64;
 - 
 -     union {
 -         uint8_t u8[BLOCK_LENGTH];
 -         uint32_t u32[BLOCK_LENGTH/sizeof(uint32_t)];
 -     } buffer;
 -     uint32_t state[5];
 -     uint32_t byteCount;
 -     uint8_t bufferOffset;
 -     char resultstr[41];
 - 
 -     static_assert(sizeof(buffer.u8) == sizeof(buffer.u32), "valid size");
 - 
 - public:
 -     /*
 -      * Constructor.
 -      */
 -     CarlaSha1() noexcept
 -         : byteCount(0),
 -           bufferOffset(0)
 -     {
 -         state[0] = 0x67452301;
 -         state[1] = 0xefcdab89;
 -         state[2] = 0x98badcfe;
 -         state[3] = 0x10325476;
 -         state[4] = 0xc3d2e1f0;
 -     }
 - 
 -     /*
 -      * Write a single byte of data.
 -      */
 -     void writeByte(const uint8_t data) noexcept
 -     {
 -         ++byteCount;
 -         _addUncounted(data);
 -     }
 - 
 -     /*
 -      * Write a custom blob of data.
 -      */
 -     void write(const void* const data, size_t len) noexcept
 -     {
 -         const uint8_t* u8data = static_cast<const uint8_t*>(data);
 - 
 -         while (len--)
 -             writeByte(*u8data++);
 -     }
 - 
 -     /*
 -      * Return hash result as byte array (20 characters).
 -      * @note must be called only once!
 -      */
 -     const uint8_t* resultAsHash() noexcept
 -     {
 -         // Pad to complete the last block
 -         _pad();
 - 
 -        #ifndef CARLA_SHA1_BIG_ENDIAN
 -         // Swap byte order back
 -         for (int i=0; i<5; ++i)
 -         {
 -             state[i] = ((state[i] << 24) & 0xff000000)
 -                      | ((state[i] <<  8) & 0x00ff0000)
 -                      | ((state[i] >>  8) & 0x0000ff00)
 -                      | ((state[i] >> 24) & 0x000000ff);
 -         }
 -        #endif
 - 
 -         return static_cast<uint8_t*>(static_cast<void*>(state));
 -     }
 - 
 -     /*
 -      * Return hash result as null-terminated string.
 -      * @note must be called only once!
 -      */
 -     const char* resultAsString() noexcept
 -     {
 -         const uint8_t* const hash = resultAsHash();
 - 
 -         for (int i=0; i<20; ++i)
 -             std::snprintf(resultstr + (i * 2), 3, "%02x", hash[i]);
 - 
 -         resultstr[40] = '\0';
 - 
 -         return resultstr;
 -     }
 - 
 - private:
 -     void _addUncounted(const uint8_t data) noexcept
 -     {
 -        #ifdef CARLA_SHA1_BIG_ENDIAN
 -         buffer.u8[bufferOffset] = data;
 -        #else
 -         buffer.u8[bufferOffset ^ 3] = data;
 -        #endif
 -         if (++bufferOffset == BLOCK_LENGTH)
 -         {
 -             bufferOffset = 0;
 -             _hashBlock();
 -         }
 -     }
 - 
 -     void _hashBlock() noexcept
 -     {
 -         uint32_t a = state[0];
 -         uint32_t b = state[1];
 -         uint32_t c = state[2];
 -         uint32_t d = state[3];
 -         uint32_t e = state[4];
 -         uint32_t t;
 - 
 -         for (uint8_t i=0; i<80; ++i)
 -         {
 -             if (i >= 16)
 -             {
 -                 t = buffer.u32[(i + 13) & 15]
 -                   ^ buffer.u32[(i + 8) & 15] 
 -                   ^ buffer.u32[(i + 2) & 15]
 -                   ^ buffer.u32[i & 15];
 -                 buffer.u32[i & 15] = _rol32(t, 1);
 -             }
 -             if (i < 20)
 -             {
 -                 t = (d ^ (b & (c ^ d))) + 0x5a827999;
 -             }
 -             else if (i < 40)
 -             {
 -                 t = (b ^ c ^ d) + 0x6ed9eba1;
 -             }
 -             else if (i < 60)
 -             {
 -                 t = ((b & c) | (d & (b | c))) + 0x8f1bbcdc;
 -             }
 -             else
 -             {
 -                 t = (b ^ c ^ d) + 0xca62c1d6;
 -             }
 -             t += _rol32(a, 5) + e + buffer.u32[i & 15];
 -             e = d;
 -             d = c;
 -             c = _rol32(b, 30);
 -             b = a;
 -             a = t;
 -         }
 - 
 -         state[0] += a;
 -         state[1] += b;
 -         state[2] += c;
 -         state[3] += d;
 -         state[4] += e;
 -     }
 - 
 -     // Implement SHA-1 padding (fips180-2 ยง5.1.1)
 -     void _pad() noexcept
 -     {
 -         // Pad with 0x80 followed by 0x00 until the end of the block
 -         _addUncounted(0x80);
 -         while (bufferOffset != 56) _addUncounted(0x00);
 - 
 -         // Append length in the last 8 bytes
 -         _addUncounted(0); // We're only using 32 bit lengths
 -         _addUncounted(0); // But SHA-1 supports 64 bit lengths
 -         _addUncounted(0); // So zero pad the top bits
 -         _addUncounted(byteCount >> 29); // Shifting to multiply by 8
 -         _addUncounted(byteCount >> 21); // as SHA-1 supports bitstreams as well as
 -         _addUncounted(byteCount >> 13); // byte.
 -         _addUncounted(byteCount >> 5);
 -         _addUncounted(byteCount << 3);
 -     }
 - 
 -     static uint32_t _rol32(const uint32_t number, const uint8_t bits) noexcept
 -     {
 -         return (number << bits) | (number >> (32 - bits));
 -     }
 - };
 - 
 - #endif // CARLA_SHA1_UTILS_HPP_INCLUDED
 
 
  |