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