1+ #include < cassert>
12#include < cstring>
23#include < algorithm>
34#include < filesystem>
@@ -13,7 +14,7 @@ namespace fs = std::filesystem;
1314namespace http
1415{
1516
16- // ---------------------------------------------------push_back -------------------------------------------------------------
17+ // ----------------------------------------------------------------------------------------------------------------
1718
1819 const auto BOOST_ASIO_VERSION_STRING = []() -> std::string
1920 {
@@ -585,6 +586,160 @@ namespace http
585586 return " application/text" ;
586587 }
587588
589+ // ----------------------------------------------------------------------------------------------------------------
590+
591+
592+ static constexpr uint32_t rotl (uint32_t x, size_t s)
593+ {
594+ return (x << s) | (x >> (32 - s));
595+ }
596+
597+ static constexpr uint32_t f1 (uint32_t b, uint32_t c, uint32_t d)
598+ {
599+ return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d);
600+ }
601+
602+ static constexpr uint32_t f2 (uint32_t b, uint32_t c, uint32_t d)
603+ {
604+ return b ^ c ^ d;
605+ }
606+
607+ static constexpr uint32_t f3 (uint32_t b, uint32_t c, uint32_t d)
608+ {
609+ return (b & c) | (b & d) | (c & d);
610+ }
611+
612+ const auto process_sha1_block = [](auto & hash, const auto & block, auto & words)
613+ {
614+ // Initialise buffer
615+ for (size_t i = 0 ; i < 16 ; ++i)
616+ {
617+ std::memcpy (&words[i], &block[i*4 ], 4 );
618+ words[i] = htobe32 (words[i]);
619+ }
620+
621+ for (size_t i = 16 ; i < 80 ; ++i)
622+ words[i] = rotl (words[i-3 ] ^ words[i-8 ] ^ words[i-14 ] ^ words[i-16 ], 1 );
623+
624+ // Initialize
625+ uint32_t a = hash[0 ];
626+ uint32_t b = hash[1 ];
627+ uint32_t c = hash[2 ];
628+ uint32_t d = hash[3 ];
629+ uint32_t e = hash[4 ];
630+
631+ // first round
632+ for (size_t i = 0 ; i < 4 ; ++i)
633+ {
634+ const size_t offset = 5 *i;
635+ e += rotl (a,5 ) + f1 (b,c,d) + words[offset ] + 0x5a827999 ; b = rotl (b,30 );
636+ d += rotl (e,5 ) + f1 (a,b,c) + words[offset+1 ] + 0x5a827999 ; a = rotl (a,30 );
637+ c += rotl (d,5 ) + f1 (e,a,b) + words[offset+2 ] + 0x5a827999 ; e = rotl (e,30 );
638+ b += rotl (c,5 ) + f1 (d,e,a) + words[offset+3 ] + 0x5a827999 ; d = rotl (d,30 );
639+ a += rotl (b,5 ) + f1 (c,d,e) + words[offset+4 ] + 0x5a827999 ; c = rotl (c,30 );
640+ }
641+
642+ // second round
643+ for (size_t i = 4 ; i < 8 ; ++i)
644+ {
645+ const size_t offset = 5 *i;
646+ e += rotl (a,5 ) + f2 (b,c,d) + words[offset ] + 0x6ed9eba1 ; b = rotl (b,30 );
647+ d += rotl (e,5 ) + f2 (a,b,c) + words[offset+1 ] + 0x6ed9eba1 ; a = rotl (a,30 );
648+ c += rotl (d,5 ) + f2 (e,a,b) + words[offset+2 ] + 0x6ed9eba1 ; e = rotl (e,30 );
649+ b += rotl (c,5 ) + f2 (d,e,a) + words[offset+3 ] + 0x6ed9eba1 ; d = rotl (d,30 );
650+ a += rotl (b,5 ) + f2 (c,d,e) + words[offset+4 ] + 0x6ed9eba1 ; c = rotl (c,30 );
651+ }
652+
653+ // third round
654+ for (size_t i = 8 ; i < 12 ; ++i)
655+ {
656+ const size_t offset = 5 *i;
657+ e += rotl (a,5 ) + f3 (b,c,d) + words[offset ] + 0x8f1bbcdc ; b = rotl (b,30 );
658+ d += rotl (e,5 ) + f3 (a,b,c) + words[offset+1 ] + 0x8f1bbcdc ; a = rotl (a,30 );
659+ c += rotl (d,5 ) + f3 (e,a,b) + words[offset+2 ] + 0x8f1bbcdc ; e = rotl (e,30 );
660+ b += rotl (c,5 ) + f3 (d,e,a) + words[offset+3 ] + 0x8f1bbcdc ; d = rotl (d,30 );
661+ a += rotl (b,5 ) + f3 (c,d,e) + words[offset+4 ] + 0x8f1bbcdc ; c = rotl (c,30 );
662+ }
663+
664+ // fourth round
665+ for (size_t i = 12 ; i < 16 ; ++i)
666+ {
667+ const size_t offset = 5 *i;
668+ e += rotl (a,5 ) + f2 (b,c,d) + words[offset ] + 0xca62c1d6 ; b = rotl (b,30 );
669+ d += rotl (e,5 ) + f2 (a,b,c) + words[offset+1 ] + 0xca62c1d6 ; a = rotl (a,30 );
670+ c += rotl (d,5 ) + f2 (e,a,b) + words[offset+2 ] + 0xca62c1d6 ; e = rotl (e,30 );
671+ b += rotl (c,5 ) + f2 (d,e,a) + words[offset+3 ] + 0xca62c1d6 ; d = rotl (d,30 );
672+ a += rotl (b,5 ) + f2 (c,d,e) + words[offset+4 ] + 0xca62c1d6 ; c = rotl (c,30 );
673+ }
674+
675+ // update hash
676+ hash[0 ] += a;
677+ hash[1 ] += b;
678+ hash[2 ] += c;
679+ hash[3 ] += d;
680+ hash[4 ] += e;
681+ };
682+
683+ sha1& sha1::push (size_t ndata, const uint8_t * data)
684+ {
685+ for (size_t i = 0 ; i < ndata ; ++i)
686+ {
687+ block[off] = data[i];
688+ ++off;
689+ ++total;
690+
691+ if (off == std::size (block))
692+ {
693+ off = 0 ;
694+ process_sha1_block (hash, block, words);
695+ }
696+ }
697+
698+ return *this ;
699+ }
700+
701+ sha1::digest sha1::finish ()
702+ {
703+ // number of bits
704+ const uint64_t ml = htobe64 (total*8 );
705+
706+ // Add 0x80
707+ block[off++] = 0x80 ;
708+ if (off == std::size (block))
709+ {
710+ off = 0 ;
711+ process_sha1_block (hash, block, words);
712+ }
713+
714+ // Add remaining 0 bits
715+ const size_t end = off <= 56 ? 56 : 56 + 64 ;
716+ for (size_t i = off ; i < end ; ++i)
717+ {
718+ block[off++] = 0 ;
719+ if (off == std::size (block))
720+ {
721+ off = 0 ;
722+ process_sha1_block (hash, block, words);
723+ }
724+ }
725+ assert (off == 56 );
726+
727+ // Add message length
728+ uint8_t tmp[8 ];
729+ memcpy (tmp, &ml, 8 );
730+ for (size_t i = 0 ; i < 8 ; ++i)
731+ block[off++] = tmp[i];
732+ assert (off == std::size (block));
733+ process_sha1_block (hash, block, words);
734+
735+ // Get final hash
736+ sha1::digest h;
737+ for (size_t i = 0 ; i < std::size (hash) ; ++i)
738+ hash[i] = htobe32 (hash[i]);
739+ std::memcpy (&h[0 ], &hash[0 ], h.size ());
740+ return h;
741+ }
742+
588743// ----------------------------------------------------------------------------------------------------------------
589744
590745 std::string base64_encode (std::string_view data)
0 commit comments