From de741592970fc175eba0ce41f0228e0e4170f903 Mon Sep 17 00:00:00 2001 From: Emerson Knapp Date: Mon, 23 Jan 2023 23:24:13 -0800 Subject: [PATCH 01/10] Add sha256 utility implementation. needs tests and docs Signed-off-by: Emerson Knapp --- CMakeLists.txt | 1 + include/rcutils/sha256.h | 95 ++++++++++++++++++++++ src/sha256.c | 169 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 include/rcutils/sha256.h create mode 100644 src/sha256.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 97304d5b..ab523c0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ set(rcutils_sources src/process.c src/qsort.c src/repl_str.c + src/sha256.c src/shared_library.c src/snprintf.c src/split.c diff --git a/include/rcutils/sha256.h b/include/rcutils/sha256.h new file mode 100644 index 00000000..dc441e04 --- /dev/null +++ b/include/rcutils/sha256.h @@ -0,0 +1,95 @@ +// Copyright 2023 Open Source Robotics Foundation, Inc. +// +// 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 +// +// http://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. + +/// \file Provides a simple SHA256 algorithm for hashing. +/// This implementation makes no security guarantees, its use case +/// is for non-sensitive comparison of message digests +/// Implementation originally copied from Brad Conte +/// https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c + +#ifndef RCUTILS__SHA256_H_ +#define RCUTILS__SHA256_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "rcutils/macros.h" +#include "rcutils/types/rcutils_ret.h" +#include "rcutils/visibility_control.h" + +#define RCUTILS_SHA256_BLOCK_SIZE 32 + +typedef struct { + uint8_t data[64]; + uint32_t datalen; + uint64_t bitlen; + uint32_t state[8]; +} rcutils_sha256_ctx_t; + +/// Simple SHA256 implementation +/********************************************************************* +* Filename: sha256.c +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Implementation of the SHA-256 hashing algorithm. + SHA-256 is one of the three algorithms in the SHA2 + specification. The others, SHA-384 and SHA-512, are not + offered in this implementation. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. +*********************************************************************/ + + +/** + * + * + * \param[inout] ctx + * \return rcutils_ret_t + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +rcutils_ret_t rcutils_sha256_init(rcutils_sha256_ctx_t * ctx); + +/** + * + * + * \param ctx + * \param data + * \param len + * \return rcutils_ret_t + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +rcutils_ret_t rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t data[], size_t len); + +/** + * + * + * \param ctx + * \param hash + * \return rcutils_ret_t + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +rcutils_ret_t sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[]); + +#ifdef __cplusplus +} +#endif + +#endif // RCUTILS__QSORT_H_ diff --git a/src/sha256.c b/src/sha256.c new file mode 100644 index 00000000..20b59cb1 --- /dev/null +++ b/src/sha256.c @@ -0,0 +1,169 @@ +// Copyright 2023 Open Source Robotics Foundation, Inc. +// +// 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 +// +// http://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. + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#include "rcutils/sha256.h" + +#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) +#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + +#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) +#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) +#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) + +static const uint32_t k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +void sha256_transform(rcutils_sha256_ctx_t * ctx, const uint8_t data[]) +{ + uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + for ( ; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +rcutils_ret_t rcutils_sha256_init(rcutils_sha256_ctx_t * ctx) +{ + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; + + return RCUTILS_RET_OK; +} + +rcutils_ret_t rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t data[], size_t len) +{ + uint32_t i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } + + return RCUTILS_RET_OK; +} + +rcutils_ret_t rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[]) +{ + uint32_t i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) + ctx->data[i++] = 0x00; + } + else { + ctx->data[i++] = 0x80; + while (i < 64) + ctx->data[i++] = 0x00; + sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + ctx->bitlen += ctx->datalen * 8; + ctx->data[63] = (uint8_t)(ctx->bitlen); + ctx->data[62] = (uint8_t)(ctx->bitlen >> 8); + ctx->data[61] = (uint8_t)(ctx->bitlen >> 16); + ctx->data[60] = (uint8_t)(ctx->bitlen >> 24); + ctx->data[59] = (uint8_t)(ctx->bitlen >> 32); + ctx->data[58] = (uint8_t)(ctx->bitlen >> 40); + ctx->data[57] = (uint8_t)(ctx->bitlen >> 48); + ctx->data[56] = (uint8_t)(ctx->bitlen >> 56); + sha256_transform(ctx, ctx->data); + + // Since this implementation uses little endian byte ordering and SHA uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } + + return RCUTILS_RET_OK; +} + +#ifdef __cplusplus +} +#endif From 8a73b71e1e3b83396fd1322a3b42a2fb6c84a085 Mon Sep 17 00:00:00 2001 From: Emerson Knapp Date: Tue, 24 Jan 2023 12:18:31 -0800 Subject: [PATCH 02/10] Code style updates Signed-off-by: Emerson Knapp --- include/rcutils/sha256.h | 13 +- src/sha256.c | 283 +++++++++++++++++++++------------------ 2 files changed, 158 insertions(+), 138 deletions(-) diff --git a/include/rcutils/sha256.h b/include/rcutils/sha256.h index dc441e04..e3bfea51 100644 --- a/include/rcutils/sha256.h +++ b/include/rcutils/sha256.h @@ -32,11 +32,12 @@ extern "C" #define RCUTILS_SHA256_BLOCK_SIZE 32 -typedef struct { - uint8_t data[64]; - uint32_t datalen; - uint64_t bitlen; - uint32_t state[8]; +typedef struct +{ + uint8_t data[64]; + uint32_t datalen; + uint64_t bitlen; + uint32_t state[8]; } rcutils_sha256_ctx_t; /// Simple SHA256 implementation @@ -92,4 +93,4 @@ rcutils_ret_t sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[]); } #endif -#endif // RCUTILS__QSORT_H_ +#endif // RCUTILS__SHA256_H_ diff --git a/src/sha256.c b/src/sha256.c index 20b59cb1..8aa141f2 100644 --- a/src/sha256.c +++ b/src/sha256.c @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://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, @@ -12,158 +12,177 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifdef __cplusplus -extern "C" -{ -#endif - #include #include "rcutils/sha256.h" -#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) -#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) +static inline uint32_t rotright(uint32_t value, uint8_t bits) +{ + return (value >> bits) | (value << (32 - bits)); +} + +static inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z) +{ + return (x & y) ^ (~x & z); +} + +static inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z) +{ + return (x & y) ^ (x & z) ^ (y & z); +} -#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) -#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) -#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) -#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) -#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) -#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) +static inline uint32_t ep0(uint32_t x) +{ + return rotright(x, 2) ^ rotright(x, 13) ^ rotright(x, 22); +} + +static inline uint32_t ep1(uint32_t x) +{ + return rotright(x, 6) ^ rotright(x, 11) ^ rotright(x, 25); +} + +static inline uint32_t sig0(uint32_t x) +{ + return rotright(x, 7) ^ rotright(x, 18) ^ (x >> 3); +} + +static inline uint32_t sig1(uint32_t x) +{ + return rotright(x, 17) ^ rotright(x, 19) ^ (x >> 10); +} static const uint32_t k[64] = { - 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, - 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, - 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, - 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, - 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, - 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, - 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, - 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; void sha256_transform(rcutils_sha256_ctx_t * ctx, const uint8_t data[]) { - uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; - - for (i = 0, j = 0; i < 16; ++i, j += 4) - m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); - for ( ; i < 64; ++i) - m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; - - a = ctx->state[0]; - b = ctx->state[1]; - c = ctx->state[2]; - d = ctx->state[3]; - e = ctx->state[4]; - f = ctx->state[5]; - g = ctx->state[6]; - h = ctx->state[7]; - - for (i = 0; i < 64; ++i) { - t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; - t2 = EP0(a) + MAJ(a,b,c); - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - ctx->state[0] += a; - ctx->state[1] += b; - ctx->state[2] += c; - ctx->state[3] += d; - ctx->state[4] += e; - ctx->state[5] += f; - ctx->state[6] += g; - ctx->state[7] += h; + uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) { + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + } + for ( ; i < 64; ++i) { + m[i] = sig1(m[i - 2]) + m[i - 7] + sig0(m[i - 15]) + m[i - 16]; + } + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + ep1(e) + ch(e, f, g) + k[i] + m[i]; + t2 = ep0(a) + maj(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; } rcutils_ret_t rcutils_sha256_init(rcutils_sha256_ctx_t * ctx) { - ctx->datalen = 0; - ctx->bitlen = 0; - ctx->state[0] = 0x6a09e667; - ctx->state[1] = 0xbb67ae85; - ctx->state[2] = 0x3c6ef372; - ctx->state[3] = 0xa54ff53a; - ctx->state[4] = 0x510e527f; - ctx->state[5] = 0x9b05688c; - ctx->state[6] = 0x1f83d9ab; - ctx->state[7] = 0x5be0cd19; - - return RCUTILS_RET_OK; + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; + + return RCUTILS_RET_OK; } rcutils_ret_t rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t data[], size_t len) { - uint32_t i; - - for (i = 0; i < len; ++i) { - ctx->data[ctx->datalen] = data[i]; - ctx->datalen++; - if (ctx->datalen == 64) { - sha256_transform(ctx, ctx->data); - ctx->bitlen += 512; - ctx->datalen = 0; - } - } - - return RCUTILS_RET_OK; + uint32_t i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } + + return RCUTILS_RET_OK; } rcutils_ret_t rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[]) { - uint32_t i; - - i = ctx->datalen; - - // Pad whatever data is left in the buffer. - if (ctx->datalen < 56) { - ctx->data[i++] = 0x80; - while (i < 56) - ctx->data[i++] = 0x00; - } - else { - ctx->data[i++] = 0x80; - while (i < 64) - ctx->data[i++] = 0x00; - sha256_transform(ctx, ctx->data); - memset(ctx->data, 0, 56); - } - - // Append to the padding the total message's length in bits and transform. - ctx->bitlen += ctx->datalen * 8; - ctx->data[63] = (uint8_t)(ctx->bitlen); - ctx->data[62] = (uint8_t)(ctx->bitlen >> 8); - ctx->data[61] = (uint8_t)(ctx->bitlen >> 16); - ctx->data[60] = (uint8_t)(ctx->bitlen >> 24); - ctx->data[59] = (uint8_t)(ctx->bitlen >> 32); - ctx->data[58] = (uint8_t)(ctx->bitlen >> 40); - ctx->data[57] = (uint8_t)(ctx->bitlen >> 48); - ctx->data[56] = (uint8_t)(ctx->bitlen >> 56); - sha256_transform(ctx, ctx->data); - - // Since this implementation uses little endian byte ordering and SHA uses big endian, - // reverse all the bytes when copying the final state to the output hash. - for (i = 0; i < 4; ++i) { - hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; - hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; - hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; - hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; - hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; - hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; - hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; - hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; - } - - return RCUTILS_RET_OK; -} - -#ifdef __cplusplus + uint32_t i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) { + ctx->data[i++] = 0x00; + } + } else { + ctx->data[i++] = 0x80; + while (i < 64) { + ctx->data[i++] = 0x00; + } + sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + ctx->bitlen += ctx->datalen * 8; + ctx->data[63] = (uint8_t)(ctx->bitlen); + ctx->data[62] = (uint8_t)(ctx->bitlen >> 8); + ctx->data[61] = (uint8_t)(ctx->bitlen >> 16); + ctx->data[60] = (uint8_t)(ctx->bitlen >> 24); + ctx->data[59] = (uint8_t)(ctx->bitlen >> 32); + ctx->data[58] = (uint8_t)(ctx->bitlen >> 40); + ctx->data[57] = (uint8_t)(ctx->bitlen >> 48); + ctx->data[56] = (uint8_t)(ctx->bitlen >> 56); + sha256_transform(ctx, ctx->data); + + // Since this implementation uses little endian byte ordering and SHA uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i = 0; i < 4; ++i) { + hash[i + 0] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } + + return RCUTILS_RET_OK; } -#endif From 471955f77fb466fe2638bd0ca259a8902e968c3c Mon Sep 17 00:00:00 2001 From: Emerson Knapp Date: Tue, 24 Jan 2023 14:51:38 -0800 Subject: [PATCH 03/10] Starting to add tests Signed-off-by: Emerson Knapp --- CMakeLists.txt | 7 ++++ include/rcutils/sha256.h | 54 +++++++++++++++---------------- src/sha256.c | 22 ++++--------- test/test_sha256.cpp | 69 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 44 deletions(-) create mode 100644 test/test_sha256.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ab523c0d..35d4df0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -363,6 +363,13 @@ if(BUILD_TESTING) target_link_libraries(test_repl_str ${PROJECT_NAME}) endif() + ament_add_gtest(test_sha256 + test/test_sha256.cpp + ) + if(TARGET test_sha256) + target_link_libraries(test_sha256 ${PROJECT_NAME}) + endif() + macro(add_dummy_shared_library target) add_library(${target} test/dummy_shared_library/dummy_shared_library.c) if(WIN32) diff --git a/include/rcutils/sha256.h b/include/rcutils/sha256.h index e3bfea51..5c63d32c 100644 --- a/include/rcutils/sha256.h +++ b/include/rcutils/sha256.h @@ -18,6 +18,21 @@ /// Implementation originally copied from Brad Conte /// https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c +/// Simple SHA256 implementation +/********************************************************************* +* Filename: sha256.c +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Implementation of the SHA-256 hashing algorithm. + SHA-256 is one of the three algorithms in the SHA2 + specification. The others, SHA-384 and SHA-512, are not + offered in this implementation. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. +*********************************************************************/ + #ifndef RCUTILS__SHA256_H_ #define RCUTILS__SHA256_H_ @@ -34,37 +49,20 @@ extern "C" typedef struct { - uint8_t data[64]; - uint32_t datalen; - uint64_t bitlen; - uint32_t state[8]; + unsigned char data[64]; + unsigned int datalen; + unsigned long long bitlen; + unsigned int state[8]; } rcutils_sha256_ctx_t; -/// Simple SHA256 implementation -/********************************************************************* -* Filename: sha256.c -* Author: Brad Conte (brad AT bradconte.com) -* Copyright: -* Disclaimer: This code is presented "as is" without any guarantees. -* Details: Implementation of the SHA-256 hashing algorithm. - SHA-256 is one of the three algorithms in the SHA2 - specification. The others, SHA-384 and SHA-512, are not - offered in this implementation. - Algorithm specification can be found here: - * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf - This implementation uses little endian byte order. -*********************************************************************/ - - /** * * * \param[inout] ctx - * \return rcutils_ret_t + * \return void */ RCUTILS_PUBLIC -RCUTILS_WARN_UNUSED -rcutils_ret_t rcutils_sha256_init(rcutils_sha256_ctx_t * ctx); +void rcutils_sha256_init(rcutils_sha256_ctx_t * ctx); /** * @@ -72,22 +70,20 @@ rcutils_ret_t rcutils_sha256_init(rcutils_sha256_ctx_t * ctx); * \param ctx * \param data * \param len - * \return rcutils_ret_t + * \return void */ RCUTILS_PUBLIC -RCUTILS_WARN_UNUSED -rcutils_ret_t rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t data[], size_t len); +void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t * data, size_t data_len); /** * * * \param ctx * \param hash - * \return rcutils_ret_t + * \return void */ RCUTILS_PUBLIC -RCUTILS_WARN_UNUSED -rcutils_ret_t sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[]); +void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[RCUTILS_SHA256_BLOCK_SIZE]); #ifdef __cplusplus } diff --git a/src/sha256.c b/src/sha256.c index 8aa141f2..d21d6929 100644 --- a/src/sha256.c +++ b/src/sha256.c @@ -16,9 +16,9 @@ #include "rcutils/sha256.h" -static inline uint32_t rotright(uint32_t value, uint8_t bits) +static inline uint32_t rotright(uint32_t a, uint8_t b) { - return (value >> bits) | (value << (32 - bits)); + return (a >> b) | (a << (32 - b)); } static inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z) @@ -105,7 +105,7 @@ void sha256_transform(rcutils_sha256_ctx_t * ctx, const uint8_t data[]) ctx->state[7] += h; } -rcutils_ret_t rcutils_sha256_init(rcutils_sha256_ctx_t * ctx) +void rcutils_sha256_init(rcutils_sha256_ctx_t * ctx) { ctx->datalen = 0; ctx->bitlen = 0; @@ -117,11 +117,9 @@ rcutils_ret_t rcutils_sha256_init(rcutils_sha256_ctx_t * ctx) ctx->state[5] = 0x9b05688c; ctx->state[6] = 0x1f83d9ab; ctx->state[7] = 0x5be0cd19; - - return RCUTILS_RET_OK; } -rcutils_ret_t rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t data[], size_t len) +void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t data, size_t len) { uint32_t i; @@ -134,17 +132,13 @@ rcutils_ret_t rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t da ctx->datalen = 0; } } - - return RCUTILS_RET_OK; } -rcutils_ret_t rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[]) +void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[RCUTILS_SHA256_BLOCK_SIZE]) { - uint32_t i; - + uint32_t i i = ctx->datalen; - // Pad whatever data is left in the buffer. if (ctx->datalen < 56) { ctx->data[i++] = 0x80; while (i < 56) { @@ -174,7 +168,7 @@ rcutils_ret_t rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[]) // Since this implementation uses little endian byte ordering and SHA uses big endian, // reverse all the bytes when copying the final state to the output hash. for (i = 0; i < 4; ++i) { - hash[i + 0] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; @@ -183,6 +177,4 @@ rcutils_ret_t rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[]) hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; } - - return RCUTILS_RET_OK; } diff --git a/test/test_sha256.cpp b/test/test_sha256.cpp new file mode 100644 index 00000000..344f56e4 --- /dev/null +++ b/test/test_sha256.cpp @@ -0,0 +1,69 @@ +// Copyright 2023 Open Source Robotics Foundation, Inc. +// +// 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 +// +// http://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 + +#include "rcutils/sha256.h" + +TEST(TestSHA256, test_text1) { + uint8_t text1[] = {"abc"}; + uint8_t hash1[RCUTILS_SHA256_BLOCK_SIZE] = { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; + uint8_t buf[RCUTILS_SHA256_BLOCK_SIZE]; + + + rcutils_sha256_ctx_t ctx; + rcutils_sha256_init(&ctx); + rcutils_sha256_update(&ctx, text1, sizeof(text1)); + rcutils_sha256_final(&ctx, buf); + + for (int i = 0; i < 32; i++) { + printf("%x ", buf[0]); + } + printf("\n"); + + ASSERT_EQ(0, memcmp(hash1, buf, RCUTILS_SHA256_BLOCK_SIZE)); +} + +// int sha256_test() +// { +// BYTE text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}; +// BYTE text3[] = {"aaaaaaaaaa"}; +// BYTE hash2[SHA256_BLOCK_SIZE] = { +// 0x24,0x8d,0x6a,0x61,0xd2,0x06,0x38,0xb8,0xe5,0xc0,0x26,0x93,0x0c,0x3e,0x60,0x39, +// 0xa3,0x3c,0xe4,0x59,0x64,0xff,0x21,0x67,0xf6,0xec,0xed,0xd4,0x19,0xdb,0x06,0xc1}; +// BYTE hash3[SHA256_BLOCK_SIZE] = { +// 0xcd,0xc7,0x6e,0x5c,0x99,0x14,0xfb,0x92,0x81,0xa1,0xc7,0xe2,0x84,0xd7,0x3e,0x67, +// 0xf1,0x80,0x9a,0x48,0xa4,0x97,0x20,0x0e,0x04,0x6d,0x39,0xcc,0xc7,0x11,0x2c,0xd0}; +// BYTE buf[SHA256_BLOCK_SIZE]; +// SHA256_CTX ctx; +// int idx; +// int pass = 1; + +// sha256_init(&ctx); +// sha256_update(&ctx, text2, strlen(text2)); +// sha256_final(&ctx, buf); +// pass = pass && !memcmp(hash2, buf, SHA256_BLOCK_SIZE); + +// sha256_init(&ctx); +// for (idx = 0; idx < 100000; ++idx) +// sha256_update(&ctx, text3, strlen(text3)); +// sha256_final(&ctx, buf); +// pass = pass && !memcmp(hash3, buf, SHA256_BLOCK_SIZE); + +// return(pass); +// } From 3e3e1b3f4b98b38e4918fe7593909208f5670517 Mon Sep 17 00:00:00 2001 From: Emerson Knapp Date: Tue, 24 Jan 2023 15:42:54 -0800 Subject: [PATCH 04/10] Finish tests and code cleanup Signed-off-by: Emerson Knapp --- include/rcutils/sha256.h | 8 ++--- src/sha256.c | 10 +++--- test/test_sha256.cpp | 68 ++++++++++++++++++++++------------------ 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/include/rcutils/sha256.h b/include/rcutils/sha256.h index 5c63d32c..37c644fc 100644 --- a/include/rcutils/sha256.h +++ b/include/rcutils/sha256.h @@ -49,10 +49,10 @@ extern "C" typedef struct { - unsigned char data[64]; - unsigned int datalen; - unsigned long long bitlen; - unsigned int state[8]; + uint8_t data[64]; + uint32_t datalen; + uint64_t bitlen; + uint32_t state[8]; } rcutils_sha256_ctx_t; /** diff --git a/src/sha256.c b/src/sha256.c index d21d6929..dc907643 100644 --- a/src/sha256.c +++ b/src/sha256.c @@ -119,7 +119,7 @@ void rcutils_sha256_init(rcutils_sha256_ctx_t * ctx) ctx->state[7] = 0x5be0cd19; } -void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t data, size_t len) +void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t * data, size_t len) { uint32_t i; @@ -136,9 +136,9 @@ void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t data, size_ void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[RCUTILS_SHA256_BLOCK_SIZE]) { - uint32_t i - i = ctx->datalen; + uint32_t i = ctx->datalen; + // Pad whatever data is left in the buffer. if (ctx->datalen < 56) { ctx->data[i++] = 0x80; while (i < 56) { @@ -155,7 +155,7 @@ void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[RCUTILS_SHA25 // Append to the padding the total message's length in bits and transform. ctx->bitlen += ctx->datalen * 8; - ctx->data[63] = (uint8_t)(ctx->bitlen); + ctx->data[63] = (uint8_t)(ctx->bitlen >> 0); ctx->data[62] = (uint8_t)(ctx->bitlen >> 8); ctx->data[61] = (uint8_t)(ctx->bitlen >> 16); ctx->data[60] = (uint8_t)(ctx->bitlen >> 24); @@ -168,7 +168,7 @@ void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[RCUTILS_SHA25 // Since this implementation uses little endian byte ordering and SHA uses big endian, // reverse all the bytes when copying the final state to the output hash. for (i = 0; i < 4; ++i) { - hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 0] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; diff --git a/test/test_sha256.cpp b/test/test_sha256.cpp index 344f56e4..9c10b59c 100644 --- a/test/test_sha256.cpp +++ b/test/test_sha256.cpp @@ -18,6 +18,7 @@ TEST(TestSHA256, test_text1) { uint8_t text1[] = {"abc"}; + size_t text1_len = sizeof(text1) - 1; uint8_t hash1[RCUTILS_SHA256_BLOCK_SIZE] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, @@ -28,42 +29,47 @@ TEST(TestSHA256, test_text1) { rcutils_sha256_ctx_t ctx; rcutils_sha256_init(&ctx); - rcutils_sha256_update(&ctx, text1, sizeof(text1)); + rcutils_sha256_update(&ctx, text1, text1_len); rcutils_sha256_final(&ctx, buf); - for (int i = 0; i < 32; i++) { - printf("%x ", buf[0]); - } - printf("\n"); - ASSERT_EQ(0, memcmp(hash1, buf, RCUTILS_SHA256_BLOCK_SIZE)); } -// int sha256_test() -// { -// BYTE text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}; -// BYTE text3[] = {"aaaaaaaaaa"}; -// BYTE hash2[SHA256_BLOCK_SIZE] = { -// 0x24,0x8d,0x6a,0x61,0xd2,0x06,0x38,0xb8,0xe5,0xc0,0x26,0x93,0x0c,0x3e,0x60,0x39, -// 0xa3,0x3c,0xe4,0x59,0x64,0xff,0x21,0x67,0xf6,0xec,0xed,0xd4,0x19,0xdb,0x06,0xc1}; -// BYTE hash3[SHA256_BLOCK_SIZE] = { -// 0xcd,0xc7,0x6e,0x5c,0x99,0x14,0xfb,0x92,0x81,0xa1,0xc7,0xe2,0x84,0xd7,0x3e,0x67, -// 0xf1,0x80,0x9a,0x48,0xa4,0x97,0x20,0x0e,0x04,0x6d,0x39,0xcc,0xc7,0x11,0x2c,0xd0}; -// BYTE buf[SHA256_BLOCK_SIZE]; -// SHA256_CTX ctx; -// int idx; -// int pass = 1; +TEST(TestSHA256, test_text2) { + uint8_t text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}; + size_t text2_len = sizeof(text2) - 1; + uint8_t hash2[RCUTILS_SHA256_BLOCK_SIZE] = { + 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}; + uint8_t buf[RCUTILS_SHA256_BLOCK_SIZE]; + + rcutils_sha256_ctx_t ctx; + rcutils_sha256_init(&ctx); + rcutils_sha256_update(&ctx, text2, text2_len); + rcutils_sha256_final(&ctx, buf); + + ASSERT_EQ(0, memcmp(hash2, buf, RCUTILS_SHA256_BLOCK_SIZE)); +} + +TEST(TestSHA256, test_multi_update) { + uint8_t text[] = {"aaaaaaaaaa"}; + size_t text_len = sizeof(text) - 1; -// sha256_init(&ctx); -// sha256_update(&ctx, text2, strlen(text2)); -// sha256_final(&ctx, buf); -// pass = pass && !memcmp(hash2, buf, SHA256_BLOCK_SIZE); + uint8_t hash[RCUTILS_SHA256_BLOCK_SIZE] = { + 0x28, 0x16, 0x59, 0x78, 0x88, 0xe4, 0xa0, 0xd3, + 0xa3, 0x6b, 0x82, 0xb8, 0x33, 0x16, 0xab, 0x32, + 0x68, 0x0e, 0xb8, 0xf0, 0x0f, 0x8c, 0xd3, 0xb9, + 0x04, 0xd6, 0x81, 0x24, 0x6d, 0x28, 0x5a, 0x0e}; + uint8_t buf[RCUTILS_SHA256_BLOCK_SIZE]; -// sha256_init(&ctx); -// for (idx = 0; idx < 100000; ++idx) -// sha256_update(&ctx, text3, strlen(text3)); -// sha256_final(&ctx, buf); -// pass = pass && !memcmp(hash3, buf, SHA256_BLOCK_SIZE); + rcutils_sha256_ctx_t ctx; + rcutils_sha256_init(&ctx); + for (int i = 0; i < 10; i++) { + rcutils_sha256_update(&ctx, text, text_len); + } + rcutils_sha256_final(&ctx, buf); -// return(pass); -// } + ASSERT_EQ(0, memcmp(hash, buf, RCUTILS_SHA256_BLOCK_SIZE)); +} From ccb74880c7b4563a2c1d187cbf7e7dba0beef2fd Mon Sep 17 00:00:00 2001 From: Emerson Knapp Date: Tue, 24 Jan 2023 15:55:41 -0800 Subject: [PATCH 05/10] Add docstrings Signed-off-by: Emerson Knapp --- include/rcutils/sha256.h | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/include/rcutils/sha256.h b/include/rcutils/sha256.h index 37c644fc..8a9c054a 100644 --- a/include/rcutils/sha256.h +++ b/include/rcutils/sha256.h @@ -18,20 +18,17 @@ /// Implementation originally copied from Brad Conte /// https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c -/// Simple SHA256 implementation -/********************************************************************* -* Filename: sha256.c -* Author: Brad Conte (brad AT bradconte.com) -* Copyright: -* Disclaimer: This code is presented "as is" without any guarantees. -* Details: Implementation of the SHA-256 hashing algorithm. - SHA-256 is one of the three algorithms in the SHA2 - specification. The others, SHA-384 and SHA-512, are not - offered in this implementation. - Algorithm specification can be found here: - * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf - This implementation uses little endian byte order. -*********************************************************************/ +/** \file sha256.h + * \brief SHA256 implementation + * + * This contains an implementation of the SHA256 algorithm + * It was originally copied from Brad Conte + * https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c + * and modified to meet ros2 code formatting and compiler warning requirements. + * Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + * This implementation uses little endian byte order. + */ #ifndef RCUTILS__SHA256_H_ #define RCUTILS__SHA256_H_ @@ -55,8 +52,9 @@ typedef struct uint32_t state[8]; } rcutils_sha256_ctx_t; +/// Initialize the sha256 algorithm context with starting state. /** - * + * Call this on any new context before starting to input data. * * \param[inout] ctx * \return void @@ -64,22 +62,24 @@ typedef struct RCUTILS_PUBLIC void rcutils_sha256_init(rcutils_sha256_ctx_t * ctx); +/// Add data to the sha256 algorithm /** + * This may be called repeatedly on an initialized context. * - * - * \param ctx - * \param data - * \param len + * \param[inout] ctx Initialized sha256 context struct + * \param[in] data Data to add to the total message being hashed + * \param[in] data_len Size of the input data. * \return void */ RCUTILS_PUBLIC void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t * data, size_t data_len); +/// Finalize and output sha256 hash for all data added. /** + * Call only once on a context that has been initialized, and optionally updated with data. * - * - * \param ctx - * \param hash + * \param[inout] ctx Initialized sha256 context struct + * \param[out] hash Calculated sha256 message digest * \return void */ RCUTILS_PUBLIC From 1f5400459e5134a3622f7926b1fcdb51e5702d94 Mon Sep 17 00:00:00 2001 From: Emerson Knapp Date: Tue, 24 Jan 2023 16:01:38 -0800 Subject: [PATCH 06/10] Fix includes Signed-off-by: Emerson Knapp --- include/rcutils/sha256.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/rcutils/sha256.h b/include/rcutils/sha256.h index 8a9c054a..57c278c7 100644 --- a/include/rcutils/sha256.h +++ b/include/rcutils/sha256.h @@ -38,13 +38,13 @@ extern "C" { #endif -#include "rcutils/macros.h" -#include "rcutils/types/rcutils_ret.h" +#include + #include "rcutils/visibility_control.h" #define RCUTILS_SHA256_BLOCK_SIZE 32 -typedef struct +typedef struct RCUTILS_PUBLIC_TYPE rcutils_sha256_ctx_s { uint8_t data[64]; uint32_t datalen; From d8684172c8532a45a01282ce31c30e2f9df8e77e Mon Sep 17 00:00:00 2001 From: Emerson Knapp Date: Wed, 25 Jan 2023 14:40:19 -0800 Subject: [PATCH 07/10] Memcpy blocks in sha256_update Signed-off-by: Emerson Knapp --- include/rcutils/sha256.h | 4 +-- src/sha256.c | 62 +++++++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/include/rcutils/sha256.h b/include/rcutils/sha256.h index 57c278c7..a2229d92 100644 --- a/include/rcutils/sha256.h +++ b/include/rcutils/sha256.h @@ -47,7 +47,7 @@ extern "C" typedef struct RCUTILS_PUBLIC_TYPE rcutils_sha256_ctx_s { uint8_t data[64]; - uint32_t datalen; + size_t datalen; uint64_t bitlen; uint32_t state[8]; } rcutils_sha256_ctx_t; @@ -83,7 +83,7 @@ void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t * data, siz * \return void */ RCUTILS_PUBLIC -void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[RCUTILS_SHA256_BLOCK_SIZE]); +void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t output_hash[RCUTILS_SHA256_BLOCK_SIZE]); #ifdef __cplusplus } diff --git a/src/sha256.c b/src/sha256.c index dc907643..59e267d1 100644 --- a/src/sha256.c +++ b/src/sha256.c @@ -12,12 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include "rcutils/sha256.h" -static inline uint32_t rotright(uint32_t a, uint8_t b) +static inline size_t min(size_t a, size_t b) { + return a < b ? a : b; +} + +static inline size_t max(size_t a, size_t b) +{ + return a > b ? a : b; +} + +static inline uint32_t rotright(uint32_t a, const uint8_t b) +{ + assert(b < 32); return (a >> b) | (a << (32 - b)); } @@ -62,9 +74,10 @@ static const uint32_t k[64] = { 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; -void sha256_transform(rcutils_sha256_ctx_t * ctx, const uint8_t data[]) +static void sha256_transform(rcutils_sha256_ctx_t * ctx) { uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + uint8_t * data = ctx->data; for (i = 0, j = 0; i < 16; ++i, j += 4) { m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); @@ -119,24 +132,33 @@ void rcutils_sha256_init(rcutils_sha256_ctx_t * ctx) ctx->state[7] = 0x5be0cd19; } +#include void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t * data, size_t len) { - uint32_t i; + size_t i, data_remaining, block_remaining, copy_len; + i = 0; + + while (i < len) { + data_remaining = len - i; + block_remaining = 64 - ctx->datalen; + copy_len = min(min(block_remaining, data_remaining), 64); + + memcpy(ctx->data + ctx->datalen, data + i, copy_len); + ctx->datalen += copy_len; + i += copy_len; - for (i = 0; i < len; ++i) { - ctx->data[ctx->datalen] = data[i]; - ctx->datalen++; - if (ctx->datalen == 64) { - sha256_transform(ctx, ctx->data); + if (ctx->datalen >= 64) { + sha256_transform(ctx); ctx->bitlen += 512; ctx->datalen = 0; } } } -void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[RCUTILS_SHA256_BLOCK_SIZE]) +void rcutils_sha256_final( + rcutils_sha256_ctx_t * ctx, uint8_t output_hash[RCUTILS_SHA256_BLOCK_SIZE]) { - uint32_t i = ctx->datalen; + size_t i = ctx->datalen; // Pad whatever data is left in the buffer. if (ctx->datalen < 56) { @@ -149,7 +171,7 @@ void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[RCUTILS_SHA25 while (i < 64) { ctx->data[i++] = 0x00; } - sha256_transform(ctx, ctx->data); + sha256_transform(ctx); memset(ctx->data, 0, 56); } @@ -163,18 +185,18 @@ void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t hash[RCUTILS_SHA25 ctx->data[58] = (uint8_t)(ctx->bitlen >> 40); ctx->data[57] = (uint8_t)(ctx->bitlen >> 48); ctx->data[56] = (uint8_t)(ctx->bitlen >> 56); - sha256_transform(ctx, ctx->data); + sha256_transform(ctx); // Since this implementation uses little endian byte ordering and SHA uses big endian, // reverse all the bytes when copying the final state to the output hash. for (i = 0; i < 4; ++i) { - hash[i + 0] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; - hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; - hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; - hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; - hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; - hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; - hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; - hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + output_hash[i + 0] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + output_hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + output_hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + output_hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + output_hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + output_hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + output_hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + output_hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; } } From a9e987ac4a0946d43dbc0daeef09175522d4a4e7 Mon Sep 17 00:00:00 2001 From: Emerson Knapp Date: Wed, 25 Jan 2023 14:47:07 -0800 Subject: [PATCH 08/10] Remaining review comments Signed-off-by: Emerson Knapp --- src/sha256.c | 9 +++------ test/test_sha256.cpp | 12 ++++++------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/sha256.c b/src/sha256.c index 59e267d1..515e7a19 100644 --- a/src/sha256.c +++ b/src/sha256.c @@ -132,7 +132,6 @@ void rcutils_sha256_init(rcutils_sha256_ctx_t * ctx) ctx->state[7] = 0x5be0cd19; } -#include void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t * data, size_t len) { size_t i, data_remaining, block_remaining, copy_len; @@ -163,13 +162,11 @@ void rcutils_sha256_final( // Pad whatever data is left in the buffer. if (ctx->datalen < 56) { ctx->data[i++] = 0x80; - while (i < 56) { - ctx->data[i++] = 0x00; - } + memset(ctx->data + i, 0x00, 56 - i); } else { ctx->data[i++] = 0x80; - while (i < 64) { - ctx->data[i++] = 0x00; + if (i < 64) { + memset(ctx->data + i, 0x00, 64 - i); } sha256_transform(ctx); memset(ctx->data, 0, 56); diff --git a/test/test_sha256.cpp b/test/test_sha256.cpp index 9c10b59c..fda87c88 100644 --- a/test/test_sha256.cpp +++ b/test/test_sha256.cpp @@ -19,7 +19,7 @@ TEST(TestSHA256, test_text1) { uint8_t text1[] = {"abc"}; size_t text1_len = sizeof(text1) - 1; - uint8_t hash1[RCUTILS_SHA256_BLOCK_SIZE] = { + uint8_t expected_hash1[RCUTILS_SHA256_BLOCK_SIZE] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, @@ -32,13 +32,13 @@ TEST(TestSHA256, test_text1) { rcutils_sha256_update(&ctx, text1, text1_len); rcutils_sha256_final(&ctx, buf); - ASSERT_EQ(0, memcmp(hash1, buf, RCUTILS_SHA256_BLOCK_SIZE)); + ASSERT_EQ(0, memcmp(expected_hash1, buf, RCUTILS_SHA256_BLOCK_SIZE)); } TEST(TestSHA256, test_text2) { uint8_t text2[] = {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}; size_t text2_len = sizeof(text2) - 1; - uint8_t hash2[RCUTILS_SHA256_BLOCK_SIZE] = { + uint8_t expected_hash2[RCUTILS_SHA256_BLOCK_SIZE] = { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, @@ -50,14 +50,14 @@ TEST(TestSHA256, test_text2) { rcutils_sha256_update(&ctx, text2, text2_len); rcutils_sha256_final(&ctx, buf); - ASSERT_EQ(0, memcmp(hash2, buf, RCUTILS_SHA256_BLOCK_SIZE)); + ASSERT_EQ(0, memcmp(expected_hash2, buf, RCUTILS_SHA256_BLOCK_SIZE)); } TEST(TestSHA256, test_multi_update) { uint8_t text[] = {"aaaaaaaaaa"}; size_t text_len = sizeof(text) - 1; - uint8_t hash[RCUTILS_SHA256_BLOCK_SIZE] = { + uint8_t expected_hash[RCUTILS_SHA256_BLOCK_SIZE] = { 0x28, 0x16, 0x59, 0x78, 0x88, 0xe4, 0xa0, 0xd3, 0xa3, 0x6b, 0x82, 0xb8, 0x33, 0x16, 0xab, 0x32, 0x68, 0x0e, 0xb8, 0xf0, 0x0f, 0x8c, 0xd3, 0xb9, @@ -71,5 +71,5 @@ TEST(TestSHA256, test_multi_update) { } rcutils_sha256_final(&ctx, buf); - ASSERT_EQ(0, memcmp(hash, buf, RCUTILS_SHA256_BLOCK_SIZE)); + ASSERT_EQ(0, memcmp(expected_hash, buf, RCUTILS_SHA256_BLOCK_SIZE)); } From fa5aa5a9af5e867297d15832285a3fcaa6c31f12 Mon Sep 17 00:00:00 2001 From: Emerson Knapp Date: Wed, 25 Jan 2023 14:51:17 -0800 Subject: [PATCH 09/10] Update docstring var name Signed-off-by: Emerson Knapp --- include/rcutils/sha256.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rcutils/sha256.h b/include/rcutils/sha256.h index a2229d92..8ee32d84 100644 --- a/include/rcutils/sha256.h +++ b/include/rcutils/sha256.h @@ -79,7 +79,7 @@ void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t * data, siz * Call only once on a context that has been initialized, and optionally updated with data. * * \param[inout] ctx Initialized sha256 context struct - * \param[out] hash Calculated sha256 message digest + * \param[out] output_hash Calculated sha256 message digest to be filled * \return void */ RCUTILS_PUBLIC From 97aab3537c59fd2ec0a5f3f4b6ef53cef4e9ea6d Mon Sep 17 00:00:00 2001 From: Emerson Knapp Date: Thu, 26 Jan 2023 11:47:41 -0800 Subject: [PATCH 10/10] Fix long line Signed-off-by: Emerson Knapp --- include/rcutils/sha256.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/rcutils/sha256.h b/include/rcutils/sha256.h index 8ee32d84..6632f6df 100644 --- a/include/rcutils/sha256.h +++ b/include/rcutils/sha256.h @@ -83,7 +83,9 @@ void rcutils_sha256_update(rcutils_sha256_ctx_t * ctx, const uint8_t * data, siz * \return void */ RCUTILS_PUBLIC -void rcutils_sha256_final(rcutils_sha256_ctx_t * ctx, uint8_t output_hash[RCUTILS_SHA256_BLOCK_SIZE]); +void rcutils_sha256_final( + rcutils_sha256_ctx_t * ctx, + uint8_t output_hash[RCUTILS_SHA256_BLOCK_SIZE]); #ifdef __cplusplus }