summaryrefslogtreecommitdiffstats
path: root/libqpdf/Pl_SHA2.cc
blob: 17eff7e34215e2b4196e34a7ad46f5617a657ccd (plain) (blame)
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <qpdf/Pl_SHA2.hh>
#include <stdexcept>
#include <cstdio>
#include <qpdf/PointerHolder.hh>
#include <qpdf/QUtil.hh>

Pl_SHA2::Pl_SHA2(int bits, Pipeline* next) :
    Pipeline("sha2", next),
    in_progress(false),
    bits(0)
{
    if (bits)
    {
        resetBits(bits);
    }
}

Pl_SHA2::~Pl_SHA2()
{
}

void
Pl_SHA2::badBits()
{
    throw std::logic_error("Pl_SHA2 has unexpected value for bits");
}

void
Pl_SHA2::write(unsigned char* buf, size_t len)
{
    if (! this->in_progress)
    {
        switch (bits)
        {
          case 256:
            sph_sha256_init(&this->ctx256);
            break;
          case 384:
            sph_sha384_init(&this->ctx384);
            break;
          case 512:
            sph_sha512_init(&this->ctx512);
            break;
          default:
            badBits();
            break;
        }
	this->in_progress = true;
    }

    // Write in chunks in case len is too big to fit in an int.
    // Assume int is at least 32 bits.
    static size_t const max_bytes = 1 << 30;
    size_t bytes_left = len;
    unsigned char* data = buf;
    while (bytes_left > 0)
    {
	size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);
        switch (bits)
        {
          case 256:
            sph_sha256(&this->ctx256, data, bytes);
            break;
          case 384:
            sph_sha384(&this->ctx384, data, bytes);
            break;
          case 512:
            sph_sha512(&this->ctx512, data, bytes);
            break;
          default:
            badBits();
            break;
        }
	bytes_left -= bytes;
        data += bytes;
    }

    if (this->getNext(true))
    {
        this->getNext()->write(buf, len);
    }
}

void
Pl_SHA2::finish()
{
    if (this->getNext(true))
    {
        this->getNext()->finish();
    }
    switch (bits)
    {
      case 256:
        sph_sha256_close(&this->ctx256, sha256sum);
        break;
      case 384:
        sph_sha384_close(&this->ctx384, sha384sum);
        break;
      case 512:
        sph_sha512_close(&this->ctx512, sha512sum);
        break;
      default:
        badBits();
        break;
    }
    this->in_progress = false;
}

void
Pl_SHA2::resetBits(int bits)
{
    if (this->in_progress)
    {
	throw std::logic_error(
	    "bit reset requested for in-progress SHA2 Pipeline");
    }
    if (! ((bits == 256) || (bits == 384) || (bits == 512)))
    {
	throw std::logic_error("Pl_SHA2 called with bits != 256, 384, or 512");
    }
    this->bits = bits;
}

std::string
Pl_SHA2::getRawDigest()
{
    std::string result;
    switch (bits)
    {
      case 256:
        result = std::string(reinterpret_cast<char*>(this->sha256sum),
                             sizeof(this->sha256sum));
        break;
      case 384:
        result = std::string(reinterpret_cast<char*>(this->sha384sum),
                             sizeof(this->sha384sum));
        break;
      case 512:
        result = std::string(reinterpret_cast<char*>(this->sha512sum),
                             sizeof(this->sha512sum));
        break;
      default:
        badBits();
        break;
    }
    return result;
}

std::string
Pl_SHA2::getHexDigest()
{
    if (this->in_progress)
    {
	throw std::logic_error(
	    "digest requested for in-progress SHA2 Pipeline");
    }
    return QUtil::hex_encode(getRawDigest());
}