summaryrefslogtreecommitdiffstats
path: root/storage/maria/libmarias3/src/sha256.c
blob: 8a28f906ea58683e060f03de9b92d446ed84581d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * SHA-256 hash implementation and interface functions
 * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
 *
 * This software may be distributed under the terms of the BSD license.
 * See README for more details.
 */

#include "sha256.h"
#include "sha256_i.h"

/**
 * sha256 - SHA256 hash for data vector
 * @num_elem: Number of elements in the data vector
 * @addr: Pointer to the data areas
 * @len: Length of the data blocks
 * @mac: Buffer for the hash
 * Returns: 0 on success, -1 of failure
 */
int sha256(const uint8_t *addr, const size_t len, uint8_t *mac)
{
  struct sha256_state ctx;

  sha256_init(&ctx);

  if (sha256_process(&ctx, addr, len))
    return -1;

  if (sha256_done(&ctx, mac))
    return -1;

  return 0;
}

/**
 * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104)
 * @key: Key for HMAC operations
 * @key_len: Length of the key in bytes
 * @num_elem: Number of elements in the data vector
 * @addr: Pointers to the data areas
 * @len: Lengths of the data blocks
 * @mac: Buffer for the hash (32 bytes)
 * Returns: 0 on success, -1 on failure
 */
int hmac_sha256_vector(const uint8_t *key, size_t key_len, size_t num_elem,
                       const uint8_t *addr[], const size_t *len, uint8_t *mac)
{
  unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
  unsigned char tk[32];
  const uint8_t *_addr[6];
  size_t _len[6], i;

  if (num_elem > 5)
  {
    /*
     * Fixed limit on the number of fragments to avoid having to
     * allocate memory (which could fail).
     */
    return -1;
  }

  /* if key is longer than 64 bytes reset it to key = SHA256(key) */
  if (key_len > 64)
  {
    if (sha256_vector(1, &key, &key_len, tk) < 0)
      return -1;

    key = tk;
    key_len = 32;
  }

  /* the HMAC_SHA256 transform looks like:
   *
   * SHA256(K XOR opad, SHA256(K XOR ipad, text))
   *
   * where K is an n byte key
   * ipad is the byte 0x36 repeated 64 times
   * opad is the byte 0x5c repeated 64 times
   * and text is the data being protected */

  /* start out by storing key in ipad */
  memset(k_pad, 0, sizeof(k_pad));
  memcpy(k_pad, key, key_len);

  /* XOR key with ipad values */
  for (i = 0; i < 64; i++)
    k_pad[i] ^= 0x36;

  /* perform inner SHA256 */
  _addr[0] = k_pad;
  _len[0] = 64;

  for (i = 0; i < num_elem; i++)
  {
    _addr[i + 1] = addr[i];
    _len[i + 1] = len[i];
  }

  if (sha256_vector(1 + num_elem, _addr, _len, mac) < 0)
    return -1;

  memset(k_pad, 0, sizeof(k_pad));
  memcpy(k_pad, key, key_len);

  /* XOR key with opad values */
  for (i = 0; i < 64; i++)
    k_pad[i] ^= 0x5c;

  /* perform outer SHA256 */
  _addr[0] = k_pad;
  _len[0] = 64;
  _addr[1] = mac;
  _len[1] = SHA256_MAC_LEN;
  return sha256_vector(2, _addr, _len, mac);
}


/**
 * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104)
 * @key: Key for HMAC operations
 * @key_len: Length of the key in bytes
 * @data: Pointers to the data area
 * @data_len: Length of the data area
 * @mac: Buffer for the hash (32 bytes)
 * Returns: 0 on success, -1 on failure
 */
int hmac_sha256(const uint8_t *key, size_t key_len, const uint8_t *data,
                size_t data_len, uint8_t *mac)
{
  return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
}