1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 /**
5    @file s_ocb_done.c
6    OCB implementation, internal helper, by Tom St Denis
7 */
8 #include "tomcrypt_private.h"
9 
10 #ifdef LTC_OCB_MODE
11 
12 /* Since the last block is encrypted in CTR mode the same code can
13  * be used to finish a decrypt or encrypt stream.  The only difference
14  * is we XOR the final ciphertext into the checksum so we have to xor it
15  * before we CTR [decrypt] or after [encrypt]
16  *
17  * the names pt/ptlen/ct really just mean in/inlen/out but this is the way I wrote it...
18  */
19 
20 /**
21    Shared code to finish an OCB stream
22    @param ocb    The OCB state
23    @param pt     The remaining plaintext [or input]
24    @param ptlen  The length of the input (octets)
25    @param ct     [out] The output buffer
26    @param tag    [out] The destination for the authentication tag
27    @param taglen [in/out] The max size and resulting size of the authentication tag
28    @param mode   The mode we are terminating, 0==encrypt, 1==decrypt
29    @return       CRYPT_OK if successful
30 */
s_ocb_done(ocb_state * ocb,const unsigned char * pt,unsigned long ptlen,unsigned char * ct,unsigned char * tag,unsigned long * taglen,int mode)31 int s_ocb_done(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen,
32                unsigned char *ct, unsigned char *tag, unsigned long *taglen, int mode)
33 
34 {
35    unsigned char *Z, *Y, *X;
36    int err, x;
37 
38    LTC_ARGCHK(ocb    != NULL);
39    LTC_ARGCHK(pt     != NULL);
40    LTC_ARGCHK(ct     != NULL);
41    LTC_ARGCHK(tag    != NULL);
42    LTC_ARGCHK(taglen != NULL);
43    if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
44       return err;
45    }
46    if (ocb->block_len != cipher_descriptor[ocb->cipher]->block_length ||
47        (int)ptlen > ocb->block_len || (int)ptlen < 0) {
48       return CRYPT_INVALID_ARG;
49    }
50 
51    /* allocate ram */
52    Z = XMALLOC(MAXBLOCKSIZE);
53    Y = XMALLOC(MAXBLOCKSIZE);
54    X = XMALLOC(MAXBLOCKSIZE);
55    if (X == NULL || Y == NULL || Z == NULL) {
56       if (X != NULL) {
57          XFREE(X);
58       }
59       if (Y != NULL) {
60          XFREE(Y);
61       }
62       if (Z != NULL) {
63          XFREE(Z);
64       }
65       return CRYPT_MEM;
66    }
67 
68    /* compute X[m] = len(pt[m]) XOR Lr XOR Z[m] */
69    ocb_shift_xor(ocb, X);
70    XMEMCPY(Z, X, ocb->block_len);
71 
72    X[ocb->block_len-1] ^= (ptlen*8)&255;
73    X[ocb->block_len-2] ^= ((ptlen*8)>>8)&255;
74    for (x = 0; x < ocb->block_len; x++) {
75        X[x] ^= ocb->Lr[x];
76    }
77 
78    /* Y[m] = E(X[m])) */
79    if ((err = cipher_descriptor[ocb->cipher]->ecb_encrypt(X, Y, &ocb->key)) != CRYPT_OK) {
80       goto error;
81    }
82 
83    if (mode == 1) {
84       /* decrypt mode, so let's xor it first */
85       /* xor C[m] into checksum */
86       for (x = 0; x < (int)ptlen; x++) {
87          ocb->checksum[x] ^= ct[x];
88       }
89    }
90 
91    /* C[m] = P[m] xor Y[m] */
92    for (x = 0; x < (int)ptlen; x++) {
93        ct[x] = pt[x] ^ Y[x];
94    }
95 
96    if (mode == 0) {
97       /* encrypt mode */
98       /* xor C[m] into checksum */
99       for (x = 0; x < (int)ptlen; x++) {
100           ocb->checksum[x] ^= ct[x];
101       }
102    }
103 
104    /* xor Y[m] and Z[m] into checksum */
105    for (x = 0; x < ocb->block_len; x++) {
106        ocb->checksum[x] ^= Y[x] ^ Z[x];
107    }
108 
109    /* encrypt checksum, er... tag!! */
110    if ((err = cipher_descriptor[ocb->cipher]->ecb_encrypt(ocb->checksum, X, &ocb->key)) != CRYPT_OK) {
111       goto error;
112    }
113    cipher_descriptor[ocb->cipher]->done(&ocb->key);
114 
115    /* now store it */
116    for (x = 0; x < ocb->block_len && x < (int)*taglen; x++) {
117        tag[x] = X[x];
118    }
119    *taglen = x;
120 
121 #ifdef LTC_CLEAN_STACK
122    zeromem(X, MAXBLOCKSIZE);
123    zeromem(Y, MAXBLOCKSIZE);
124    zeromem(Z, MAXBLOCKSIZE);
125    zeromem(ocb, sizeof(*ocb));
126 #endif
127 error:
128    XFREE(X);
129    XFREE(Y);
130    XFREE(Z);
131 
132    return err;
133 }
134 
135 #endif
136 
137