1 // SPDX-License-Identifier: Unlicense AND BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
3 /* Copyright (c) 2023 Linaro Limited */
4 #include <crypto/crypto_accel.h>
5 #include <tomcrypt_private.h>
6
7 /**
8 @param sha512.c
9 LTC_SHA512 by Tom St Denis
10 */
11
12 #ifdef LTC_SHA512
13
14 const struct ltc_hash_descriptor sha512_desc =
15 {
16 "sha512",
17 5,
18 64,
19 128,
20
21 /* OID */
22 { 2, 16, 840, 1, 101, 3, 4, 2, 3, },
23 9,
24
25 &sha512_init,
26 &sha512_process,
27 &sha512_done,
28 &sha512_test,
29 NULL
30 };
31
32
33 /* Implemented in assembly */
34 int sha512_ce_transform(ulong64 *state, const unsigned char *buf, int blocks);
35
sha512_compress_nblocks(hash_state * md,const unsigned char * buf,int blocks)36 static int sha512_compress_nblocks(hash_state *md, const unsigned char *buf,
37 int blocks)
38 {
39 void *state = md->sha512.state;
40
41 COMPILE_TIME_ASSERT(sizeof(md->sha512.state[0]) == sizeof(uint64_t));
42
43 crypto_accel_sha512_compress(state, buf, blocks);
44
45 return CRYPT_OK;
46 }
47
sha512_compress(hash_state * md,const unsigned char * buf)48 static int sha512_compress(hash_state *md, const unsigned char *buf)
49 {
50 return sha512_compress_nblocks(md, buf, 1);
51 }
52
53 /**
54 Initialize the hash state
55 @param md The hash state you wish to initialize
56 @return CRYPT_OK if successful
57 */
sha512_init(hash_state * md)58 int sha512_init(hash_state * md)
59 {
60 LTC_ARGCHK(md != NULL);
61 md->sha512.curlen = 0;
62 md->sha512.length = 0;
63 md->sha512.state[0] = CONST64(0x6a09e667f3bcc908);
64 md->sha512.state[1] = CONST64(0xbb67ae8584caa73b);
65 md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b);
66 md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1);
67 md->sha512.state[4] = CONST64(0x510e527fade682d1);
68 md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f);
69 md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b);
70 md->sha512.state[7] = CONST64(0x5be0cd19137e2179);
71 return CRYPT_OK;
72 }
73
74 HASH_PROCESS_NBLOCKS(sha512_process, sha512_compress_nblocks, sha512, 128)
75
76 /**
77 Terminate the hash to get the digest
78 @param md The hash state
79 @param out [out] The destination of the hash (64 bytes)
80 @return CRYPT_OK if successful
81 */
sha512_done(hash_state * md,unsigned char * out)82 int sha512_done(hash_state * md, unsigned char *out)
83 {
84 int i;
85
86 LTC_ARGCHK(md != NULL);
87 LTC_ARGCHK(out != NULL);
88
89 if (md->sha512.curlen >= sizeof(md->sha512.buf)) {
90 return CRYPT_INVALID_ARG;
91 }
92
93 /* increase the length of the message */
94 md->sha512.length += md->sha512.curlen * CONST64(8);
95
96 /* append the '1' bit */
97 md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80;
98
99 /* if the length is currently above 112 bytes we append zeros
100 * then compress. Then we can fall back to padding zeros and length
101 * encoding like normal.
102 */
103 if (md->sha512.curlen > 112) {
104 while (md->sha512.curlen < 128) {
105 md->sha512.buf[md->sha512.curlen++] = (unsigned char)0;
106 }
107 sha512_compress(md, md->sha512.buf);
108 md->sha512.curlen = 0;
109 }
110
111 /* pad upto 120 bytes of zeroes
112 * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
113 * > 2^64 bits of data... :-)
114 */
115 while (md->sha512.curlen < 120) {
116 md->sha512.buf[md->sha512.curlen++] = (unsigned char)0;
117 }
118
119 /* store length */
120 STORE64H(md->sha512.length, md->sha512.buf+120);
121 sha512_compress(md, md->sha512.buf);
122
123 /* copy output */
124 for (i = 0; i < 8; i++) {
125 STORE64H(md->sha512.state[i], out+(8*i));
126 }
127 #ifdef LTC_CLEAN_STACK
128 zeromem(md, sizeof(hash_state));
129 #endif
130 return CRYPT_OK;
131 }
132
133 /**
134 Self-test the hash
135 @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
136 */
sha512_test(void)137 int sha512_test(void)
138 {
139 #ifndef LTC_TEST
140 return CRYPT_NOP;
141 #else
142 static const struct {
143 const char *msg;
144 unsigned char hash[64];
145 } tests[] = {
146 { "abc",
147 { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba,
148 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
149 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
150 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
151 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8,
152 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
153 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
154 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f }
155 },
156 { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
157 { 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda,
158 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f,
159 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1,
160 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18,
161 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4,
162 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a,
163 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54,
164 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 }
165 },
166 };
167
168 int i;
169 unsigned char tmp[64];
170 hash_state md;
171
172 for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
173 sha512_init(&md);
174 sha512_process(&md, (unsigned char *)tests[i].msg, (unsigned long)XSTRLEN(tests[i].msg));
175 sha512_done(&md, tmp);
176 if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "SHA512", i)) {
177 return CRYPT_FAIL_TESTVECTOR;
178 }
179 }
180 return CRYPT_OK;
181 #endif
182 }
183
184 #endif /*LTC_SHA512*/
185