libluna+apps: Add a SHA256 hash implementation
All checks were successful
Build and test / build (push) Successful in 2m26s
All checks were successful
Build and test / build (push) Successful in 2m26s
This commit is contained in:
parent
7345a952ca
commit
db2f91b1fb
@ -52,3 +52,4 @@ target_link_libraries(clock PUBLIC ui)
|
|||||||
luna_app(startui.cpp startui)
|
luna_app(startui.cpp startui)
|
||||||
luna_app(launch.cpp launch)
|
luna_app(launch.cpp launch)
|
||||||
luna_app(run.cpp run)
|
luna_app(run.cpp run)
|
||||||
|
luna_app(sha256sum.cpp sha256sum)
|
||||||
|
30
apps/sha256sum.cpp
Normal file
30
apps/sha256sum.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <luna/SHA.h>
|
||||||
|
#include <os/ArgumentParser.h>
|
||||||
|
#include <os/File.h>
|
||||||
|
|
||||||
|
Result<int> luna_main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
Vector<StringView> files;
|
||||||
|
|
||||||
|
os::ArgumentParser parser;
|
||||||
|
parser.add_description("Calculate SHA256 hashes for a series of files."_sv);
|
||||||
|
parser.add_system_program_info("sha256sum"_sv);
|
||||||
|
parser.set_vector_argument(files, "files"_sv, "-"_sv);
|
||||||
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
|
for (auto path : files)
|
||||||
|
{
|
||||||
|
auto file = TRY(os::File::open_input_file(path));
|
||||||
|
auto data = TRY(file->read_all());
|
||||||
|
|
||||||
|
SHA256 sha;
|
||||||
|
|
||||||
|
TRY(sha.append(data.data(), data.size()));
|
||||||
|
auto hash = TRY(sha.digest());
|
||||||
|
|
||||||
|
auto string = TRY(sha.hash_to_string(hash));
|
||||||
|
os::println("%s %s", string.chars(), path.chars());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -16,6 +16,7 @@ set(FREESTANDING_SOURCES
|
|||||||
src/Bitmap.cpp
|
src/Bitmap.cpp
|
||||||
src/Buffer.cpp
|
src/Buffer.cpp
|
||||||
src/Scanf.cpp
|
src/Scanf.cpp
|
||||||
|
src/SHA.cpp
|
||||||
src/Stack.cpp
|
src/Stack.cpp
|
||||||
src/String.cpp
|
src/String.cpp
|
||||||
src/StringBuilder.cpp
|
src/StringBuilder.cpp
|
||||||
|
40
libluna/include/luna/SHA.h
Normal file
40
libluna/include/luna/SHA.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* @file SHA.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief SHA256 algorithm implementation.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <luna/Buffer.h>
|
||||||
|
#include <luna/String.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A class to calculate a SHA256 hash.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class SHA256
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Add data to the hash.
|
||||||
|
*
|
||||||
|
* @param data The data to add.
|
||||||
|
* @param size The amount of bytes to add.
|
||||||
|
*/
|
||||||
|
Result<void> append(const u8* data, usize size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculate the final hash.
|
||||||
|
*
|
||||||
|
* @return Buffer The calculated hash.
|
||||||
|
*/
|
||||||
|
Result<Buffer> digest();
|
||||||
|
|
||||||
|
static Result<String> hash_to_string(const Buffer& buffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Buffer m_message;
|
||||||
|
};
|
185
libluna/src/SHA.cpp
Normal file
185
libluna/src/SHA.cpp
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
/**
|
||||||
|
* @file SHA.cpp
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief SHA256 algorithm implementation.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <luna/Alignment.h>
|
||||||
|
#include <luna/Common.h>
|
||||||
|
#include <luna/DebugLog.h>
|
||||||
|
#include <luna/SHA.h>
|
||||||
|
#include <luna/StringBuilder.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Taken from https://gist.github.com/hak8or/8794351
|
||||||
|
#define ROTRIGHT(word, bits) (((word) >> (bits)) | ((word) << (32 - (bits))))
|
||||||
|
|
||||||
|
u32 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 };
|
||||||
|
|
||||||
|
u32 static H0 = 0x6a09e667;
|
||||||
|
u32 static H1 = 0xbb67ae85;
|
||||||
|
u32 static H2 = 0x3c6ef372;
|
||||||
|
u32 static H3 = 0xa54ff53a;
|
||||||
|
u32 static H4 = 0x510e527f;
|
||||||
|
u32 static H5 = 0x9b05688c;
|
||||||
|
u32 static H6 = 0x1f83d9ab;
|
||||||
|
u32 static H7 = 0x5be0cd19;
|
||||||
|
|
||||||
|
Result<void> SHA256::append(const u8* data, usize size)
|
||||||
|
{
|
||||||
|
return m_message.append_data(data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thank you to https://sha256algorithm.com/ for showing me how the SHA256 algorithm works, and effectively, how to
|
||||||
|
// implement it!
|
||||||
|
Result<Buffer> SHA256::digest()
|
||||||
|
{
|
||||||
|
usize message_block_length = m_message.size() + 1 + sizeof(u64);
|
||||||
|
usize message_block_chunks = ceil_div(message_block_length, 64ul);
|
||||||
|
usize num_zeros = message_block_chunks * 64 - message_block_length;
|
||||||
|
|
||||||
|
// Prepare a message block and add the data into it.
|
||||||
|
Buffer message_block;
|
||||||
|
TRY(message_block.append_data(m_message.data(), m_message.size()));
|
||||||
|
|
||||||
|
// Add one bit at the end.
|
||||||
|
u8 one = 0b10000000;
|
||||||
|
TRY(message_block.append_data(&one, 1));
|
||||||
|
|
||||||
|
// Fill with zeros.
|
||||||
|
u8* slice = TRY(message_block.slice_at_end(num_zeros));
|
||||||
|
memset(slice, 0, num_zeros);
|
||||||
|
|
||||||
|
// Add the length of the original message (in bits), this has to be big-endian.
|
||||||
|
usize message_length = m_message.size() * 8;
|
||||||
|
message_length = __builtin_bswap64(message_length); // FIXME: We're assuming we're on a little-endian platform.
|
||||||
|
TRY(message_block.append_data((const u8*)&message_length, sizeof(usize)));
|
||||||
|
|
||||||
|
// The length of the message block should now be a multiple of 512 bits (64 bytes).
|
||||||
|
check(is_aligned<64>(message_block.size()));
|
||||||
|
|
||||||
|
u32 a, b, c, d, e, f, g, h; // working variables
|
||||||
|
u32 h0, h1, h2, h3, h4, h5, h6, h7; // hash values
|
||||||
|
|
||||||
|
// Initialize the hash values to their starting values.
|
||||||
|
h0 = H0;
|
||||||
|
h1 = H1;
|
||||||
|
h2 = H2;
|
||||||
|
h3 = H3;
|
||||||
|
h4 = H4;
|
||||||
|
h5 = H5;
|
||||||
|
h6 = H6;
|
||||||
|
h7 = H7;
|
||||||
|
|
||||||
|
// For each 512-bit (64-byte) chunk, perform the following operations.
|
||||||
|
for (usize i = 0; i < message_block_chunks; i++)
|
||||||
|
{
|
||||||
|
// Create a message schedule of 64 dwords, and copy the current chunk into the first 16 dwords.
|
||||||
|
u32 message_schedule[64];
|
||||||
|
|
||||||
|
memcpy(message_schedule, &message_block.data()[i * 64], 64);
|
||||||
|
|
||||||
|
for (int j = 0; j < 16; j++)
|
||||||
|
{
|
||||||
|
// SHA uses big-endian. FIXME: Don't assume little-endian.
|
||||||
|
message_schedule[j] = __builtin_bswap32(message_schedule[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the rest of the message schedule.
|
||||||
|
for (int j = 0; j < 48; j++)
|
||||||
|
{
|
||||||
|
u32 w0 = message_schedule[j];
|
||||||
|
u32 w1 = message_schedule[j + 1];
|
||||||
|
u32 w14 = message_schedule[j + 14];
|
||||||
|
u32 w9 = message_schedule[j + 9];
|
||||||
|
|
||||||
|
u32 s0 = ROTRIGHT(w1, 7) ^ ROTRIGHT(w1, 18) ^ (w1 >> 3);
|
||||||
|
u32 s1 = ROTRIGHT(w14, 17) ^ ROTRIGHT(w14, 19) ^ (w14 >> 10);
|
||||||
|
|
||||||
|
message_schedule[j + 16] = w0 + s0 + w9 + s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the working variables with the current hash values.
|
||||||
|
a = h0;
|
||||||
|
b = h1;
|
||||||
|
c = h2;
|
||||||
|
d = h3;
|
||||||
|
e = h4;
|
||||||
|
f = h5;
|
||||||
|
g = h6;
|
||||||
|
h = h7;
|
||||||
|
|
||||||
|
// For each dword in the message schedule, update the working variables, using this algorithm and the
|
||||||
|
// corresponding dword from the constant k[] array.
|
||||||
|
for (int j = 0; j < 64; j++)
|
||||||
|
{
|
||||||
|
u32 temp1, temp2, choice, majority;
|
||||||
|
choice = (e & f) ^ ((~e) & g);
|
||||||
|
majority = (a & b) ^ (a & c) ^ (b & c);
|
||||||
|
temp1 = h + (ROTRIGHT(e, 6) ^ ROTRIGHT(e, 11) ^ ROTRIGHT(e, 25)) + choice + k[j] + message_schedule[j];
|
||||||
|
temp2 = (ROTRIGHT(a, 2) ^ ROTRIGHT(a, 13) ^ ROTRIGHT(a, 22)) + majority;
|
||||||
|
|
||||||
|
h = g;
|
||||||
|
g = f;
|
||||||
|
f = e;
|
||||||
|
e = d + temp1;
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b = a;
|
||||||
|
a = temp1 + temp2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the working variables to the hash values.
|
||||||
|
h0 += a;
|
||||||
|
h1 += b;
|
||||||
|
h2 += c;
|
||||||
|
h3 += d;
|
||||||
|
h4 += e;
|
||||||
|
h5 += f;
|
||||||
|
h6 += g;
|
||||||
|
h7 += h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Again, this assumes little-endian.
|
||||||
|
h0 = __builtin_bswap32(h0);
|
||||||
|
h1 = __builtin_bswap32(h1);
|
||||||
|
h2 = __builtin_bswap32(h2);
|
||||||
|
h3 = __builtin_bswap32(h3);
|
||||||
|
h4 = __builtin_bswap32(h4);
|
||||||
|
h5 = __builtin_bswap32(h5);
|
||||||
|
h6 = __builtin_bswap32(h6);
|
||||||
|
h7 = __builtin_bswap32(h7);
|
||||||
|
|
||||||
|
Buffer result;
|
||||||
|
TRY(result.append_data((const u8*)&h0, sizeof(u32)));
|
||||||
|
TRY(result.append_data((const u8*)&h1, sizeof(u32)));
|
||||||
|
TRY(result.append_data((const u8*)&h2, sizeof(u32)));
|
||||||
|
TRY(result.append_data((const u8*)&h3, sizeof(u32)));
|
||||||
|
TRY(result.append_data((const u8*)&h4, sizeof(u32)));
|
||||||
|
TRY(result.append_data((const u8*)&h5, sizeof(u32)));
|
||||||
|
TRY(result.append_data((const u8*)&h6, sizeof(u32)));
|
||||||
|
TRY(result.append_data((const u8*)&h7, sizeof(u32)));
|
||||||
|
|
||||||
|
m_message.try_resize(0); // Don't need this anymore.
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<String> SHA256::hash_to_string(const Buffer& buffer)
|
||||||
|
{
|
||||||
|
StringBuilder sb;
|
||||||
|
|
||||||
|
for (usize i = 0; i < buffer.size(); i++) { sb.format("%02x", buffer.data()[i]); }
|
||||||
|
|
||||||
|
return sb.string();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user