1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 /**
5    @file ocb3_init.c
6    OCB implementation, initialize state, by Tom St Denis
7 */
8 #include "tomcrypt_private.h"
9 
10 #ifdef LTC_OCB3_MODE
11 
s_ocb3_int_calc_offset_zero(ocb3_state * ocb,const unsigned char * nonce,unsigned long noncelen,unsigned long taglen)12 static void s_ocb3_int_calc_offset_zero(ocb3_state *ocb, const unsigned char *nonce, unsigned long noncelen, unsigned long taglen)
13 {
14    int x, y, bottom;
15    int idx, shift;
16    unsigned char iNonce[MAXBLOCKSIZE];
17    unsigned char iKtop[MAXBLOCKSIZE];
18    unsigned char iStretch[MAXBLOCKSIZE+8];
19 
20    /* Nonce = zeros(127-bitlen(N)) || 1 || N          */
21    zeromem(iNonce, sizeof(iNonce));
22    for (x = ocb->block_len-1, y=0; y<(int)noncelen; x--, y++) {
23      iNonce[x] = nonce[noncelen-y-1];
24    }
25    iNonce[x] = 0x01;
26    iNonce[0] |= ((taglen*8) % 128) << 1;
27 
28    /* bottom = str2num(Nonce[123..128])               */
29    bottom = iNonce[ocb->block_len-1] & 0x3F;
30 
31    /* Ktop = ENCIPHER(K, Nonce[1..122] || zeros(6))   */
32    iNonce[ocb->block_len-1] = iNonce[ocb->block_len-1] & 0xC0;
33    if ((cipher_descriptor[ocb->cipher]->ecb_encrypt(iNonce, iKtop, &ocb->key)) != CRYPT_OK) {
34       zeromem(ocb->Offset_current, ocb->block_len);
35       return;
36    }
37 
38    /* Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72]) */
39    for (x = 0; x < ocb->block_len; x++) {
40      iStretch[x] = iKtop[x];
41    }
42    for (y = 0; y < 8; y++) {
43      iStretch[x+y] = iKtop[y] ^ iKtop[y+1];
44    }
45 
46    /* Offset_0 = Stretch[1+bottom..128+bottom]        */
47    idx = bottom / 8;
48    shift = (bottom % 8);
49    for (x = 0; x < ocb->block_len; x++) {
50       ocb->Offset_current[x] = iStretch[idx+x] << shift;
51       if (shift > 0) {
52         ocb->Offset_current[x] |= iStretch[idx+x+1] >> (8-shift);
53       }
54    }
55 }
56 
57 static const struct {
58     int           len;
59     unsigned char poly_mul[MAXBLOCKSIZE];
60 } polys[] = {
61 {
62     8,
63     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B }
64 }, {
65     16,
66     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 }
68 }
69 };
70 
71 /**
72    Initialize an OCB context
73    @param ocb       [out] The destination of the OCB state
74    @param cipher    The index of the desired cipher
75    @param key       The secret key
76    @param keylen    The length of the secret key (octets)
77    @param nonce     The session nonce
78    @param noncelen  The length of the session nonce (octets, up to 15)
79    @param taglen    The length of the tag (octets, up to 16)
80    @return CRYPT_OK if successful
81 */
ocb3_init(ocb3_state * ocb,int cipher,const unsigned char * key,unsigned long keylen,const unsigned char * nonce,unsigned long noncelen,unsigned long taglen)82 int ocb3_init(ocb3_state *ocb, int cipher,
83              const unsigned char *key, unsigned long keylen,
84              const unsigned char *nonce, unsigned long noncelen,
85              unsigned long taglen)
86 {
87    int poly, x, y, m, err;
88    unsigned char *previous, *current;
89 
90    LTC_ARGCHK(ocb   != NULL);
91    LTC_ARGCHK(key   != NULL);
92    LTC_ARGCHK(nonce != NULL);
93 
94    /* valid cipher? */
95    if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
96       return err;
97    }
98    ocb->cipher = cipher;
99 
100    /* Valid Nonce?
101     * As of RFC7253: "string of no more than 120 bits" */
102    if (noncelen > (120/8)) {
103       return CRYPT_INVALID_ARG;
104    }
105 
106    /* The blockcipher must have a 128-bit blocksize */
107    if (cipher_descriptor[cipher]->block_length != 16) {
108       return CRYPT_INVALID_ARG;
109    }
110 
111    /* The TAGLEN may be any value up to 128 (bits) */
112    if (taglen > 16) {
113       return CRYPT_INVALID_ARG;
114    }
115    ocb->tag_len = taglen;
116 
117    /* determine which polys to use */
118    ocb->block_len = cipher_descriptor[cipher]->block_length;
119    x = (int)(sizeof(polys)/sizeof(polys[0]));
120    for (poly = 0; poly < x; poly++) {
121        if (polys[poly].len == ocb->block_len) {
122           break;
123        }
124    }
125    if (poly == x) {
126       return CRYPT_INVALID_ARG; /* block_len not found in polys */
127    }
128    if (polys[poly].len != ocb->block_len) {
129       return CRYPT_INVALID_ARG;
130    }
131 
132    /* schedule the key */
133    if ((err = cipher_descriptor[cipher]->setup(key, keylen, 0, &ocb->key)) != CRYPT_OK) {
134       return err;
135    }
136 
137    /* L_* = ENCIPHER(K, zeros(128)) */
138    zeromem(ocb->L_star, ocb->block_len);
139    if ((err = cipher_descriptor[cipher]->ecb_encrypt(ocb->L_star, ocb->L_star, &ocb->key)) != CRYPT_OK) {
140       return err;
141    }
142 
143    /* compute L_$, L_0, L_1, ... */
144    for (x = -1; x < 32; x++) {
145       if (x == -1) {                /* gonna compute: L_$ = double(L_*) */
146          current  = ocb->L_dollar;
147          previous = ocb->L_star;
148       }
149       else if (x == 0) {            /* gonna compute: L_0 = double(L_$) */
150          current  = ocb->L_[0];
151          previous = ocb->L_dollar;
152       }
153       else {                        /* gonna compute: L_i = double(L_{i-1}) for every integer i > 0 */
154          current  = ocb->L_[x];
155          previous = ocb->L_[x-1];
156       }
157       m = previous[0] >> 7;
158       for (y = 0; y < ocb->block_len-1; y++) {
159          current[y] = ((previous[y] << 1) | (previous[y+1] >> 7)) & 255;
160       }
161       current[ocb->block_len-1] = (previous[ocb->block_len-1] << 1) & 255;
162       if (m == 1) {
163          /* current[] = current[] XOR polys[poly].poly_mul[]*/
164          ocb3_int_xor_blocks(current, current, polys[poly].poly_mul, ocb->block_len);
165       }
166    }
167 
168    /* initialize ocb->Offset_current = Offset_0 */
169    s_ocb3_int_calc_offset_zero(ocb, nonce, noncelen, taglen);
170 
171    /* initialize checksum to all zeros */
172    zeromem(ocb->checksum, ocb->block_len);
173 
174    /* set block index */
175    ocb->block_index = 1;
176 
177    /* initialize AAD related stuff */
178    ocb->ablock_index = 1;
179    ocb->adata_buffer_bytes = 0;
180    zeromem(ocb->aOffset_current, ocb->block_len);
181    zeromem(ocb->aSum_current, ocb->block_len);
182 
183    return CRYPT_OK;
184 }
185 
186 #endif
187