Crypto IOV API per Projects/AEAD encryption API
[krb5.git] / src / lib / crypto / des / d3_aead.c
1 /*
2  * Copyright (C) 2008 by the Massachusetts Institute of Technology.
3  * Copyright 1995 by Richard P. Basch.  All Rights Reserved.
4  * Copyright 1995 by Lehman Brothers, Inc.  All Rights Reserved.
5  *
6  * Export of this software from the United States of America may
7  *   require a specific license from the United States Government.
8  *   It is the responsibility of any person or organization contemplating
9  *   export to obtain such a license before exporting.
10  * 
11  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12  * distribute this software and its documentation for any purpose and
13  * without fee is hereby granted, provided that the above copyright
14  * notice appear in all copies and that both that copyright notice and
15  * this permission notice appear in supporting documentation, and that
16  * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
17  * in advertising or publicity pertaining to distribution of the software
18  * without specific, written prior permission.  Richard P. Basch,
19  * Lehman Brothers and M.I.T. make no representations about the suitability
20  * of this software for any purpose.  It is provided "as is" without
21  * express or implied warranty.
22  */
23
24 #include "des_int.h"
25 #include "f_tables.h"
26 #include "../aead.h"
27
28 void
29 krb5int_des3_cbc_encrypt_iov(krb5_crypto_iov *data,
30                              unsigned long num_data,
31                              const mit_des_key_schedule ks1,
32                              const mit_des_key_schedule ks2,
33                              const mit_des_key_schedule ks3,
34                              mit_des_cblock ivec)
35 {
36     unsigned DES_INT32 left, right;
37     const unsigned DES_INT32 *kp1, *kp2, *kp3;
38     const unsigned char *ip;
39     unsigned char *op;
40     struct iov_block_state input_pos, output_pos;
41     unsigned char iblock[MIT_DES_BLOCK_LENGTH];
42     unsigned char oblock[MIT_DES_BLOCK_LENGTH];
43
44     IOV_BLOCK_STATE_INIT(&input_pos);
45     IOV_BLOCK_STATE_INIT(&output_pos);
46
47     /*
48      * Get key pointer here.  This won't need to be reinitialized
49      */
50     kp1 = (const unsigned DES_INT32 *)ks1;
51     kp2 = (const unsigned DES_INT32 *)ks2;
52     kp3 = (const unsigned DES_INT32 *)ks3;
53
54     /*
55      * Initialize left and right with the contents of the initial
56      * vector.
57      */
58     if (ivec != NULL)
59         ip = ivec;
60     else
61         ip = mit_des_zeroblock;
62     GET_HALF_BLOCK(left, ip);
63     GET_HALF_BLOCK(right, ip);
64
65     /*
66      * Suitably initialized, now work the length down 8 bytes
67      * at a time.
68      */
69     for (;;) {
70         unsigned DES_INT32 temp;
71
72         ip = iblock;
73         op = oblock;
74
75         if (!krb5int_c_iov_get_block(iblock, MIT_DES_BLOCK_LENGTH, data, num_data, &input_pos))
76             break;
77
78         GET_HALF_BLOCK(temp, ip);
79         left  ^= temp;
80         GET_HALF_BLOCK(temp, ip);
81         right ^= temp;
82
83         /*
84          * Encrypt what we have
85          */
86         DES_DO_ENCRYPT(left, right, kp1);
87         DES_DO_DECRYPT(left, right, kp2);
88         DES_DO_ENCRYPT(left, right, kp3);
89
90         /*
91          * Copy the results out
92          */
93         PUT_HALF_BLOCK(left, op);
94         PUT_HALF_BLOCK(right, op);
95
96         krb5int_c_iov_put_block(data, num_data, oblock, MIT_DES_BLOCK_LENGTH, &output_pos);
97     }
98
99     if (ivec != NULL)
100         memcpy(ivec, oblock, MIT_DES_BLOCK_LENGTH);
101 }
102
103 void
104 krb5int_des3_cbc_decrypt_iov(krb5_crypto_iov *data,
105                              unsigned long num_data,
106                              const mit_des_key_schedule ks1,
107                              const mit_des_key_schedule ks2,
108                              const mit_des_key_schedule ks3,
109                              mit_des_cblock ivec)
110 {
111     unsigned DES_INT32 left, right;
112     const unsigned DES_INT32 *kp1, *kp2, *kp3;
113     const unsigned char *ip;
114     unsigned DES_INT32 ocipherl, ocipherr;
115     unsigned DES_INT32 cipherl, cipherr;
116     unsigned char *op;
117     struct iov_block_state input_pos, output_pos;
118     unsigned char iblock[MIT_DES_BLOCK_LENGTH];
119     unsigned char oblock[MIT_DES_BLOCK_LENGTH];
120
121     IOV_BLOCK_STATE_INIT(&input_pos);
122     IOV_BLOCK_STATE_INIT(&output_pos);
123
124     /*
125      * Get key pointer here.  This won't need to be reinitialized
126      */
127     kp1 = (const unsigned DES_INT32 *)ks1;
128     kp2 = (const unsigned DES_INT32 *)ks2;
129     kp3 = (const unsigned DES_INT32 *)ks3;
130
131     /*
132      * Decrypting is harder than encrypting because of
133      * the necessity of remembering a lot more things.
134      * Should think about this a little more...
135      */
136
137     if (num_data == 0)
138         return;
139
140     /*
141      * Prime the old cipher with ivec.
142      */
143     if (ivec != NULL)
144         ip = ivec;
145     else
146         ip = mit_des_zeroblock;
147     GET_HALF_BLOCK(ocipherl, ip);
148     GET_HALF_BLOCK(ocipherr, ip);
149
150     /*
151      * Now do this in earnest until we run out of length.
152      */
153     for (;;) {
154         /*
155          * Read a block from the input into left and
156          * right.  Save this cipher block for later.
157          */
158
159         if (!krb5int_c_iov_get_block(iblock, MIT_DES_BLOCK_LENGTH, data, num_data, &input_pos))
160             break;
161
162         ip = iblock;
163         op = oblock;
164
165         GET_HALF_BLOCK(left, ip);
166         GET_HALF_BLOCK(right, ip);
167         cipherl = left;
168         cipherr = right;
169
170         /*
171          * Decrypt this.
172          */
173         DES_DO_DECRYPT(left, right, kp3);
174         DES_DO_ENCRYPT(left, right, kp2);
175         DES_DO_DECRYPT(left, right, kp1);
176
177         /*
178          * Xor with the old cipher to get plain
179          * text.  Output 8 or less bytes of this.
180          */
181         left ^= ocipherl;
182         right ^= ocipherr;
183
184         PUT_HALF_BLOCK(left, op);
185         PUT_HALF_BLOCK(right, op);
186
187         /*
188          * Save current cipher block here
189          */
190         ocipherl = cipherl;
191         ocipherr = cipherr;
192
193         krb5int_c_iov_put_block(data, num_data, oblock, MIT_DES_BLOCK_LENGTH, &output_pos);
194     }
195
196     if (ivec != NULL)
197         memcpy(ivec, oblock, MIT_DES_BLOCK_LENGTH);
198 }