aboutsummaryrefslogtreecommitdiff
path: root/libbutl/sha1.cxx
blob: f4a6bad0d2b60aa2bca06bba916cffe8f9cd62d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// file      : libbutl/sha1.cxx -*- C++ -*-
// license   : MIT; see accompanying LICENSE file

#ifndef __cpp_modules_ts
#include <libbutl/sha1.mxx>
#endif

// C interface for sha1c.
//
#include <stdint.h>
#include <stddef.h> // size_t

struct sha1_ctxt {
  union {
    uint8_t b8[20];
    uint32_t b32[5];
  } h;
  union {
    uint8_t b8[8];
    uint64_t b64[1];
  } c;
  union {
    uint8_t b8[64];
    uint32_t b32[16];
  } m;
  uint8_t count;
};
typedef struct sha1_ctxt SHA1_CTX;

extern "C"
{
  static void sha1_init(struct sha1_ctxt *);
  static void sha1_pad(struct sha1_ctxt *);
  static void sha1_loop(struct sha1_ctxt *, const uint8_t *, size_t);
  static void sha1_result(struct sha1_ctxt *, char[20]);

#include "sha1.c"
}

#define SHA1_Init(x)         sha1_init((x))
#define SHA1_Update(x, y, z) sha1_loop((x), (const uint8_t *)(y), (z))
#define SHA1_Final(x, y)     sha1_result((y), (char(&)[20])(x))

#include <cassert>

#ifndef __cpp_lib_modules_ts
#include <string>
#include <cstddef>
#include <cstdint>

#include <istream>
#endif

// Other includes.

#ifdef __cpp_modules_ts
module butl.sha1;

// Only imports additional to interface.
#ifdef __clang__
#ifdef __cpp_lib_modules_ts
import std.core;
#endif
#endif
#else
#include <libbutl/bufstreambuf.hxx>
#endif

using namespace std;

namespace butl
{
  void sha1::
  reset ()
  {
    SHA1_Init (reinterpret_cast<SHA1_CTX*> (buf_));
    done_ = false;
    empty_ = true;
  }

  void sha1::
  append (const void* b, size_t n)
  {
    if (n != 0)
    {
      SHA1_Update (reinterpret_cast<SHA1_CTX*> (buf_), b, n);

      if (empty_)
        empty_ = false;
    }
  }

  void sha1::
  append (istream& is)
  {
    bufstreambuf* buf (dynamic_cast<bufstreambuf*> (is.rdbuf ()));
    assert (buf != nullptr);

    while (is.peek () != istream::traits_type::eof () && is.good ())
    {
      size_t n (buf->egptr () - buf->gptr ());
      append (buf->gptr (), n);
      buf->gbump (static_cast<int> (n));
    }
  }

  const sha1::digest_type& sha1::
  binary () const
  {
    if (!done_)
    {
      SHA1_Final (bin_, reinterpret_cast<SHA1_CTX*> (buf_));
      done_ = true;
      buf_[0] = '\0'; // Indicate we haven't computed the string yet.
    }

    return bin_;
  }

  static const char hex_map[16] = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    'a', 'b', 'c', 'd', 'e', 'f'};

  const char* sha1::
  string () const
  {
    if (!done_)
      binary ();

    if (buf_[0] == '\0')
    {
      for (size_t i (0); i != 20; ++i)
      {
        buf_[i * 2]     = hex_map[bin_[i] >> 4];
        buf_[i * 2 + 1] = hex_map[bin_[i] & 0x0f];
      }

      buf_[40] = '\0';
    }

    return buf_;
  }
}