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 
11 /**
12    @file ocb_init.c
13    OCB implementation, initialize state, by Tom St Denis
14 */
15 #include "tomcrypt_private.h"
16 
17 #ifdef LTC_OCB_MODE
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 an OCB context.
39   @param ocb     [out] The destination of the OCB state
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   @param nonce   The session nonce (length of the block size of the cipher)
44   @return CRYPT_OK if successful
45 */
ocb_init(ocb_state * ocb,int cipher,const unsigned char * key,unsigned long keylen,const unsigned char * nonce)46 int ocb_init(ocb_state *ocb, int cipher,
47              const unsigned char *key, unsigned long keylen, const unsigned char *nonce)
48 {
49    int poly, x, y, m, err;
50 
51    LTC_ARGCHK(ocb   != NULL);
52    LTC_ARGCHK(key   != NULL);
53    LTC_ARGCHK(nonce != NULL);
54 
55    /* valid cipher? */
56    if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
57       return err;
58    }
59 
60    /* determine which polys to use */
61    ocb->block_len = cipher_descriptor[cipher]->block_length;
62    x = (int)(sizeof(polys)/sizeof(polys[0]));
63    for (poly = 0; poly < x; poly++) {
64        if (polys[poly].len == ocb->block_len) {
65           break;
66        }
67    }
68    if (poly == x) {
69       return CRYPT_INVALID_ARG; /* block_len not found in polys */
70    }
71    if (polys[poly].len != ocb->block_len) {
72       return CRYPT_INVALID_ARG;
73    }
74 
75    /* schedule the key */
76    if ((err = cipher_descriptor[cipher]->setup(key, keylen, 0, &ocb->key)) != CRYPT_OK) {
77       return err;
78    }
79 
80    /* find L = E[0] */
81    zeromem(ocb->L, ocb->block_len);
82    if ((err = cipher_descriptor[cipher]->ecb_encrypt(ocb->L, ocb->L, &ocb->key)) != CRYPT_OK) {
83       return err;
84    }
85 
86    /* find R = E[N xor L] */
87    for (x = 0; x < ocb->block_len; x++) {
88        ocb->R[x] = ocb->L[x] ^ nonce[x];
89    }
90    if ((err = cipher_descriptor[cipher]->ecb_encrypt(ocb->R, ocb->R, &ocb->key)) != CRYPT_OK) {
91       return err;
92    }
93 
94    /* find Ls[i] = L << i for i == 0..31 */
95    XMEMCPY(ocb->Ls[0], ocb->L, ocb->block_len);
96    for (x = 1; x < 32; x++) {
97        m = ocb->Ls[x-1][0] >> 7;
98        for (y = 0; y < ocb->block_len-1; y++) {
99            ocb->Ls[x][y] = ((ocb->Ls[x-1][y] << 1) | (ocb->Ls[x-1][y+1] >> 7)) & 255;
100        }
101        ocb->Ls[x][ocb->block_len-1] = (ocb->Ls[x-1][ocb->block_len-1] << 1) & 255;
102 
103        if (m == 1) {
104           for (y = 0; y < ocb->block_len; y++) {
105               ocb->Ls[x][y] ^= polys[poly].poly_mul[y];
106           }
107        }
108    }
109 
110    /* find Lr = L / x */
111    m = ocb->L[ocb->block_len-1] & 1;
112 
113    /* shift right */
114    for (x = ocb->block_len - 1; x > 0; x--) {
115       ocb->Lr[x] = ((ocb->L[x] >> 1) | (ocb->L[x-1] << 7)) & 255;
116    }
117    ocb->Lr[0] = ocb->L[0] >> 1;
118 
119    if (m == 1) {
120       for (x = 0; x < ocb->block_len; x++) {
121          ocb->Lr[x] ^= polys[poly].poly_div[x];
122       }
123    }
124 
125    /* set Li, checksum */
126    zeromem(ocb->Li,       ocb->block_len);
127    zeromem(ocb->checksum, ocb->block_len);
128 
129    /* set other params */
130    ocb->block_index = 1;
131    ocb->cipher      = cipher;
132 
133    return CRYPT_OK;
134 }
135 
136 #endif
137 
138 /* ref:         $Format:%D$ */
139 /* git commit:  $Format:%H$ */
140 /* commit time: $Format:%ai$ */
141