Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_sha256.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33
34#include "nilorea/n_common.h"
35#include "nilorea/n_log.h"
36#include "nilorea/n_sha256.h"
37
39static int log_level = LOG_ERR;
41static int failures = 0;
42
46static void expect_true(const char* what, int ok) {
47 if (!ok) {
48 n_log(LOG_ERR, "FAIL: %s", what);
49 failures++;
50 } else {
51 n_log(LOG_INFO, "ok: %s", what);
52 }
53}
54
59static int process_args(int argc, char** argv) {
60 int opt = 0;
61
62 while ((opt = getopt(argc, argv, "V:")) != -1) {
63 if (opt == 'V') {
64 log_level = atoi(optarg);
65 } else {
66 return -1;
67 }
68 }
69 return 0;
70}
71
77static int hex_is(const void* data, size_t len, const char* want) {
78 unsigned char digest[N_SHA256_LEN];
79 char hex[N_SHA256_HEX_LEN];
80
81 n_sha256(data, len, digest);
82 n_sha256_hex(digest, hex);
83 return strcmp(hex, want) == 0;
84}
85
90int main(int argc, char** argv) {
91 static const char* two_blocks = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
92 unsigned char whole[N_SHA256_LEN], pieces[N_SHA256_LEN];
93 char* million = NULL;
94 size_t step = 0;
95
97 if (process_args(argc, argv) != 0) {
98 fprintf(stderr, "Usage: %s [-V LOG_LEVEL]\n", argv[0]);
99 return 2;
100 }
102
103 expect_true("the empty string", hex_is("", 0, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"));
104 expect_true("abc", hex_is("abc", 3, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"));
105 expect_true("two blocks", hex_is(two_blocks, strlen(two_blocks),
106 "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"));
107 million = (char*)malloc(1000000);
108 if (million) {
109 memset(million, 'a', 1000000);
110 expect_true("a million a", hex_is(million, 1000000,
111 "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"));
112 /* Fed in pieces of every size from 1 to 130: the block boundary
113 * crossed in every way, the same digest. */
114 n_sha256(million, 100000, whole);
115 for (step = 1; step <= 130; step++) {
116 N_SHA256 ctx;
117 size_t done = 0;
118
119 n_sha256_init(&ctx);
120 while (done < 100000) {
121 size_t take = 100000 - done < step ? 100000 - done : step;
122
123 n_sha256_update(&ctx, million + done, take);
124 done += take;
125 }
126 n_sha256_final(&ctx, pieces);
127 if (memcmp(whole, pieces, N_SHA256_LEN) != 0) break;
128 }
129 expect_true("pieces of every size give the one call's digest", step > 130);
130 {
131 /* A name of its own in the working directory: mkstemp() is not in
132 * every C library this builds against. */
133 static const char* path = "ex_sha256.tmp";
134 unsigned char from_file[N_SHA256_LEN];
135 FILE* f = fopen(path, "wb");
136
137 if (f) {
138 size_t wrote = fwrite(million, 1, 1000000, f);
139
140 fclose(f);
141 n_sha256(million, 1000000, whole);
142 expect_true("a file hashes as its bytes", wrote == 1000000 && n_sha256_file(path, from_file) == 0 &&
143 memcmp(whole, from_file, N_SHA256_LEN) == 0);
144 remove(path);
145 }
146 /* Where n_sha256_file() stops reading: empty, and exactly one
147 * and two of its 65536 byte reads, where the last read comes back
148 * with nothing after full ones. */
149 {
150 static const size_t sizes[] = {0, 65536, 131072};
151 size_t k = 0;
152
153 for (k = 0; k < sizeof(sizes) / sizeof(sizes[0]); k++) {
154 char what[64];
155 size_t wrote = 0;
156
157 f = fopen(path, "wb");
158 if (!f)
159 continue;
160 wrote = sizes[k] ? fwrite(million, 1, sizes[k], f) : 0;
161 fclose(f);
162 n_sha256(million, sizes[k], whole);
163 snprintf(what, sizeof(what), "a file of %zu bytes hashes as its bytes", sizes[k]);
164 expect_true(what, wrote == sizes[k] && n_sha256_file(path, from_file) == 0 &&
165 memcmp(whole, from_file, N_SHA256_LEN) == 0);
166 remove(path);
167 }
168 }
169 }
170 free(million);
171 }
172 expect_true("a missing file is refused", n_sha256_file("/nonexistent/ex_sha256", whole) == -1);
173
174 if (failures) {
175 fprintf(stderr, "ex_sha256: %d failure(s)\n", failures);
176 return 1;
177 }
178 printf("ex_sha256: ok\n");
179 return 0;
180}
void process_args(int argc, char **argv)
static int failures
Definition ex_atlas.c:51
int main(void)
Definition ex_atlas.c:117
static void expect_true(const char *label, int cond)
Definition ex_atlas.c:53
static int log_level
volatile sig_atomic_t done
static int hex_is(const void *data, size_t len, const char *want)
the hex digest of a buffer equals the expected one
Definition ex_sha256.c:77
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:113
#define LOG_ERR
error conditions
Definition n_log.h:100
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
Definition n_log.c:123
#define LOG_INFO
informational
Definition n_log.h:106
void n_sha256_final(N_SHA256 *ctx, unsigned char out[32])
finish: the digest, the state left spent
Definition n_sha256.c:132
void n_sha256_init(N_SHA256 *ctx)
start a hash
Definition n_sha256.c:91
int n_sha256_file(const char *path, unsigned char out[32])
hash a file, read in pieces
Definition n_sha256.c:166
void n_sha256(const void *data, size_t len, unsigned char out[32])
hash one buffer
Definition n_sha256.c:158
#define N_SHA256_HEX_LEN
size of its lowercase hex form, terminator included
Definition n_sha256.h:54
void n_sha256_update(N_SHA256 *ctx, const void *data, size_t len)
feed bytes
Definition n_sha256.c:103
#define N_SHA256_LEN
size in bytes of a SHA-256 digest
Definition n_sha256.h:52
void n_sha256_hex(const unsigned char digest[32], char out[65])
a digest as lowercase hex
Definition n_sha256.c:195
a SHA-256 in progress: plain data, copyable to fork a hash
Definition n_sha256.h:57
Common headers and low-level functions & define.
Generic log system.
SHA-256 in portable C, fed a piece at a time.