1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4
5 /**
6 @file pmac_init.c
7 PMAC implementation, initialize state, by Tom St Denis
8 */
9
10 #ifdef LTC_PMAC
11
12 static const struct {
13 int len;
14 unsigned char poly_div[MAXBLOCKSIZE],
15 poly_mul[MAXBLOCKSIZE];
16 } polys[] = {
17 {
18 8,
19 { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D },
20 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B }
21 }, {
22 16,
23 { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 },
25 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 }
27 }
28 };
29
30 /**
31 Initialize a PMAC state
32 @param pmac The PMAC state to initialize
33 @param cipher The index of the desired cipher
34 @param key The secret key
35 @param keylen The length of the secret key (octets)
36 @return CRYPT_OK if successful
37 */
pmac_init(pmac_state * pmac,int cipher,const unsigned char * key,unsigned long keylen)38 int pmac_init(pmac_state *pmac, int cipher, const unsigned char *key, unsigned long keylen)
39 {
40 int poly, x, y, m, err;
41 unsigned char *L;
42
43 LTC_ARGCHK(pmac != NULL);
44 LTC_ARGCHK(key != NULL);
45
46 /* valid cipher? */
47 if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
48 return err;
49 }
50
51 /* determine which polys to use */
52 pmac->block_len = cipher_descriptor[cipher]->block_length;
53 for (poly = 0; poly < (int)(sizeof(polys)/sizeof(polys[0])); poly++) {
54 if (polys[poly].len == pmac->block_len) {
55 break;
56 }
57 }
58 if (poly >= (int)(sizeof(polys)/sizeof(polys[0]))) {
59 return CRYPT_INVALID_ARG;
60 }
61 if (polys[poly].len != pmac->block_len) {
62 return CRYPT_INVALID_ARG;
63 }
64
65 #ifdef LTC_FAST
66 if (pmac->block_len % sizeof(LTC_FAST_TYPE)) {
67 return CRYPT_INVALID_ARG;
68 }
69 #endif
70
71
72 /* schedule the key */
73 if ((err = cipher_descriptor[cipher]->setup(key, keylen, 0, &pmac->key)) != CRYPT_OK) {
74 return err;
75 }
76
77 /* allocate L */
78 L = XMALLOC(pmac->block_len);
79 if (L == NULL) {
80 return CRYPT_MEM;
81 }
82
83 /* find L = E[0] */
84 zeromem(L, pmac->block_len);
85 if ((err = cipher_descriptor[cipher]->ecb_encrypt(L, L, &pmac->key)) != CRYPT_OK) {
86 goto error;
87 }
88
89 /* find Ls[i] = L << i for i == 0..31 */
90 XMEMCPY(pmac->Ls[0], L, pmac->block_len);
91 for (x = 1; x < 32; x++) {
92 m = pmac->Ls[x-1][0] >> 7;
93 for (y = 0; y < pmac->block_len-1; y++) {
94 pmac->Ls[x][y] = ((pmac->Ls[x-1][y] << 1) | (pmac->Ls[x-1][y+1] >> 7)) & 255;
95 }
96 pmac->Ls[x][pmac->block_len-1] = (pmac->Ls[x-1][pmac->block_len-1] << 1) & 255;
97
98 if (m == 1) {
99 for (y = 0; y < pmac->block_len; y++) {
100 pmac->Ls[x][y] ^= polys[poly].poly_mul[y];
101 }
102 }
103 }
104
105 /* find Lr = L / x */
106 m = L[pmac->block_len-1] & 1;
107
108 /* shift right */
109 for (x = pmac->block_len - 1; x > 0; x--) {
110 pmac->Lr[x] = ((L[x] >> 1) | (L[x-1] << 7)) & 255;
111 }
112 pmac->Lr[0] = L[0] >> 1;
113
114 if (m == 1) {
115 for (x = 0; x < pmac->block_len; x++) {
116 pmac->Lr[x] ^= polys[poly].poly_div[x];
117 }
118 }
119
120 /* zero buffer, counters, etc... */
121 pmac->block_index = 1;
122 pmac->cipher_idx = cipher;
123 pmac->buflen = 0;
124 zeromem(pmac->block, sizeof(pmac->block));
125 zeromem(pmac->Li, sizeof(pmac->Li));
126 zeromem(pmac->checksum, sizeof(pmac->checksum));
127 err = CRYPT_OK;
128 error:
129 #ifdef LTC_CLEAN_STACK
130 zeromem(L, pmac->block_len);
131 #endif
132
133 XFREE(L);
134
135 return err;
136 }
137
138 #endif
139