1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6    @file pelican.c
7    Pelican MAC, initialize state, by Tom St Denis
8 */
9 
10 #ifdef LTC_PELICAN
11 
12 #define LTC_AES_TAB_C
13 #define ENCRYPT_ONLY
14 #define PELI_TAB
15 #include "../../ciphers/aes/aes_tab.c"
16 
17 /**
18    Initialize a Pelican state
19    @param pelmac    The Pelican state to initialize
20    @param key       The secret key
21    @param keylen    The length of the secret key (octets)
22    @return CRYPT_OK if successful
23 */
pelican_init(pelican_state * pelmac,const unsigned char * key,unsigned long keylen)24 int pelican_init(pelican_state *pelmac, const unsigned char *key, unsigned long keylen)
25 {
26     int err;
27 
28     LTC_ARGCHK(pelmac != NULL);
29     LTC_ARGCHK(key    != NULL);
30 
31 #ifdef LTC_FAST
32     if (16 % sizeof(LTC_FAST_TYPE)) {
33         return CRYPT_INVALID_ARG;
34     }
35 #endif
36 
37     if ((err = aes_setup(key, keylen, 0, &pelmac->K)) != CRYPT_OK) {
38        return err;
39     }
40 
41     zeromem(pelmac->state, 16);
42     aes_ecb_encrypt(pelmac->state, pelmac->state, &pelmac->K);
43     pelmac->buflen = 0;
44 
45     return CRYPT_OK;
46 }
47 
s_four_rounds(pelican_state * pelmac)48 static void s_four_rounds(pelican_state *pelmac)
49 {
50     ulong32 s0, s1, s2, s3, t0, t1, t2, t3;
51     int r;
52 
53     LOAD32H(s0, pelmac->state      );
54     LOAD32H(s1, pelmac->state  +  4);
55     LOAD32H(s2, pelmac->state  +  8);
56     LOAD32H(s3, pelmac->state  + 12);
57     for (r = 0; r < 4; r++) {
58         t0 =
59             Te0(LTC_BYTE(s0, 3)) ^
60             Te1(LTC_BYTE(s1, 2)) ^
61             Te2(LTC_BYTE(s2, 1)) ^
62             Te3(LTC_BYTE(s3, 0));
63         t1 =
64             Te0(LTC_BYTE(s1, 3)) ^
65             Te1(LTC_BYTE(s2, 2)) ^
66             Te2(LTC_BYTE(s3, 1)) ^
67             Te3(LTC_BYTE(s0, 0));
68         t2 =
69             Te0(LTC_BYTE(s2, 3)) ^
70             Te1(LTC_BYTE(s3, 2)) ^
71             Te2(LTC_BYTE(s0, 1)) ^
72             Te3(LTC_BYTE(s1, 0));
73         t3 =
74             Te0(LTC_BYTE(s3, 3)) ^
75             Te1(LTC_BYTE(s0, 2)) ^
76             Te2(LTC_BYTE(s1, 1)) ^
77             Te3(LTC_BYTE(s2, 0));
78         s0 = t0; s1 = t1; s2 = t2; s3 = t3;
79     }
80     STORE32H(s0, pelmac->state      );
81     STORE32H(s1, pelmac->state  +  4);
82     STORE32H(s2, pelmac->state  +  8);
83     STORE32H(s3, pelmac->state  + 12);
84 }
85 
86 /**
87   Process a block of text through Pelican
88   @param pelmac       The Pelican MAC state
89   @param in           The input
90   @param inlen        The length input (octets)
91   @return CRYPT_OK on success
92   */
pelican_process(pelican_state * pelmac,const unsigned char * in,unsigned long inlen)93 int pelican_process(pelican_state *pelmac, const unsigned char *in, unsigned long inlen)
94 {
95 
96    LTC_ARGCHK(pelmac != NULL);
97    LTC_ARGCHK(in     != NULL);
98 
99    /* check range */
100    if (pelmac->buflen < 0 || pelmac->buflen > 15) {
101       return CRYPT_INVALID_ARG;
102    }
103 
104 #ifdef LTC_FAST
105    if (pelmac->buflen == 0) {
106       while (inlen & ~15) {
107          int x;
108          for (x = 0; x < 16; x += sizeof(LTC_FAST_TYPE)) {
109             *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)pelmac->state + x)) ^= *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)in + x));
110          }
111          s_four_rounds(pelmac);
112          in    += 16;
113          inlen -= 16;
114       }
115    }
116 #endif
117 
118    while (inlen--) {
119        pelmac->state[pelmac->buflen++] ^= *in++;
120        if (pelmac->buflen == 16) {
121           s_four_rounds(pelmac);
122           pelmac->buflen = 0;
123        }
124    }
125    return CRYPT_OK;
126 }
127 
128 /**
129   Terminate Pelican MAC
130   @param pelmac      The Pelican MAC state
131   @param out         [out] The TAG
132   @return CRYPT_OK on sucess
133 */
pelican_done(pelican_state * pelmac,unsigned char * out)134 int pelican_done(pelican_state *pelmac, unsigned char *out)
135 {
136    LTC_ARGCHK(pelmac  != NULL);
137    LTC_ARGCHK(out     != NULL);
138 
139    /* check range */
140    if (pelmac->buflen < 0 || pelmac->buflen > 16) {
141       return CRYPT_INVALID_ARG;
142    }
143 
144    if  (pelmac->buflen == 16) {
145        s_four_rounds(pelmac);
146        pelmac->buflen = 0;
147    }
148    pelmac->state[pelmac->buflen++] ^= 0x80;
149    aes_ecb_encrypt(pelmac->state, out, &pelmac->K);
150    aes_done(&pelmac->K);
151    return CRYPT_OK;
152 }
153 
154 #endif
155