2 * Copyright (c) 1995 - 2000, 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "rxkad_locl.h"
38 * this assumes that KRB_C_BIGENDIAN is used.
39 * if we can find out endianess at compile-time, do so,
40 * otherwise WORDS_BIGENDIAN should already have been defined
43 #if ENDIANESS_IN_SYS_PARAM_H
44 # undef WORDS_BIGENDIAN
45 # include <sys/types.h>
46 # include <sys/param.h>
47 # if BYTE_ORDER == BIG_ENDIAN
48 # define WORDS_BIGENDIAN 1
49 # elif BYTE_ORDER == LITTLE_ENDIAN
52 # error where do you cut your eggs?
59 * Unrolling of the inner loops helps the most on pentium chips
60 * (ca 18%). On risc machines only expect a modest improvement (ca 5%).
61 * The cost for this is rougly 4k bytes.
63 #define UNROLL_LOOPS 1
65 * Inline assembler gives a boost only to fc_keysched.
66 * On the pentium expect ca 28%.
68 /*#define GNU_ASM 1 (now autoconfed) */
70 #if !defined(inline) && !defined(__GNUC__)
75 #define fc_keysched _afs_QTKrFdpoFL
76 #define fc_ecb_encrypt _afs_sDLThwNLok
77 #define fc_cbc_encrypt _afs_fkyCWTvfRS
78 #define rxkad_DecryptPacket _afs_SRWEeqTXrS
79 #define rxkad_EncryptPacket _afs_bpwQbdoghO
83 * There is usually no memcpy in kernels but gcc will inline all
84 * calls to memcpy in this code anyway.
86 #if defined(KERNEL) && !defined(__GNUC__)
87 #define memcpy(to, from, n) bcopy((from), (to), (n))
90 /* Rotate 32 bit word left */
94 #define ROT32L(x, n) ((((uint32_t) x) << (n)) | (((uint32_t) x) >> (32-(n))))
95 #define bswap32(x) (((ROT32L(x, 16) & 0x00ff00ff)<<8) | ((ROT32L(x, 16)>>8) & 0x00ff00ff))
101 #define NTOH(x) bswap32(x)
105 * Try to use a good function for ntohl-ing.
107 * The choice is done by autoconf setting EFF_NTOHL to one of:
115 #if defined(__GNUC__) && (defined(i386) || defined(__i386__))
116 static inline uint32_t
119 asm("bswap %0" : "=r" (x
) : "0" (x
));
125 * Sboxes for Feistel network derived from
126 * /afs/transarc.com/public/afsps/afs.rel31b.export-src/rxkad/sboxes.h
130 #define Z(x) NTOH(x << 3)
131 static const uint32_t sbox0
[256] = {
132 Z(0xea), Z(0x7f), Z(0xb2), Z(0x64), Z(0x9d), Z(0xb0), Z(0xd9), Z(0x11), Z(0xcd), Z(0x86), Z(0x86),
133 Z(0x91), Z(0x0a), Z(0xb2), Z(0x93), Z(0x06), Z(0x0e), Z(0x06), Z(0xd2), Z(0x65), Z(0x73), Z(0xc5),
134 Z(0x28), Z(0x60), Z(0xf2), Z(0x20), Z(0xb5), Z(0x38), Z(0x7e), Z(0xda), Z(0x9f), Z(0xe3), Z(0xd2),
135 Z(0xcf), Z(0xc4), Z(0x3c), Z(0x61), Z(0xff), Z(0x4a), Z(0x4a), Z(0x35), Z(0xac), Z(0xaa), Z(0x5f),
136 Z(0x2b), Z(0xbb), Z(0xbc), Z(0x53), Z(0x4e), Z(0x9d), Z(0x78), Z(0xa3), Z(0xdc), Z(0x09), Z(0x32),
137 Z(0x10), Z(0xc6), Z(0x6f), Z(0x66), Z(0xd6), Z(0xab), Z(0xa9), Z(0xaf), Z(0xfd), Z(0x3b), Z(0x95),
138 Z(0xe8), Z(0x34), Z(0x9a), Z(0x81), Z(0x72), Z(0x80), Z(0x9c), Z(0xf3), Z(0xec), Z(0xda), Z(0x9f),
139 Z(0x26), Z(0x76), Z(0x15), Z(0x3e), Z(0x55), Z(0x4d), Z(0xde), Z(0x84), Z(0xee), Z(0xad), Z(0xc7),
140 Z(0xf1), Z(0x6b), Z(0x3d), Z(0xd3), Z(0x04), Z(0x49), Z(0xaa), Z(0x24), Z(0x0b), Z(0x8a), Z(0x83),
141 Z(0xba), Z(0xfa), Z(0x85), Z(0xa0), Z(0xa8), Z(0xb1), Z(0xd4), Z(0x01), Z(0xd8), Z(0x70), Z(0x64),
142 Z(0xf0), Z(0x51), Z(0xd2), Z(0xc3), Z(0xa7), Z(0x75), Z(0x8c), Z(0xa5), Z(0x64), Z(0xef), Z(0x10),
143 Z(0x4e), Z(0xb7), Z(0xc6), Z(0x61), Z(0x03), Z(0xeb), Z(0x44), Z(0x3d), Z(0xe5), Z(0xb3), Z(0x5b),
144 Z(0xae), Z(0xd5), Z(0xad), Z(0x1d), Z(0xfa), Z(0x5a), Z(0x1e), Z(0x33), Z(0xab), Z(0x93), Z(0xa2),
145 Z(0xb7), Z(0xe7), Z(0xa8), Z(0x45), Z(0xa4), Z(0xcd), Z(0x29), Z(0x63), Z(0x44), Z(0xb6), Z(0x69),
146 Z(0x7e), Z(0x2e), Z(0x62), Z(0x03), Z(0xc8), Z(0xe0), Z(0x17), Z(0xbb), Z(0xc7), Z(0xf3), Z(0x3f),
147 Z(0x36), Z(0xba), Z(0x71), Z(0x8e), Z(0x97), Z(0x65), Z(0x60), Z(0x69), Z(0xb6), Z(0xf6), Z(0xe6),
148 Z(0x6e), Z(0xe0), Z(0x81), Z(0x59), Z(0xe8), Z(0xaf), Z(0xdd), Z(0x95), Z(0x22), Z(0x99), Z(0xfd),
149 Z(0x63), Z(0x19), Z(0x74), Z(0x61), Z(0xb1), Z(0xb6), Z(0x5b), Z(0xae), Z(0x54), Z(0xb3), Z(0x70),
150 Z(0xff), Z(0xc6), Z(0x3b), Z(0x3e), Z(0xc1), Z(0xd7), Z(0xe1), Z(0x0e), Z(0x76), Z(0xe5), Z(0x36),
151 Z(0x4f), Z(0x59), Z(0xc7), Z(0x08), Z(0x6e), Z(0x82), Z(0xa6), Z(0x93), Z(0xc4), Z(0xaa), Z(0x26),
152 Z(0x49), Z(0xe0), Z(0x21), Z(0x64), Z(0x07), Z(0x9f), Z(0x64), Z(0x81), Z(0x9c), Z(0xbf), Z(0xf9),
153 Z(0xd1), Z(0x43), Z(0xf8), Z(0xb6), Z(0xb9), Z(0xf1), Z(0x24), Z(0x75), Z(0x03), Z(0xe4), Z(0xb0),
154 Z(0x99), Z(0x46), Z(0x3d), Z(0xf5), Z(0xd1), Z(0x39), Z(0x72), Z(0x12), Z(0xf6), Z(0xba), Z(0x0c),
155 Z(0x0d), Z(0x42), Z(0x2e)};
158 #define Z(x) NTOH((x << 27) | (x >> 5))
159 static const uint32_t sbox1
[256] = {
160 Z(0x77), Z(0x14), Z(0xa6), Z(0xfe), Z(0xb2), Z(0x5e), Z(0x8c), Z(0x3e), Z(0x67), Z(0x6c), Z(0xa1),
161 Z(0x0d), Z(0xc2), Z(0xa2), Z(0xc1), Z(0x85), Z(0x6c), Z(0x7b), Z(0x67), Z(0xc6), Z(0x23), Z(0xe3),
162 Z(0xf2), Z(0x89), Z(0x50), Z(0x9c), Z(0x03), Z(0xb7), Z(0x73), Z(0xe6), Z(0xe1), Z(0x39), Z(0x31),
163 Z(0x2c), Z(0x27), Z(0x9f), Z(0xa5), Z(0x69), Z(0x44), Z(0xd6), Z(0x23), Z(0x83), Z(0x98), Z(0x7d),
164 Z(0x3c), Z(0xb4), Z(0x2d), Z(0x99), Z(0x1c), Z(0x1f), Z(0x8c), Z(0x20), Z(0x03), Z(0x7c), Z(0x5f),
165 Z(0xad), Z(0xf4), Z(0xfa), Z(0x95), Z(0xca), Z(0x76), Z(0x44), Z(0xcd), Z(0xb6), Z(0xb8), Z(0xa1),
166 Z(0xa1), Z(0xbe), Z(0x9e), Z(0x54), Z(0x8f), Z(0x0b), Z(0x16), Z(0x74), Z(0x31), Z(0x8a), Z(0x23),
167 Z(0x17), Z(0x04), Z(0xfa), Z(0x79), Z(0x84), Z(0xb1), Z(0xf5), Z(0x13), Z(0xab), Z(0xb5), Z(0x2e),
168 Z(0xaa), Z(0x0c), Z(0x60), Z(0x6b), Z(0x5b), Z(0xc4), Z(0x4b), Z(0xbc), Z(0xe2), Z(0xaf), Z(0x45),
169 Z(0x73), Z(0xfa), Z(0xc9), Z(0x49), Z(0xcd), Z(0x00), Z(0x92), Z(0x7d), Z(0x97), Z(0x7a), Z(0x18),
170 Z(0x60), Z(0x3d), Z(0xcf), Z(0x5b), Z(0xde), Z(0xc6), Z(0xe2), Z(0xe6), Z(0xbb), Z(0x8b), Z(0x06),
171 Z(0xda), Z(0x08), Z(0x15), Z(0x1b), Z(0x88), Z(0x6a), Z(0x17), Z(0x89), Z(0xd0), Z(0xa9), Z(0xc1),
172 Z(0xc9), Z(0x70), Z(0x6b), Z(0xe5), Z(0x43), Z(0xf4), Z(0x68), Z(0xc8), Z(0xd3), Z(0x84), Z(0x28),
173 Z(0x0a), Z(0x52), Z(0x66), Z(0xa3), Z(0xca), Z(0xf2), Z(0xe3), Z(0x7f), Z(0x7a), Z(0x31), Z(0xf7),
174 Z(0x88), Z(0x94), Z(0x5e), Z(0x9c), Z(0x63), Z(0xd5), Z(0x24), Z(0x66), Z(0xfc), Z(0xb3), Z(0x57),
175 Z(0x25), Z(0xbe), Z(0x89), Z(0x44), Z(0xc4), Z(0xe0), Z(0x8f), Z(0x23), Z(0x3c), Z(0x12), Z(0x52),
176 Z(0xf5), Z(0x1e), Z(0xf4), Z(0xcb), Z(0x18), Z(0x33), Z(0x1f), Z(0xf8), Z(0x69), Z(0x10), Z(0x9d),
177 Z(0xd3), Z(0xf7), Z(0x28), Z(0xf8), Z(0x30), Z(0x05), Z(0x5e), Z(0x32), Z(0xc0), Z(0xd5), Z(0x19),
178 Z(0xbd), Z(0x45), Z(0x8b), Z(0x5b), Z(0xfd), Z(0xbc), Z(0xe2), Z(0x5c), Z(0xa9), Z(0x96), Z(0xef),
179 Z(0x70), Z(0xcf), Z(0xc2), Z(0x2a), Z(0xb3), Z(0x61), Z(0xad), Z(0x80), Z(0x48), Z(0x81), Z(0xb7),
180 Z(0x1d), Z(0x43), Z(0xd9), Z(0xd7), Z(0x45), Z(0xf0), Z(0xd8), Z(0x8a), Z(0x59), Z(0x7c), Z(0x57),
181 Z(0xc1), Z(0x79), Z(0xc7), Z(0x34), Z(0xd6), Z(0x43), Z(0xdf), Z(0xe4), Z(0x78), Z(0x16), Z(0x06),
182 Z(0xda), Z(0x92), Z(0x76), Z(0x51), Z(0xe1), Z(0xd4), Z(0x70), Z(0x03), Z(0xe0), Z(0x2f), Z(0x96),
183 Z(0x91), Z(0x82), Z(0x80)};
186 #define Z(x) NTOH(x << 11)
187 static const uint32_t sbox2
[256] = {
188 Z(0xf0), Z(0x37), Z(0x24), Z(0x53), Z(0x2a), Z(0x03), Z(0x83), Z(0x86), Z(0xd1), Z(0xec), Z(0x50),
189 Z(0xf0), Z(0x42), Z(0x78), Z(0x2f), Z(0x6d), Z(0xbf), Z(0x80), Z(0x87), Z(0x27), Z(0x95), Z(0xe2),
190 Z(0xc5), Z(0x5d), Z(0xf9), Z(0x6f), Z(0xdb), Z(0xb4), Z(0x65), Z(0x6e), Z(0xe7), Z(0x24), Z(0xc8),
191 Z(0x1a), Z(0xbb), Z(0x49), Z(0xb5), Z(0x0a), Z(0x7d), Z(0xb9), Z(0xe8), Z(0xdc), Z(0xb7), Z(0xd9),
192 Z(0x45), Z(0x20), Z(0x1b), Z(0xce), Z(0x59), Z(0x9d), Z(0x6b), Z(0xbd), Z(0x0e), Z(0x8f), Z(0xa3),
193 Z(0xa9), Z(0xbc), Z(0x74), Z(0xa6), Z(0xf6), Z(0x7f), Z(0x5f), Z(0xb1), Z(0x68), Z(0x84), Z(0xbc),
194 Z(0xa9), Z(0xfd), Z(0x55), Z(0x50), Z(0xe9), Z(0xb6), Z(0x13), Z(0x5e), Z(0x07), Z(0xb8), Z(0x95),
195 Z(0x02), Z(0xc0), Z(0xd0), Z(0x6a), Z(0x1a), Z(0x85), Z(0xbd), Z(0xb6), Z(0xfd), Z(0xfe), Z(0x17),
196 Z(0x3f), Z(0x09), Z(0xa3), Z(0x8d), Z(0xfb), Z(0xed), Z(0xda), Z(0x1d), Z(0x6d), Z(0x1c), Z(0x6c),
197 Z(0x01), Z(0x5a), Z(0xe5), Z(0x71), Z(0x3e), Z(0x8b), Z(0x6b), Z(0xbe), Z(0x29), Z(0xeb), Z(0x12),
198 Z(0x19), Z(0x34), Z(0xcd), Z(0xb3), Z(0xbd), Z(0x35), Z(0xea), Z(0x4b), Z(0xd5), Z(0xae), Z(0x2a),
199 Z(0x79), Z(0x5a), Z(0xa5), Z(0x32), Z(0x12), Z(0x7b), Z(0xdc), Z(0x2c), Z(0xd0), Z(0x22), Z(0x4b),
200 Z(0xb1), Z(0x85), Z(0x59), Z(0x80), Z(0xc0), Z(0x30), Z(0x9f), Z(0x73), Z(0xd3), Z(0x14), Z(0x48),
201 Z(0x40), Z(0x07), Z(0x2d), Z(0x8f), Z(0x80), Z(0x0f), Z(0xce), Z(0x0b), Z(0x5e), Z(0xb7), Z(0x5e),
202 Z(0xac), Z(0x24), Z(0x94), Z(0x4a), Z(0x18), Z(0x15), Z(0x05), Z(0xe8), Z(0x02), Z(0x77), Z(0xa9),
203 Z(0xc7), Z(0x40), Z(0x45), Z(0x89), Z(0xd1), Z(0xea), Z(0xde), Z(0x0c), Z(0x79), Z(0x2a), Z(0x99),
204 Z(0x6c), Z(0x3e), Z(0x95), Z(0xdd), Z(0x8c), Z(0x7d), Z(0xad), Z(0x6f), Z(0xdc), Z(0xff), Z(0xfd),
205 Z(0x62), Z(0x47), Z(0xb3), Z(0x21), Z(0x8a), Z(0xec), Z(0x8e), Z(0x19), Z(0x18), Z(0xb4), Z(0x6e),
206 Z(0x3d), Z(0xfd), Z(0x74), Z(0x54), Z(0x1e), Z(0x04), Z(0x85), Z(0xd8), Z(0xbc), Z(0x1f), Z(0x56),
207 Z(0xe7), Z(0x3a), Z(0x56), Z(0x67), Z(0xd6), Z(0xc8), Z(0xa5), Z(0xf3), Z(0x8e), Z(0xde), Z(0xae),
208 Z(0x37), Z(0x49), Z(0xb7), Z(0xfa), Z(0xc8), Z(0xf4), Z(0x1f), Z(0xe0), Z(0x2a), Z(0x9b), Z(0x15),
209 Z(0xd1), Z(0x34), Z(0x0e), Z(0xb5), Z(0xe0), Z(0x44), Z(0x78), Z(0x84), Z(0x59), Z(0x56), Z(0x68),
210 Z(0x77), Z(0xa5), Z(0x14), Z(0x06), Z(0xf5), Z(0x2f), Z(0x8c), Z(0x8a), Z(0x73), Z(0x80), Z(0x76),
211 Z(0xb4), Z(0x10), Z(0x86)};
214 #define Z(x) NTOH(x << 19)
215 static const uint32_t sbox3
[256] = {
216 Z(0xa9), Z(0x2a), Z(0x48), Z(0x51), Z(0x84), Z(0x7e), Z(0x49), Z(0xe2), Z(0xb5), Z(0xb7), Z(0x42),
217 Z(0x33), Z(0x7d), Z(0x5d), Z(0xa6), Z(0x12), Z(0x44), Z(0x48), Z(0x6d), Z(0x28), Z(0xaa), Z(0x20),
218 Z(0x6d), Z(0x57), Z(0xd6), Z(0x6b), Z(0x5d), Z(0x72), Z(0xf0), Z(0x92), Z(0x5a), Z(0x1b), Z(0x53),
219 Z(0x80), Z(0x24), Z(0x70), Z(0x9a), Z(0xcc), Z(0xa7), Z(0x66), Z(0xa1), Z(0x01), Z(0xa5), Z(0x41),
220 Z(0x97), Z(0x41), Z(0x31), Z(0x82), Z(0xf1), Z(0x14), Z(0xcf), Z(0x53), Z(0x0d), Z(0xa0), Z(0x10),
221 Z(0xcc), Z(0x2a), Z(0x7d), Z(0xd2), Z(0xbf), Z(0x4b), Z(0x1a), Z(0xdb), Z(0x16), Z(0x47), Z(0xf6),
222 Z(0x51), Z(0x36), Z(0xed), Z(0xf3), Z(0xb9), Z(0x1a), Z(0xa7), Z(0xdf), Z(0x29), Z(0x43), Z(0x01),
223 Z(0x54), Z(0x70), Z(0xa4), Z(0xbf), Z(0xd4), Z(0x0b), Z(0x53), Z(0x44), Z(0x60), Z(0x9e), Z(0x23),
224 Z(0xa1), Z(0x18), Z(0x68), Z(0x4f), Z(0xf0), Z(0x2f), Z(0x82), Z(0xc2), Z(0x2a), Z(0x41), Z(0xb2),
225 Z(0x42), Z(0x0c), Z(0xed), Z(0x0c), Z(0x1d), Z(0x13), Z(0x3a), Z(0x3c), Z(0x6e), Z(0x35), Z(0xdc),
226 Z(0x60), Z(0x65), Z(0x85), Z(0xe9), Z(0x64), Z(0x02), Z(0x9a), Z(0x3f), Z(0x9f), Z(0x87), Z(0x96),
227 Z(0xdf), Z(0xbe), Z(0xf2), Z(0xcb), Z(0xe5), Z(0x6c), Z(0xd4), Z(0x5a), Z(0x83), Z(0xbf), Z(0x92),
228 Z(0x1b), Z(0x94), Z(0x00), Z(0x42), Z(0xcf), Z(0x4b), Z(0x00), Z(0x75), Z(0xba), Z(0x8f), Z(0x76),
229 Z(0x5f), Z(0x5d), Z(0x3a), Z(0x4d), Z(0x09), Z(0x12), Z(0x08), Z(0x38), Z(0x95), Z(0x17), Z(0xe4),
230 Z(0x01), Z(0x1d), Z(0x4c), Z(0xa9), Z(0xcc), Z(0x85), Z(0x82), Z(0x4c), Z(0x9d), Z(0x2f), Z(0x3b),
231 Z(0x66), Z(0xa1), Z(0x34), Z(0x10), Z(0xcd), Z(0x59), Z(0x89), Z(0xa5), Z(0x31), Z(0xcf), Z(0x05),
232 Z(0xc8), Z(0x84), Z(0xfa), Z(0xc7), Z(0xba), Z(0x4e), Z(0x8b), Z(0x1a), Z(0x19), Z(0xf1), Z(0xa1),
233 Z(0x3b), Z(0x18), Z(0x12), Z(0x17), Z(0xb0), Z(0x98), Z(0x8d), Z(0x0b), Z(0x23), Z(0xc3), Z(0x3a),
234 Z(0x2d), Z(0x20), Z(0xdf), Z(0x13), Z(0xa0), Z(0xa8), Z(0x4c), Z(0x0d), Z(0x6c), Z(0x2f), Z(0x47),
235 Z(0x13), Z(0x13), Z(0x52), Z(0x1f), Z(0x2d), Z(0xf5), Z(0x79), Z(0x3d), Z(0xa2), Z(0x54), Z(0xbd),
236 Z(0x69), Z(0xc8), Z(0x6b), Z(0xf3), Z(0x05), Z(0x28), Z(0xf1), Z(0x16), Z(0x46), Z(0x40), Z(0xb0),
237 Z(0x11), Z(0xd3), Z(0xb7), Z(0x95), Z(0x49), Z(0xcf), Z(0xc3), Z(0x1d), Z(0x8f), Z(0xd8), Z(0xe1),
238 Z(0x73), Z(0xdb), Z(0xad), Z(0xc8), Z(0xc9), Z(0xa9), Z(0xa1), Z(0xc2), Z(0xc5), Z(0xe3), Z(0xba),
239 Z(0xfc), Z(0x0e), Z(0x25)};
242 * This is a 16 round Feistel network with permutation F_ENCRYPT
245 #define F_ENCRYPT(R, L, sched) { \
246 union lc4 { uint32_t l; unsigned char c[4]; } u; \
248 L ^= sbox0[u.c[0]] ^ sbox1[u.c[1]] ^ sbox2[u.c[2]] ^ sbox3[u.c[3]]; }
250 #ifndef WORDS_BIGENDIAN
251 /* BEWARE: this code is endian dependent.
252 * This should really be inline assembler on the x86.
255 #define FF(y, shiftN) (((y) >> shiftN) & 0xFF)
256 #define F_ENCRYPT(R, L, sched) { \
259 L ^= sbox0[FF(u, 0)] ^ sbox1[FF(u, 8)] ^ sbox2[FF(u, 16)] ^ sbox3[FF(u, 24)];}
264 fc_ecb_enc(uint32_t l
,
267 const int32_t sched
[ROUNDS
])
269 #if !defined(UNROLL_LOOPS)
272 for (i
= 0; i
< (ROUNDS
/4); i
++)
274 F_ENCRYPT(r
, l
, *sched
++);
275 F_ENCRYPT(l
, r
, *sched
++);
276 F_ENCRYPT(r
, l
, *sched
++);
277 F_ENCRYPT(l
, r
, *sched
++);
281 F_ENCRYPT(r
, l
, *sched
++);
282 F_ENCRYPT(l
, r
, *sched
++);
283 F_ENCRYPT(r
, l
, *sched
++);
284 F_ENCRYPT(l
, r
, *sched
++);
285 F_ENCRYPT(r
, l
, *sched
++);
286 F_ENCRYPT(l
, r
, *sched
++);
287 F_ENCRYPT(r
, l
, *sched
++);
288 F_ENCRYPT(l
, r
, *sched
++);
289 F_ENCRYPT(r
, l
, *sched
++);
290 F_ENCRYPT(l
, r
, *sched
++);
291 F_ENCRYPT(r
, l
, *sched
++);
292 F_ENCRYPT(l
, r
, *sched
++);
293 F_ENCRYPT(r
, l
, *sched
++);
294 F_ENCRYPT(l
, r
, *sched
++);
295 F_ENCRYPT(r
, l
, *sched
++);
296 F_ENCRYPT(l
, r
, *sched
++);
297 #endif /* UNROLL_LOOPS */
305 fc_ecb_dec(uint32_t l
,
308 const int32_t sched
[ROUNDS
])
310 sched
= &sched
[ROUNDS
-1];
312 #if !defined(UNROLL_LOOPS)
315 for (i
= 0; i
< (ROUNDS
/4); i
++)
317 F_ENCRYPT(l
, r
, *sched
--);
318 F_ENCRYPT(r
, l
, *sched
--);
319 F_ENCRYPT(l
, r
, *sched
--);
320 F_ENCRYPT(r
, l
, *sched
--);
324 F_ENCRYPT(l
, r
, *sched
--);
325 F_ENCRYPT(r
, l
, *sched
--);
326 F_ENCRYPT(l
, r
, *sched
--);
327 F_ENCRYPT(r
, l
, *sched
--);
328 F_ENCRYPT(l
, r
, *sched
--);
329 F_ENCRYPT(r
, l
, *sched
--);
330 F_ENCRYPT(l
, r
, *sched
--);
331 F_ENCRYPT(r
, l
, *sched
--);
332 F_ENCRYPT(l
, r
, *sched
--);
333 F_ENCRYPT(r
, l
, *sched
--);
334 F_ENCRYPT(l
, r
, *sched
--);
335 F_ENCRYPT(r
, l
, *sched
--);
336 F_ENCRYPT(l
, r
, *sched
--);
337 F_ENCRYPT(r
, l
, *sched
--);
338 F_ENCRYPT(l
, r
, *sched
--);
339 F_ENCRYPT(r
, l
, *sched
--);
340 #endif /* UNROLL_LOOPS */
348 fc_cbc_enc(const uint32_t *in
,
351 const int32_t sched
[ROUNDS
],
354 int32_t xor0
= iv
[0], xor1
= iv
[1];
356 for (; length
> 0; length
-= 8)
359 /* If length < 8 we read to much, usally ok */
362 fc_ecb_enc(xor0
, xor1
, b8
, sched
);
363 xor0
= in
[0] ^ b8
[0];
364 xor1
= in
[1] ^ b8
[1];
366 /* Out is always a multiple of 8 */
377 fc_cbc_dec(const uint32_t *in
,
380 const int32_t sched
[ROUNDS
],
383 int32_t xor0
= iv
[0], xor1
= iv
[1];
385 for (; length
> 0; length
-= 8)
388 /* In is always a multiple of 8 */
389 fc_ecb_dec(in
[0], in
[1], b8
, sched
);
392 xor0
= in
[0] ^ b8
[0];
393 xor1
= in
[1] ^ b8
[1];
399 memcpy(out
, b8
, length
); /* Don't write to much when length < 8 */
401 /* If length < 8 we write to much, this is not always ok */
412 fc_ecb_encrypt(const void *in_
,
414 const int32_t sched
[ROUNDS
],
417 const uint32_t *in
= in_
; /* In must be uint32_t aligned */
418 uint32_t *out
= out_
; /* Out must be uint32_t aligned */
420 fc_ecb_enc(in
[0], in
[1], out
, sched
);
422 fc_ecb_dec(in
[0], in
[1], out
, sched
);
427 fc_cbc_encrypt(const void *in_
,
430 const int32_t sched
[ROUNDS
],
434 const uint32_t *in
= in_
; /* In must be uint32_t aligned */
435 uint32_t *out
= out_
; /* Out must be uint32_t aligned */
437 fc_cbc_enc(in
, out
, length
, sched
, iv
);
439 fc_cbc_dec(in
, out
, length
, sched
, iv
);
443 /* Rotate two 32 bit numbers as a 56 bit number */
444 #define ROT56R(hi, lo, n) { \
445 uint32_t t = lo & ((1<<n)-1); \
446 lo = (lo >> n) | ((hi & ((1<<n)-1)) << (32-n)); \
447 hi = (hi >> n) | (t << (24-n)); }
449 /* Rotate one 64 bit number as a 56 bit number */
450 #define ROT56R64(k, n) { \
451 k = (k >> n) | ((k & ((1<<n) - 1)) << (56-n)); }
454 * Generate a key schedule from key, the least significant bit in each
455 * key byte is parity and shall be ignored. This leaves 56 significant
456 * bits in the key to scatter over the 16 key schedules. For each
457 * schedule extract the low order 32 bits and use as schedule, then
458 * rotate right by 11 bits.
460 * Note that this fc_keysched() generates a schedule in natural byte
461 * order, the Transarc function does not. Therefore it's *not*
462 * possible to mix fc_keysched, fc_ecb_encrypt and fc_cbc_encrypt
463 * from different implementations. Keep them in the same module!
466 fc_keysched(const void *key_
,
467 int32_t sched
[ROUNDS
])
469 const unsigned char *key
= key_
;
471 /* Do we have 56 bit longs or even longer longs? */
472 #if ((1ul << 31) << 1) && defined(ULONG_MAX) && ((ULONG_MAX >> 55) != 0) && ((1ul << 55) != 0)
473 unsigned long k
; /* k holds all 56 non parity bits */
475 /* Compress out parity bits */
492 /* Use lower 32 bits for schedule, rotate by 11 each round (16 times) */
493 *sched
++ = EFF_NTOHL((uint32_t)k
);
495 *sched
++ = EFF_NTOHL((uint32_t)k
);
497 *sched
++ = EFF_NTOHL((uint32_t)k
);
499 *sched
++ = EFF_NTOHL((uint32_t)k
);
502 *sched
++ = EFF_NTOHL((uint32_t)k
);
504 *sched
++ = EFF_NTOHL((uint32_t)k
);
506 *sched
++ = EFF_NTOHL((uint32_t)k
);
508 *sched
++ = EFF_NTOHL((uint32_t)k
);
511 *sched
++ = EFF_NTOHL((uint32_t)k
);
513 *sched
++ = EFF_NTOHL((uint32_t)k
);
515 *sched
++ = EFF_NTOHL((uint32_t)k
);
517 *sched
++ = EFF_NTOHL((uint32_t)k
);
520 *sched
++ = EFF_NTOHL((uint32_t)k
);
522 *sched
++ = EFF_NTOHL((uint32_t)k
);
524 *sched
++ = EFF_NTOHL((uint32_t)k
);
526 *sched
++ = EFF_NTOHL((uint32_t)k
);
529 uint32_t hi
, lo
; /* hi is upper 24 bits and lo lower 32, total 56 */
531 /* Compress out parity bits */
550 /* Use lower 32 bits for schedule, rotate by 11 each round (16 times) */
551 *sched
++ = EFF_NTOHL(lo
);
553 *sched
++ = EFF_NTOHL(lo
);
555 *sched
++ = EFF_NTOHL(lo
);
557 *sched
++ = EFF_NTOHL(lo
);
560 *sched
++ = EFF_NTOHL(lo
);
562 *sched
++ = EFF_NTOHL(lo
);
564 *sched
++ = EFF_NTOHL(lo
);
566 *sched
++ = EFF_NTOHL(lo
);
569 *sched
++ = EFF_NTOHL(lo
);
571 *sched
++ = EFF_NTOHL(lo
);
573 *sched
++ = EFF_NTOHL(lo
);
575 *sched
++ = EFF_NTOHL(lo
);
578 *sched
++ = EFF_NTOHL(lo
);
580 *sched
++ = EFF_NTOHL(lo
);
582 *sched
++ = EFF_NTOHL(lo
);
584 *sched
++ = EFF_NTOHL(lo
);
590 * Encryption/decryption of Rx packets is pretty straight forward. Run
591 * fc_cbc_encrypt over the packet fragments until len bytes have been
592 * processed. Skip the Rx packet header but not the security header.
595 rxkad_EncryptPacket(const void *rx_connection_not_used
,
596 const int32_t sched
[ROUNDS
],
597 const uint32_t iv
[2],
599 struct rx_packet
*packet
)
605 /* What is this good for?
606 * It turns out that the security header for auth_enc is of
607 * size 8 bytes and the last 4 bytes are defined to be 0!
609 uint32_t *t
= (uint32_t *)packet
->wirevec
[1].iov_base
;
613 memcpy(ivec
, iv
, sizeof(ivec
)); /* Must use copy of iv */
614 for (frag
= &packet
->wirevec
[1]; len
; frag
++)
616 int iov_len
= frag
->iov_len
;
617 uint32_t *iov_bas
= (uint32_t *) frag
->iov_base
;
619 return RXKADDATALEN
; /* Length mismatch */
621 iov_len
= len
; /* Don't process to much data */
622 fc_cbc_enc(iov_bas
, iov_bas
, iov_len
, sched
, ivec
);
629 rxkad_DecryptPacket(const void *rx_connection_not_used
,
630 const int32_t sched
[ROUNDS
],
631 const uint32_t iv
[2],
633 struct rx_packet
*packet
)
638 memcpy(ivec
, iv
, sizeof(ivec
)); /* Must use copy of iv */
639 for (frag
= &packet
->wirevec
[1]; len
> 0; frag
++)
641 int iov_len
= frag
->iov_len
;
642 uint32_t *iov_bas
= (uint32_t *) frag
->iov_base
;
644 return RXKADDATALEN
; /* Length mismatch */
646 iov_len
= len
; /* Don't process to much data */
647 fc_cbc_dec(iov_bas
, iov_bas
, iov_len
, sched
, ivec
);
653 #if defined(TEST) || defined(TEST_KERNEL)
655 * It is possible to link with the client kernel libafs.a to verify
656 * the test case. Use TEST_KERNEL to get the mangled names.
662 const char the_quick
[] = "The quick brown fox jumps over the lazy dogs.\0\0";
664 const unsigned char key1
[8]={0xf0,0xe1,0xd2,0xc3,0xb4,0xa5,0x96,0x87};
665 const char ciph1
[] = {
666 0x00, 0xf0, 0xe, 0x11, 0x75, 0xe6, 0x23, 0x82, 0xee, 0xac, 0x98, 0x62,
667 0x44, 0x51, 0xe4, 0x84, 0xc3, 0x59, 0xd8, 0xaa, 0x64, 0x60, 0xae, 0xf7,
668 0xd2, 0xd9, 0x13, 0x79, 0x72, 0xa3, 0x45, 0x03, 0x23, 0xb5, 0x62, 0xd7,
669 0xc, 0xf5, 0x27, 0xd1, 0xf8, 0x91, 0x3c, 0xac, 0x44, 0x22, 0x92, 0xef };
671 const unsigned char key2
[8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
672 const char ciph2
[] = {
673 0xca, 0x90, 0xf5, 0x9d, 0xcb, 0xd4, 0xd2, 0x3c, 0x01, 0x88, 0x7f, 0x3e,
674 0x31, 0x6e, 0x62, 0x9d, 0xd8, 0xe0, 0x57, 0xa3, 0x06, 0x3a, 0x42, 0x58,
675 0x2a, 0x28, 0xfe, 0x72, 0x52, 0x2f, 0xdd, 0xe0, 0x19, 0x89, 0x09, 0x1c,
676 0x2a, 0x8e, 0x8c, 0x94, 0xfc, 0xc7, 0x68, 0xe4, 0x88, 0xaa, 0xde, 0x0f };
679 #define fc_keysched _afs_QTKrFdpoFL
680 #define fc_ecb_encrypt _afs_sDLThwNLok
681 #define fc_cbc_encrypt _afs_fkyCWTvfRS
682 #define rxkad_DecryptPacket _afs_SRWEeqTXrS
683 #define rxkad_EncryptPacket _afs_bpwQbdoghO
689 int32_t sched
[ROUNDS
];
690 char ciph
[100], clear
[100], tmp
[100];
693 struct rx_packet packet
;
695 if (sizeof(int32_t) != 4)
696 fprintf(stderr
, "error: sizeof(int32_t) != 4\n");
697 if (sizeof(uint32_t) != 4)
698 fprintf(stderr
, "error: sizeof(uint32_t) != 4\n");
701 * Use key1 and key2 as iv */
702 fc_keysched(key1
, sched
);
703 memcpy(iv
, key2
, sizeof(iv
));
704 fc_cbc_encrypt(the_quick
, ciph
, sizeof(the_quick
), sched
, iv
, FC_ENCRYPT
);
705 if (memcmp(ciph1
, ciph
, sizeof(ciph1
)) != 0)
706 fprintf(stderr
, "encrypt FAILED\n");
707 memcpy(iv
, key2
, sizeof(iv
));
708 fc_cbc_encrypt(ciph
, clear
, sizeof(the_quick
), sched
, iv
, FC_DECRYPT
);
709 if (strcmp(the_quick
, clear
) != 0)
710 fprintf(stderr
, "crypt decrypt FAILED\n");
713 * Use key2 and key1 as iv
715 fc_keysched(key2
, sched
);
716 memcpy(iv
, key1
, sizeof(iv
));
717 fc_cbc_encrypt(the_quick
, ciph
, sizeof(the_quick
), sched
, iv
, FC_ENCRYPT
);
718 if (memcmp(ciph2
, ciph
, sizeof(ciph2
)) != 0)
719 fprintf(stderr
, "encrypt FAILED\n");
720 memcpy(iv
, key1
, sizeof(iv
));
721 fc_cbc_encrypt(ciph
, clear
, sizeof(the_quick
), sched
, iv
, FC_DECRYPT
);
722 if (strcmp(the_quick
, clear
) != 0)
723 fprintf(stderr
, "crypt decrypt FAILED\n");
726 * Test Encrypt- and Decrypt-Packet, use key1 and key2 as iv
728 fc_keysched(key1
, sched
);
729 memcpy(iv
, key2
, sizeof(iv
));
730 strlcpy(clear
, the_quick
, sizeof(clear
));
731 packet
.wirevec
[1].iov_base
= clear
;
732 packet
.wirevec
[1].iov_len
= sizeof(the_quick
);
733 packet
.wirevec
[2].iov_len
= 0;
735 /* For unknown reasons bytes 4-7 are zeroed in rxkad_EncryptPacket */
736 rxkad_EncryptPacket(tmp
, sched
, iv
, sizeof(the_quick
), &packet
);
737 rxkad_DecryptPacket(tmp
, sched
, iv
, sizeof(the_quick
), &packet
);
742 if (strcmp(the_quick
, clear
) != 0)
743 fprintf(stderr
, "rxkad_EncryptPacket/rxkad_DecryptPacket FAILED\n");
746 struct timeval start
, stop
;
749 fc_keysched(key1
, sched
);
750 gettimeofday(&start
, 0);
751 for (i
= 0; i
< 1000000; i
++)
752 fc_keysched(key1
, sched
);
753 gettimeofday(&stop
, 0);
754 printf("fc_keysched = %2.2f us\n",
755 (stop
.tv_sec
- start
.tv_sec
756 + (stop
.tv_usec
- start
.tv_usec
)/1e6
)*1);
758 fc_ecb_encrypt(data
, data
, sched
, FC_ENCRYPT
);
759 gettimeofday(&start
, 0);
760 for (i
= 0; i
< 1000000; i
++)
761 fc_ecb_encrypt(data
, data
, sched
, FC_ENCRYPT
);
762 gettimeofday(&stop
, 0);
763 printf("fc_ecb_encrypt = %2.2f us\n",
764 (stop
.tv_sec
- start
.tv_sec
765 + (stop
.tv_usec
- start
.tv_usec
)/1e6
)*1);
767 fc_cbc_encrypt(the_quick
, ciph
, sizeof(the_quick
), sched
, iv
, FC_ENCRYPT
);
768 gettimeofday(&start
, 0);
769 for (i
= 0; i
< 100000; i
++)
770 fc_cbc_encrypt(the_quick
, ciph
, sizeof(the_quick
), sched
, iv
, FC_ENCRYPT
);
771 gettimeofday(&stop
, 0);
772 printf("fc_cbc_encrypt = %2.2f us\n",
773 (stop
.tv_sec
- start
.tv_sec
774 + (stop
.tv_usec
- start
.tv_usec
)/1e6
)*10);