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