blob: 6918bec3e282760880fa32f095aa6c2c83e0a569 [file] [log] [blame]
/*
* 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 );