blob: 32e8566e81216a53514c9ce6a9f9b6b031ef0fc5 [file] [log] [blame]
// Copyright 2021 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_crypto/sha256.h"
#include <cstring>
#include "gtest/gtest.h"
#include "pw_stream/memory_stream.h"
namespace pw::crypto::sha256 {
namespace {
#define ASSERT_OK(expr) ASSERT_EQ(OkStatus(), expr)
#define ASSERT_FAIL(expr) ASSERT_NE(OkStatus(), expr)
#define AS_BYTES(s) std::as_bytes(std::span(s, sizeof(s) - 1))
// Generated in Python 3 with:
// `hashlib.sha256('Hello, Pigweed!'.encode('ascii')).hexdigest()`.
#define SHA256_HASH_OF_HELLO_PIGWEED \
"\x8d\xce\x14\xee\x2c\xd9\xfd\x9b\xbd\x8c\x8d\x57\x68\x50\x2c\x2f" \
"\xfb\xb3\x52\x36\xce\x93\x47\x1b\x80\xfc\xa4\x7d\xb5\xf8\x41\x9d"
// Generated in Python with `hashlib.sha256().hexdigest()`.
#define SHA256_HASH_OF_EMPTY_STRING \
"\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24" \
"\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55"
TEST(Hash, ComputesCorrectDigest) {
std::byte digest[kDigestSizeBytes];
ASSERT_OK(Hash(AS_BYTES("Hello, Pigweed!"), digest));
ASSERT_EQ(0,
std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest)));
}
TEST(Hash, ComputesCorrectDigestFromReader) {
std::byte digest[kDigestSizeBytes];
ConstByteSpan message = AS_BYTES("Hello, Pigweed!");
stream::MemoryReader reader(message);
ASSERT_OK(Hash(reader, digest));
ASSERT_EQ(0,
std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest)));
}
TEST(Hash, ComputesCorrectDigestOnEmptyMessage) {
std::byte digest[kDigestSizeBytes];
ASSERT_OK(Hash({}, digest));
ASSERT_EQ(0,
std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
}
TEST(Hash, ComputesCorrectDigestOnEmptyMessageFromReader) {
std::byte digest[kDigestSizeBytes];
ConstByteSpan empty;
stream::MemoryReader reader(empty);
ASSERT_OK(Hash(reader, digest));
ASSERT_EQ(0,
std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
}
TEST(Hash, DigestBufferTooSmall) {
std::array<std::byte, 31> digest = {};
ASSERT_FAIL(Hash({}, digest));
}
TEST(Hash, DigestBufferTooSmallForReaderBasedAPI) {
std::array<std::byte, 31> digest = {};
ConstByteSpan empty;
stream::MemoryReader reader(empty);
ASSERT_FAIL(Hash(reader, digest));
}
TEST(Hash, AcceptsLargerDigestBuffer) {
std::array<std::byte, 33> digest = {};
ASSERT_OK(Hash({}, digest));
}
TEST(Hash, AcceptsLargerDigestBufferForReaderBasedAPI) {
std::array<std::byte, 33> digest = {};
ConstByteSpan empty;
stream::MemoryReader reader(empty);
ASSERT_OK(Hash(reader, digest));
}
TEST(Sha256, AllowsSkippedUpdate) {
std::byte digest[kDigestSizeBytes];
ASSERT_OK(Sha256().Final(digest));
ASSERT_EQ(0,
std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
}
TEST(Sha256, AllowsEmptyUpdate) {
std::byte digest[kDigestSizeBytes];
ASSERT_OK(Sha256().Update({}).Final(digest));
ASSERT_EQ(0,
std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
}
TEST(Sha256, AllowsMultipleUpdates) {
std::byte digest[kDigestSizeBytes];
ASSERT_OK(Sha256()
.Update(AS_BYTES("Hello, "))
.Update(AS_BYTES("Pigweed!"))
.Final(digest));
ASSERT_EQ(0,
std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest)));
}
TEST(Sha256, NoFinalAfterFinal) {
std::byte digest[kDigestSizeBytes];
auto h = Sha256();
ASSERT_OK(h.Final(digest));
ASSERT_FAIL(h.Final(digest));
}
TEST(Sha256, NoUpdateAfterFinal) {
std::byte digest[kDigestSizeBytes];
auto h = Sha256();
ASSERT_OK(h.Final(digest));
ASSERT_FAIL(h.Update(AS_BYTES("blah")).Final(digest));
}
} // namespace
} // namespace pw::crypto::sha256