| /* |
| * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation; either version 2 of the |
| * License, or any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| * 02110-1301, USA. |
| * |
| * You can also choose to distribute this program under the terms of |
| * the Unmodified Binary Distribution Licence (as given in the file |
| * COPYING.UBDL), provided that you have satisfied its requirements. |
| */ |
| |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); |
| |
| /** @file |
| * |
| * DES algorithm |
| * |
| * DES was not designed to be implemented in software, and therefore |
| * contains a large number of bit permutation operations that are |
| * essentially free in hardware (requiring only wires, no gates) but |
| * expensive in software. |
| * |
| * Since DES is no longer used as a practical block cipher for large |
| * volumes of data, we optimise for code size, and do not attempt to |
| * obtain fast throughput. |
| * |
| * The algorithm is specified in NIST SP 800-67, downloadable from |
| * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-67r2.pdf |
| */ |
| |
| #include <stdint.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <byteswap.h> |
| #include <ipxe/rotate.h> |
| #include <ipxe/crypto.h> |
| #include <ipxe/ecb.h> |
| #include <ipxe/cbc.h> |
| #include <ipxe/init.h> |
| #include <ipxe/des.h> |
| |
| /** |
| * DES shift schedule |
| * |
| * The DES shift schedule (ordered from round 16 down to round 1) is |
| * {1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,1}. In binary, this may be |
| * represented as {1,10,10,10,10,10,10,1,10,10,10,10,10,10,1,1} and |
| * concatenated (without padding) to produce a single binary integer |
| * 1101010101010110101010101011 (equal to 0x0d556aab in hexadecimal). |
| * |
| * This integer may then be consumed LSB-first, where a 1 bit |
| * indicates a shift and the generation of a round key, and a 0 bit |
| * indicates a shift without the generation of a round key. |
| */ |
| #define DES_SCHEDULE 0x0d556aab |
| |
| /** |
| * Define an element pair in a DES S-box |
| * |
| * @v x Upper element of element pair |
| * @v y Lower element of element pair |
| * |
| * DES S-box elements are 4-bit values. We encode two values per |
| * byte, ordering the elements so that the six-bit input value may be |
| * used directly as a lookup index. |
| * |
| * Specifically, if the input value is {r1,c3,c2,c1,c0,r0}, where |
| * {r1,r0} is the table row index and {c3,c2,c1,c0} is the table |
| * column index (as used in the DES specification), then: |
| * |
| * - {r1,c3,c2,c1,c0} is the byte index into the table |
| * |
| * - (4*r0) is the required bit shift to extract the 4-bit value |
| */ |
| #define SBYTE( x, y ) ( ( (y) << 4 ) | (x) ) |
| |
| /** |
| * Define a row pair in a DES S-box |
| * |
| * @v x0..xf Upper row of row pair |
| * @v y0..yf Lower row of row pair |
| */ |
| #define SBOX( x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, \ |
| y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, ya, yb, yc, yd, ye, yf ) \ |
| SBYTE ( x0, y0 ), SBYTE ( x1, y1 ), SBYTE ( x2, y2 ), SBYTE ( x3, y3 ),\ |
| SBYTE ( x4, y4 ), SBYTE ( x5, y5 ), SBYTE ( x6, y6 ), SBYTE ( x7, y7 ),\ |
| SBYTE ( x8, y8 ), SBYTE ( x9, y9 ), SBYTE ( xa, ya ), SBYTE ( xb, yb ),\ |
| SBYTE ( xc, yc ), SBYTE ( xd, yd ), SBYTE ( xe, ye ), SBYTE ( xf, yf ) |
| |
| /** DES S-boxes S1..S8 */ |
| static const uint8_t des_s[8][32] = { { |
| /* S1 */ |
| SBOX ( 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, |
| 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 ), |
| SBOX ( 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, |
| 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 ) |
| }, { |
| /* S2 */ |
| SBOX ( 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, |
| 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 ), |
| SBOX ( 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, |
| 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 ) |
| }, { |
| /* S3 */ |
| SBOX ( 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, |
| 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 ), |
| SBOX ( 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, |
| 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 ) |
| }, { |
| /* S4 */ |
| SBOX ( 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, |
| 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 ), |
| SBOX ( 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, |
| 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 ) |
| }, { |
| /* S5 */ |
| SBOX ( 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, |
| 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 ), |
| SBOX ( 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, |
| 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 ) |
| }, { |
| /* S6 */ |
| SBOX ( 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, |
| 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 ), |
| SBOX ( 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, |
| 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 ) |
| }, { |
| /* S7 */ |
| SBOX ( 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, |
| 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 ), |
| SBOX ( 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, |
| 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 ) |
| }, { |
| /* S8 */ |
| SBOX ( 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, |
| 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 ), |
| SBOX ( 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, |
| 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 ) |
| } }; |
| |
| /** |
| * Define a bit index within permuted choice 2 (PC2) |
| * |
| * @v bit Bit index |
| * |
| * Permuted choice 2 (PC2) is used to select bits from a concatenated |
| * pair of 28-bit registers ("C" and "D") as part of the key schedule. |
| * We store these as 32-bit registers and so must add 4 to indexes |
| * above 28. |
| */ |
| #define DES_PC2( x ) ( (x) + ( ( (x) > 28 ) ? 4 : 0 ) ) |
| |
| /** |
| * Define six bits of permuted choice 2 (PC2) |
| * |
| * @v r1:r0 Bits corresponding to S-box row index |
| * @v c3:c0 Bits corresponding to S-box column index |
| * |
| * There are 8 steps within a DES round (one step per S-box). Each |
| * step requires six bits of the round key, corresponding to the S-box |
| * input value {r1,c3,c2,c1,c0,r0}, where {r1,r0} is the table row |
| * index and {c3,c2,c1,c0} is the table column index. |
| * |
| * As an optimisation, we store the least significant of the 6 bits in |
| * the sign bit of a signed 8-bit value, and the remaining 5 bits in |
| * the least significant 5 bits of the 8-bit value. See the comments |
| * in des_sbox() for further details. |
| */ |
| #define DES_PC2R( r1, c3, c2, c1, c0, r0 ) \ |
| DES_PC2 ( r0 ), /* LSB stored in sign bit */ \ |
| DES_PC2 ( r0 ), /* Unused bit */ \ |
| DES_PC2 ( r0 ), /* Unused bit */ \ |
| DES_PC2 ( r1 ), /* Remaining 5 bits */ \ |
| DES_PC2 ( c3 ), /* ... */ \ |
| DES_PC2 ( c2 ), /* ... */ \ |
| DES_PC2 ( c1 ), /* ... */ \ |
| DES_PC2 ( c0 ) /* ... */ |
| |
| /** |
| * A DES systematic permutation generator |
| * |
| * Many of the permutations used in DES comprise systematic bit |
| * patterns. We generate these permutations at runtime to save on |
| * code size. |
| */ |
| struct des_generator { |
| /** Permutation */ |
| uint8_t *permutation; |
| /** Seed value */ |
| uint32_t seed; |
| }; |
| |
| /** |
| * Define a DES permutation generator |
| * |
| * @v PERMUTATION Permutation |
| * @v OFFSET Fixed input bit offset (0 or 1) |
| * @v INV<n> Input bit index bit <n> should be inverted |
| * @v BIT<n> Source bit for input bit index bit <n> |
| * @ret generator Permutation generator |
| */ |
| #define DES_GENERATOR( PERMUTATION, OFFSET, INV5, BIT5, INV4, BIT4, \ |
| INV3, BIT3, INV2, BIT2, INV1, BIT1, INV0, BIT0 ) \ |
| { \ |
| .permutation = (PERMUTATION), \ |
| .seed = ( ( (INV0) << 31 ) | ( (BIT0) << 28 ) | \ |
| ( (INV1) << 27 ) | ( (BIT1) << 24 ) | \ |
| ( (INV2) << 23 ) | ( (BIT2) << 20 ) | \ |
| ( (INV3) << 19 ) | ( (BIT3) << 16 ) | \ |
| ( (INV4) << 15 ) | ( (BIT4) << 12 ) | \ |
| ( (INV5) << 11 ) | ( (BIT5) << 8 ) | \ |
| ( ( uint32_t ) sizeof (PERMUTATION) - 1 ) | \ |
| (OFFSET) ), \ |
| } |
| |
| /** DES permuted choice 1 (PC1) "C" register */ |
| static uint8_t des_pc1c[29]; |
| |
| /** DES permuted choice 1 (PC1) "D" register */ |
| static uint8_t des_pc1d[33]; |
| |
| /** DES permuted choice 2 (PC2) */ |
| static const uint8_t des_pc2[65] = { |
| DES_PC2R ( 14, 17, 11, 24, 1, 5 ), |
| DES_PC2R ( 3, 28, 15, 6, 21, 10 ), |
| DES_PC2R ( 23, 19, 12, 4, 26, 8 ), |
| DES_PC2R ( 16, 7, 27, 20, 13, 2 ), |
| DES_PC2R ( 41, 52, 31, 37, 47, 55 ), |
| DES_PC2R ( 30, 40, 51, 45, 33, 48 ), |
| DES_PC2R ( 44, 49, 39, 56, 34, 53 ), |
| DES_PC2R ( 46, 42, 50, 36, 29, 32 ), |
| 0 /* terminator */ |
| }; |
| |
| /** DES initial permutation (IP) */ |
| static uint8_t des_ip[65]; |
| |
| /** DES data permutation (P) */ |
| static const uint8_t des_p[33] = { |
| 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, |
| 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25, |
| 0 /* terminator */ |
| }; |
| |
| /** DES final / inverse initial permutation (FP / IP^-1) */ |
| static uint8_t des_fp[65]; |
| |
| /** DES permutation generators */ |
| static struct des_generator des_generators[] = { |
| |
| /* The DES initial permutation transforms the bit index |
| * {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,x4,x3,~x5}+1 |
| */ |
| DES_GENERATOR ( des_ip, 1, 1, 2, 1, 1, 1, 0, 0, 4, 0, 3, 1, 5 ), |
| |
| /* The DES final permutation transforms the bit index |
| * {x5,x4,x3,x2,x1,x0}+1 into {~x0,x2,x1,~x5,~x4,~x3}+1 |
| * |
| * There is an asymmetry in the DES block diagram for the last |
| * of the 16 rounds, which is functionally equivalent to |
| * performing 16 identical rounds and then swapping the left |
| * and right halves before applying the final permutation. We |
| * may therefore account for this asymmetry by inverting the |
| * MSB in each bit index, to point to the corresponding bit in |
| * the other half. |
| * |
| * This is equivalent to using a permutation that transforms |
| * {x5,x4,x3,x2,x1,x0}+1 into {x0,x2,x1,~x5,~x4,~x3}+1 |
| */ |
| DES_GENERATOR ( des_fp, 1, 0, 0, 0, 2, 0, 1, 1, 5, 1, 4, 1, 3 ), |
| |
| /* The "C" half of DES permuted choice 1 (PC1) transforms the |
| * bit index {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,x5,x4,x3}+1 |
| */ |
| DES_GENERATOR ( des_pc1c, 1, 1, 2, 1, 1, 1, 0, 0, 5, 0, 4, 0, 3 ), |
| |
| /* The "D" half of DES permuted choice 1 (PC1) transforms the |
| * bit index {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,~x5,~x4,~x3}+0 |
| * |
| * Due to the idosyncratic design choice of using 28-bit |
| * registers in the DES key expansion schedule, the final four |
| * permutation values appear at indices [28:31] instead of |
| * [24:27]. This is adjusted for in @c des_setkey(). |
| */ |
| DES_GENERATOR ( des_pc1d, 0, 1, 2, 1, 1, 1, 0, 1, 5, 1, 4, 1, 3 ), |
| }; |
| |
| /** |
| * Generate DES permutation |
| * |
| * @v generator Generator |
| */ |
| static __attribute__ (( noinline )) void |
| des_generate ( struct des_generator *generator ) { |
| uint8_t *permutation = generator->permutation; |
| uint32_t seed = generator->seed; |
| unsigned int index = 0; |
| uint8_t accum; |
| uint8_t bit; |
| |
| /* Generate permutations |
| * |
| * This loop is optimised for code size on a |
| * register-constrained architecture such as i386. |
| */ |
| do { |
| /* Rotate seed to access MSB's bit descriptor */ |
| seed = ror32 ( seed, 8 ); |
| |
| /* Initialise accumulator with six flag bits */ |
| accum = 0xfc; |
| |
| /* Accumulate bits until all six flag bits are cleared */ |
| do { |
| /* Extract specified bit from index. Use a |
| * rotation instead of a shift, since this |
| * will allow the mask to be elided. |
| */ |
| bit = ror8 ( index, ( seed & 0x07 ) ); |
| seed = ror32 ( seed, 3 ); |
| |
| /* Toggle bit if applicable */ |
| bit ^= seed; |
| seed = ror32 ( seed, 1 ); |
| |
| /* Add bit to accumulator and clear one flag bit */ |
| accum <<= 1; |
| accum |= ( bit & 0x01 ); |
| |
| } while ( accum & 0x80 ); |
| |
| /* Add constant offset if applicable */ |
| accum += ( seed & 0x01 ); |
| |
| /* Store permutation */ |
| permutation[index] = accum; |
| |
| /* Loop until reaching length (which is always even) */ |
| } while ( ++index < ( seed & 0xfe ) ); |
| DBGC2 ( permutation, "DES generated permutation %p:\n", permutation ); |
| DBGC2_HDA ( permutation, 0, permutation, |
| ( ( seed & 0xfe ) + 1 /* zero terminator */ ) ); |
| } |
| |
| /** |
| * Initialise permutations |
| */ |
| static void des_init ( void ) { |
| unsigned int i; |
| |
| /* Generate all generated permutations */ |
| for ( i = 0 ; i < ( sizeof ( des_generators ) / |
| sizeof ( des_generators[0] ) ) ; i++ ) { |
| des_generate ( &des_generators[i] ); |
| } |
| } |
| |
| /** Initialisation function */ |
| struct init_fn des_init_fn __init_fn ( INIT_NORMAL ) = { |
| .initialise = des_init, |
| }; |
| |
| /** |
| * Perform bit permutation |
| * |
| * @v permutation Bit permutation (zero-terminated) |
| * @v in Input value |
| * @v out Output value |
| */ |
| static void des_permute ( const uint8_t *permutation, const uint8_t *in, |
| uint8_t *out ) { |
| uint8_t mask = 0x80; |
| uint8_t accum = 0; |
| unsigned int bit; |
| |
| /* Extract individual input bits to construct output value */ |
| while ( ( bit = *(permutation++) ) ) { |
| bit--; |
| if ( in[ bit / 8 ] & ( 0x80 >> ( bit % 8 ) ) ) |
| accum |= mask; |
| *out = accum; |
| mask = ror8 ( mask, 1 ); |
| if ( mask == 0x80 ) { |
| out++; |
| accum = 0; |
| } |
| } |
| } |
| |
| /** |
| * Perform DES S-box substitution |
| * |
| * @v in 32-bit input value (native endian) |
| * @v rkey 48-bit round key |
| * @ret out 32-bit output value (native endian) |
| */ |
| static uint32_t des_sbox ( uint32_t in, const union des_round_key *rkey ) { |
| uint32_t out = 0; |
| uint32_t lookup; |
| int32_t key; |
| uint8_t sub; |
| unsigned int i; |
| |
| /* Perform input expansion, key addition, and S-box substitution */ |
| for ( i = 0 ; i < 8 ; i++ ) { |
| |
| /* Rotate input and output */ |
| out = rol32 ( out, 4 ); |
| in = rol32 ( in, 4 ); |
| |
| /* Extract step key from relevant 6 bits of round key |
| * |
| * The least significant of the 6 bits (corresponding |
| * to bit r0 in the S-box lookup index) is stored in |
| * the sign bit of the step key byte. It will |
| * therefore be propagated via sign extension to the |
| * MSB of the 32-bit step key. |
| * |
| * The remaining 5 of the 6 bits (corresponding to |
| * bits {r1,c3,c2,c1,c0} in the S-box lookup index) |
| * are stored in the least significant 5 bits of the |
| * step key byte and will end up in the least |
| * significant 5 bits of the 32-bit step key. |
| */ |
| key = rkey->step[i]; |
| |
| /* Add step key to input to produce S-box lookup index |
| * |
| * We do not ever perform an explicit expansion of the |
| * input value from 32 to 48 bits. Instead, we rotate |
| * the 32-bit input value by 4 bits on each step, and |
| * extract the relevant 6 bits. |
| * |
| * The least significant of the 6 bits (corresponding |
| * to bit r0 in the S-box lookup index) is currently |
| * in the MSB of the 32-bit (rotated) input value. |
| * |
| * The remaining 5 of the 6 bits (corresponding to |
| * bits {r1,c3,c2,c1,c0} in the S-box lookup index) |
| * are currently in the least significant 5 bits of |
| * the 32-bit (rotated) input value. |
| * |
| * This aligns with the placement of the bits in the |
| * step key (see above), and we can therefore perform |
| * a single XOR to add the 6-bit step key to the |
| * relevant 6 bits of the input value. |
| */ |
| lookup = ( in ^ key ); |
| |
| /* Look up S[i][in ^ key] from S-box |
| * |
| * We have bits {r1,c3,c2,c1,c0} in the least |
| * significant 5 bits of the lookup index, and so can |
| * use the masked lookup index directly as a byte |
| * index into the relevant S-box to extract the byte |
| * containing both {r1,c3,c2,c1,c0,'0'} and |
| * {r1,c3,c2,c1,c0,'1'}. |
| * |
| * We then use the MSB of the 32-bit lookup index to |
| * extract the relevant nibble for the full lookup |
| * index {r1,c3,c2,c1,c0,r0}. |
| */ |
| sub = des_s[i][ lookup & 0x1f ]; |
| sub >>= ( ( lookup >> 29 ) & 4 ); |
| sub &= 0x0f; |
| |
| /* Substitute S[i][input ^ key] into output */ |
| out |= sub; |
| } |
| |
| return out; |
| } |
| |
| /** |
| * Perform a single DES round |
| * |
| * @v block DES block |
| * @v rkey 48-bit round key |
| */ |
| static void des_round ( union des_block *block, |
| const union des_round_key *rkey ) { |
| union des_dword sbox; |
| uint32_t left; |
| uint32_t right; |
| |
| /* Extract left and right halves L[n-1] and R[n-1] */ |
| left = block->left.dword; |
| right = block->right.dword; |
| DBGC2 ( block, "DES L=%08x R=%08x K=%08x%08x", be32_to_cpu ( left ), |
| be32_to_cpu ( right ), be32_to_cpu ( rkey->dword[0] ), |
| be32_to_cpu ( rkey->dword[1] ) ); |
| |
| /* L[n] = R[n-1] */ |
| block->left.dword = right; |
| |
| /* Calculate Feistel function f(R[n-1], K[n]) */ |
| sbox.dword = cpu_to_be32 ( des_sbox ( be32_to_cpu ( right ), rkey ) ); |
| des_permute ( des_p, sbox.byte, block->right.byte ); |
| |
| /* R[n] = L[n-1] + f(R[n-1], K[n]) */ |
| block->right.dword ^= left; |
| DBGC2 ( block, " => L=%08x R=%08x\n", |
| be32_to_cpu ( block->left.dword ), |
| be32_to_cpu ( block->right.dword ) ); |
| } |
| |
| /** |
| * Perform all DES rounds |
| * |
| * @v in Input DES block |
| * @v out Output DES block |
| * @v rkey Starting 48-bit round key |
| * @v offset Byte offset between round keys |
| */ |
| static void des_rounds ( const union des_block *in, union des_block *out, |
| const union des_round_key *rkey, |
| ssize_t offset ) { |
| union des_block tmp; |
| unsigned int i; |
| |
| /* Apply initial permutation */ |
| des_permute ( des_ip, in->byte, tmp.byte ); |
| |
| /* Perform all DES rounds, consuming keys in the specified order */ |
| for ( i = 0 ; i < DES_ROUNDS ; i++ ) { |
| des_round ( &tmp, rkey ); |
| rkey = ( ( ( void * ) rkey ) + offset ); |
| } |
| |
| /* Apply final permutation */ |
| DBGC ( &tmp, "DES %scrypted %08x%08x => ", |
| ( ( offset > 0 ) ? "en" : "de" ), be32_to_cpu ( in->dword[0] ), |
| be32_to_cpu ( in->dword[1] ) ); |
| des_permute ( des_fp, tmp.byte, out->byte ); |
| DBGC ( &tmp, "%08x%08x\n", be32_to_cpu ( out->dword[0] ), |
| be32_to_cpu ( out->dword[1] ) ); |
| } |
| |
| /** |
| * Rotate 28-bit word |
| * |
| * @v dword 28-bit dword value |
| * @ret dword Rotated 28-bit dword value |
| */ |
| static uint32_t des_rol28 ( uint32_t dword ) { |
| int32_t sdword; |
| |
| /* Convert to native-endian */ |
| sdword = be32_to_cpu ( dword ); |
| |
| /* Signed shift right by 4 places to copy bit 31 to bits 27:31 */ |
| sdword >>= 4; |
| |
| /* Rotate left */ |
| sdword = rol32 ( sdword, 1 ); |
| |
| /* Shift left by 4 places to restore bit positions */ |
| sdword <<= 4; |
| |
| /* Convert back to big-endian */ |
| dword = cpu_to_be32 ( sdword ); |
| |
| return dword; |
| } |
| |
| /** |
| * Set key |
| * |
| * @v ctx Context |
| * @v key Key |
| * @v keylen Key length |
| * @ret rc Return status code |
| */ |
| static int des_setkey ( void *ctx, const void *key, size_t keylen ) { |
| struct des_context *des = ctx; |
| union des_round_key *rkey = des->rkey; |
| union des_block reg; |
| uint32_t schedule; |
| |
| /* Validate key length */ |
| if ( keylen != DES_BLOCKSIZE ) |
| return -EINVAL; |
| DBGC ( des, "DES %p new key:\n", des ); |
| DBGC_HDA ( des, 0, key, keylen ); |
| |
| /* Apply permuted choice 1 */ |
| des_permute ( des_pc1c, key, reg.c.byte ); |
| des_permute ( des_pc1d, key, reg.d.byte ); |
| reg.d.byte[3] <<= 4; /* see comment for @c des_pc1d */ |
| DBGC2 ( des, "DES %p C[ 0]=%07x D[ 0]=%07x\n", |
| des, ( be32_to_cpu ( reg.c.dword ) >> 4 ), |
| ( be32_to_cpu ( reg.d.dword ) >> 4 ) ); |
| |
| /* Generate round keys */ |
| for ( schedule = DES_SCHEDULE ; schedule ; schedule >>= 1 ) { |
| |
| /* Shift 28-bit words */ |
| reg.c.dword = des_rol28 ( reg.c.dword ); |
| reg.d.dword = des_rol28 ( reg.d.dword ); |
| |
| /* Skip rounds according to shift schedule */ |
| if ( ! ( schedule & 1 ) ) |
| continue; |
| |
| /* Apply permuted choice 2 */ |
| des_permute ( des_pc2, reg.byte, rkey->byte ); |
| DBGC2 ( des, "DES %p C[%2zd]=%07x D[%2zd]=%07x K[%2zd]=" |
| "%08x%08x\n", des, ( ( rkey - des->rkey ) + 1 ), |
| ( be32_to_cpu ( reg.c.dword ) >> 4 ), |
| ( ( rkey - des->rkey ) + 1 ), |
| ( be32_to_cpu ( reg.d.dword ) >> 4 ), |
| ( ( rkey - des->rkey ) + 1 ), |
| be32_to_cpu ( rkey->dword[0] ), |
| be32_to_cpu ( rkey->dword[1] ) ); |
| |
| /* Move to next key */ |
| rkey++; |
| } |
| |
| /* Sanity check */ |
| assert ( rkey == &des->rkey[DES_ROUNDS] ); |
| |
| return 0; |
| } |
| |
| /** |
| * Encrypt data |
| * |
| * @v ctx Context |
| * @v src Data to encrypt |
| * @v dst Buffer for encrypted data |
| * @v len Length of data |
| */ |
| static void des_encrypt ( void *ctx, const void *src, void *dst, size_t len ) { |
| struct des_context *des = ctx; |
| |
| /* Sanity check */ |
| assert ( len == DES_BLOCKSIZE ); |
| |
| /* Cipher using keys in forward direction */ |
| des_rounds ( src, dst, &des->rkey[0], sizeof ( des->rkey[0] ) ); |
| } |
| |
| /** |
| * Decrypt data |
| * |
| * @v ctx Context |
| * @v src Data to decrypt |
| * @v dst Buffer for decrypted data |
| * @v len Length of data |
| */ |
| static void des_decrypt ( void *ctx, const void *src, void *dst, size_t len ) { |
| struct des_context *des = ctx; |
| |
| /* Sanity check */ |
| assert ( len == DES_BLOCKSIZE ); |
| |
| /* Cipher using keys in reverse direction */ |
| des_rounds ( src, dst, &des->rkey[ DES_ROUNDS - 1 ], |
| -sizeof ( des->rkey[0] ) ); |
| } |
| |
| /** Basic DES algorithm */ |
| struct cipher_algorithm des_algorithm = { |
| .name = "des", |
| .ctxsize = sizeof ( struct des_context ), |
| .blocksize = DES_BLOCKSIZE, |
| .alignsize = 0, |
| .authsize = 0, |
| .setkey = des_setkey, |
| .setiv = cipher_null_setiv, |
| .encrypt = des_encrypt, |
| .decrypt = des_decrypt, |
| .auth = cipher_null_auth, |
| }; |
| |
| /* DES in Electronic Codebook mode */ |
| ECB_CIPHER ( des_ecb, des_ecb_algorithm, |
| des_algorithm, struct des_context, DES_BLOCKSIZE ); |
| |
| /* DES in Cipher Block Chaining mode */ |
| CBC_CIPHER ( des_cbc, des_cbc_algorithm, |
| des_algorithm, struct des_context, DES_BLOCKSIZE ); |