]>
Commit | Line | Data |
---|---|---|
4c8cdcd1 | 1 | /*- |
da1c088f | 2 | * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. |
4c8cdcd1 HL |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | #include <stdio.h> | |
11 | #include <string.h> | |
12 | #include <openssl/err.h> | |
13 | #include <openssl/evp.h> | |
14 | #include <openssl/core_names.h> | |
15 | ||
16 | /* | |
17 | * Example of using an extendable-output hash function (XOF). A XOF is a hash | |
18 | * function with configurable output length and which can generate an | |
19 | * arbitrarily large output. | |
20 | * | |
21 | * This example uses SHAKE256, an extendable output variant of SHA3 (Keccak). | |
22 | * | |
23 | * To generate different output lengths, you can pass a single integer argument | |
24 | * on the command line, which is the output size in bytes. By default, a 20-byte | |
25 | * output is generated and (for this length only) a known answer test is | |
26 | * performed. | |
27 | */ | |
28 | ||
29 | /* Our input to the XOF hash function. */ | |
30 | const char message[] = "This is a test message."; | |
31 | ||
32 | /* Expected output when an output length of 20 bytes is used. */ | |
33 | static const char known_answer[] = { | |
34 | 0x52, 0x97, 0x93, 0x78, 0x27, 0x58, 0x7d, 0x62, | |
35 | 0x8b, 0x00, 0x25, 0xb5, 0xec, 0x39, 0x5e, 0x2d, | |
36 | 0x7f, 0x3e, 0xd4, 0x19 | |
37 | }; | |
38 | ||
39 | /* | |
40 | * A property query used for selecting the SHAKE256 implementation. | |
41 | */ | |
42 | static const char *propq = NULL; | |
43 | ||
44 | int main(int argc, char **argv) | |
45 | { | |
09ff84bd | 46 | int ret = EXIT_FAILURE; |
4c8cdcd1 HL |
47 | OSSL_LIB_CTX *libctx = NULL; |
48 | EVP_MD *md = NULL; | |
49 | EVP_MD_CTX *ctx = NULL; | |
50 | unsigned int digest_len = 20; | |
51 | int digest_len_i; | |
52 | unsigned char *digest = NULL; | |
53 | ||
54 | /* Allow digest length to be changed for demonstration purposes. */ | |
55 | if (argc > 1) { | |
56 | digest_len_i = atoi(argv[1]); | |
57 | if (digest_len_i <= 0) { | |
58 | fprintf(stderr, "Specify a non-negative digest length\n"); | |
59 | goto end; | |
60 | } | |
61 | ||
62 | digest_len = (unsigned int)digest_len_i; | |
63 | } | |
64 | ||
65 | /* | |
66 | * Retrieve desired algorithm. This must be a hash algorithm which supports | |
67 | * XOF. | |
68 | */ | |
69 | md = EVP_MD_fetch(libctx, "SHAKE256", propq); | |
70 | if (md == NULL) { | |
71 | fprintf(stderr, "Failed to retrieve SHAKE256 algorithm\n"); | |
72 | goto end; | |
73 | } | |
74 | ||
75 | /* Create context. */ | |
76 | ctx = EVP_MD_CTX_new(); | |
77 | if (ctx == NULL) { | |
78 | fprintf(stderr, "Failed to create digest context\n"); | |
79 | goto end; | |
80 | } | |
81 | ||
82 | /* Initialize digest context. */ | |
83 | if (EVP_DigestInit(ctx, md) == 0) { | |
84 | fprintf(stderr, "Failed to initialize digest\n"); | |
85 | goto end; | |
86 | } | |
87 | ||
88 | /* | |
89 | * Feed our message into the digest function. | |
90 | * This may be called multiple times. | |
91 | */ | |
92 | if (EVP_DigestUpdate(ctx, message, sizeof(message)) == 0) { | |
93 | fprintf(stderr, "Failed to hash input message\n"); | |
94 | goto end; | |
95 | } | |
96 | ||
97 | /* Allocate enough memory for our digest length. */ | |
98 | digest = OPENSSL_malloc(digest_len); | |
99 | if (digest == NULL) { | |
100 | fprintf(stderr, "Failed to allocate memory for digest\n"); | |
101 | goto end; | |
102 | } | |
103 | ||
104 | /* Get computed digest. The digest will be of whatever length we specify. */ | |
105 | if (EVP_DigestFinalXOF(ctx, digest, digest_len) == 0) { | |
106 | fprintf(stderr, "Failed to finalize hash\n"); | |
107 | goto end; | |
108 | } | |
109 | ||
110 | printf("Output digest:\n"); | |
111 | BIO_dump_indent_fp(stdout, digest, digest_len, 2); | |
112 | ||
113 | /* If digest length is 20 bytes, check it matches our known answer. */ | |
114 | if (digest_len == 20) { | |
115 | /* | |
116 | * Always use a constant-time function such as CRYPTO_memcmp | |
117 | * when comparing cryptographic values. Do not use memcmp(3). | |
118 | */ | |
119 | if (CRYPTO_memcmp(digest, known_answer, sizeof(known_answer)) != 0) { | |
120 | fprintf(stderr, "Output does not match expected result\n"); | |
121 | goto end; | |
122 | } | |
123 | } | |
124 | ||
09ff84bd | 125 | ret = EXIT_SUCCESS; |
4c8cdcd1 HL |
126 | end: |
127 | OPENSSL_free(digest); | |
128 | EVP_MD_CTX_free(ctx); | |
129 | EVP_MD_free(md); | |
130 | OSSL_LIB_CTX_free(libctx); | |
09ff84bd | 131 | return ret; |
4c8cdcd1 | 132 | } |