Pigweed
 
Loading...
Searching...
No Matches
sha256.h
1// Copyright 2021 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15#pragma once
16
17#include <cstdint>
18
19#include "pw_bytes/span.h"
20#include "pw_crypto/sha256_backend.h"
21#include "pw_log/log.h"
22#include "pw_status/status.h"
23#include "pw_status/try.h"
24#include "pw_stream/stream.h"
25
26namespace pw::crypto::sha256 {
27
29inline constexpr uint32_t kDigestSizeBytes = 32;
30
32enum class Sha256State {
34 kReady = 1,
35
38 kFinalized = 2,
39
41 kError = 3,
42};
43
44namespace backend {
45
46// Primitive operations to be implemented by backends.
47Status DoInit(NativeSha256Context& ctx);
48Status DoUpdate(NativeSha256Context& ctx, ConstByteSpan data);
49Status DoFinal(NativeSha256Context& ctx, ByteSpan out_digest);
50
51} // namespace backend
52
63class Sha256 {
64 public:
65 Sha256() {
66 if (!backend::DoInit(native_ctx_).ok()) {
67 PW_LOG_DEBUG("backend::DoInit() failed");
68 state_ = Sha256State::kError;
69 return;
70 }
71
72 state_ = Sha256State::kReady;
73 }
74
77 Sha256& Update(ConstByteSpan data) {
78 if (state_ != Sha256State::kReady) {
79 PW_LOG_DEBUG("The backend is not ready/initialized");
80 return *this;
81 }
82
83 if (!backend::DoUpdate(native_ctx_, data).ok()) {
84 PW_LOG_DEBUG("backend::DoUpdate() failed");
85 state_ = Sha256State::kError;
86 return *this;
87 }
88
89 return *this;
90 }
91
100 Status Final(ByteSpan out_digest) {
101 if (out_digest.size() < kDigestSizeBytes) {
102 PW_LOG_DEBUG("Digest output buffer is too small");
103 state_ = Sha256State::kError;
104 return Status::InvalidArgument();
105 }
106
107 if (state_ != Sha256State::kReady) {
108 PW_LOG_DEBUG("The backend is not ready/initialized");
109 return Status::FailedPrecondition();
110 }
111
112 auto status = backend::DoFinal(native_ctx_, out_digest);
113 if (!status.ok()) {
114 PW_LOG_DEBUG("backend::DoFinal() failed");
115 state_ = Sha256State::kError;
116 return status;
117 }
118
119 state_ = Sha256State::kFinalized;
120 return OkStatus();
121 }
122
123 private:
124 // Common hasher state. Tracked by the front-end.
125 Sha256State state_;
126 // Backend-specific context.
127 backend::NativeSha256Context native_ctx_;
128};
129
162inline Status Hash(ConstByteSpan message, ByteSpan out_digest) {
163 return Sha256().Update(message).Final(out_digest);
164}
165
166inline Status Hash(stream::Reader& reader, ByteSpan out_digest) {
167 if (out_digest.size() < kDigestSizeBytes) {
168 return Status::InvalidArgument();
169 }
170
171 Sha256 sha256;
172 while (true) {
173 Result<ByteSpan> res = reader.Read(out_digest);
174 if (res.status().IsOutOfRange()) {
175 break;
176 }
177
178 PW_TRY(res.status());
179 sha256.Update(res.value());
180 }
181
182 return sha256.Final(out_digest);
183}
184
185} // namespace pw::crypto::sha256
Definition: status.h:85
constexpr void Update(Status other)
Definition: status.h:213
Definition: sha256.h:63
Status Final(ByteSpan out_digest)
Definition: sha256.h:100
Sha256 & Update(ConstByteSpan data)
Definition: sha256.h:77
Definition: stream.h:345
Result< ByteSpan > Read(ByteSpan dest)
Definition: stream.h:120
constexpr Status OkStatus()
Definition: status.h:234