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