xref: /openbsd/usr.bin/ssh/xmss_hash.c (revision 0a3ea9a3)
1 /* $OpenBSD: xmss_hash.c,v 1.4 2023/12/20 00:06:25 jsg Exp $ */
2 /*
3 hash.c version 20160722
4 Andreas Hülsing
5 Joost Rijneveld
6 Public domain.
7 */
8 
9 #include "xmss_hash_address.h"
10 #include "xmss_commons.h"
11 #include "xmss_hash.h"
12 
13 #include <stddef.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <openssl/sha.h>
18 
19 int core_hash_SHA2(unsigned char *, const unsigned int, const unsigned char *,
20     unsigned int, const unsigned char *, unsigned long long, unsigned int);
21 
addr_to_byte(unsigned char * bytes,const uint32_t addr[8])22 unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]){
23 #if IS_LITTLE_ENDIAN==1
24   int i = 0;
25   for(i=0;i<8;i++)
26     to_byte(bytes+i*4, addr[i],4);
27   return bytes;
28 #else
29   memcpy(bytes, addr, 32);
30   return bytes;
31 #endif
32 }
33 
core_hash_SHA2(unsigned char * out,const unsigned int type,const unsigned char * key,unsigned int keylen,const unsigned char * in,unsigned long long inlen,unsigned int n)34 int core_hash_SHA2(unsigned char *out, const unsigned int type, const unsigned char *key, unsigned int keylen, const unsigned char *in, unsigned long long inlen, unsigned int n){
35   unsigned long long i = 0;
36   unsigned char buf[inlen + n + keylen];
37 
38   // Input is (toByte(X, 32) || KEY || M)
39 
40   // set toByte
41   to_byte(buf, type, n);
42 
43   for (i=0; i < keylen; i++) {
44     buf[i+n] = key[i];
45   }
46 
47   for (i=0; i < inlen; i++) {
48     buf[keylen + n + i] = in[i];
49   }
50 
51   if (n == 32) {
52     SHA256(buf, inlen + keylen + n, out);
53     return 0;
54   }
55   else {
56     if (n == 64) {
57       SHA512(buf, inlen + keylen + n, out);
58       return 0;
59     }
60   }
61   return 1;
62 }
63 
64 /**
65  * Implements PRF
66  */
prf(unsigned char * out,const unsigned char * in,const unsigned char * key,unsigned int keylen)67 int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen)
68 {
69   return core_hash_SHA2(out, 3, key, keylen, in, 32, keylen);
70 }
71 
72 /*
73  * Implements H_msg
74  */
h_msg(unsigned char * out,const unsigned char * in,unsigned long long inlen,const unsigned char * key,const unsigned int keylen,const unsigned int n)75 int h_msg(unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *key, const unsigned int keylen, const unsigned int n)
76 {
77   if (keylen != 3*n){
78     // H_msg takes 3n-bit keys, but n does not match the keylength of keylen
79     return -1;
80   }
81   return core_hash_SHA2(out, 2, key, keylen, in, inlen, n);
82 }
83 
84 /**
85  * We assume the left half is in in[0]...in[n-1]
86  */
hash_h(unsigned char * out,const unsigned char * in,const unsigned char * pub_seed,uint32_t addr[8],const unsigned int n)87 int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n)
88 {
89 
90   unsigned char buf[2*n];
91   unsigned char key[n];
92   unsigned char bitmask[2*n];
93   unsigned char byte_addr[32];
94   unsigned int i;
95 
96   setKeyAndMask(addr, 0);
97   addr_to_byte(byte_addr, addr);
98   prf(key, byte_addr, pub_seed, n);
99   // Use MSB order
100   setKeyAndMask(addr, 1);
101   addr_to_byte(byte_addr, addr);
102   prf(bitmask, byte_addr, pub_seed, n);
103   setKeyAndMask(addr, 2);
104   addr_to_byte(byte_addr, addr);
105   prf(bitmask+n, byte_addr, pub_seed, n);
106   for (i = 0; i < 2*n; i++) {
107     buf[i] = in[i] ^ bitmask[i];
108   }
109   return core_hash_SHA2(out, 1, key, n, buf, 2*n, n);
110 }
111 
hash_f(unsigned char * out,const unsigned char * in,const unsigned char * pub_seed,uint32_t addr[8],const unsigned int n)112 int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n)
113 {
114   unsigned char buf[n];
115   unsigned char key[n];
116   unsigned char bitmask[n];
117   unsigned char byte_addr[32];
118   unsigned int i;
119 
120   setKeyAndMask(addr, 0);
121   addr_to_byte(byte_addr, addr);
122   prf(key, byte_addr, pub_seed, n);
123 
124   setKeyAndMask(addr, 1);
125   addr_to_byte(byte_addr, addr);
126   prf(bitmask, byte_addr, pub_seed, n);
127 
128   for (i = 0; i < n; i++) {
129     buf[i] = in[i] ^ bitmask[i];
130   }
131   return core_hash_SHA2(out, 0, key, n, buf, n, n);
132 }
133