/*******************************************************************************
* Created 29, June, 1999
* Modified 4, June, 2008
* FILE: SEED_KISA.c
*
* DESCRIPTION: Core routines for the enhanced SEED
*
*******************************************************************************/
/******************************* Include files ********************************/
#include "SEED_KISA.h"
#include "SEED_KISA.tab"
/******************** Macros for Encryption and Decryption ********************/
#define GetB0(A) ( (BYTE)((A) ) )
#define GetB1(A) ( (BYTE)((A)>> 8) )
#define GetB2(A) ( (BYTE)((A)>>16) )
#define GetB3(A) ( (BYTE)((A)>>24) )
/* Round function F and adding output of F to L. */
/* L0, L1 : left input values at each round */
/* R0, R1 : right input values at each round */
/* K : round keys at each round */
#define SeedRound(L0, L1, R0, R1, K) { \
T0 = R0 ^ (K)[0]; \
T1 = R1 ^ (K)[1]; \
T1 ^= T0; \
T1 = SS0[GetB0(T1)] ^ SS1[GetB1(T1)] ^ \
SS2[GetB2(T1)] ^ SS3[GetB3(T1)]; \
T0 += T1; \
T0 = SS0[GetB0(T0)] ^ SS1[GetB1(T0)] ^ \
SS2[GetB2(T0)] ^ SS3[GetB3(T0)]; \
T1 += T0; \
T1 = SS0[GetB0(T1)] ^ SS1[GetB1(T1)] ^ \
SS2[GetB2(T1)] ^ SS3[GetB3(T1)]; \
T0 += T1; \
L0 ^= T0; L1 ^= T1; \
}
/********************************* Encryption *********************************/
void SeedEncrypt (
BYTE *pbData, /* [in,out] data to be encrypted */
DWORD *pdwRoundKey) /* [in] round keys for encryption */
{
DWORD L0, L1, R0, R1; /* Iuput/output values at each rounds */
DWORD T0, T1; /* Temporary variables for round function F */
DWORD *K = pdwRoundKey; /* Pointer of round keys */
/* Set up input values for first round */
L0 = ((DWORD *)pbData)[0];
L1 = ((DWORD *)pbData)[1];
R0 = ((DWORD *)pbData)[2];
R1 = ((DWORD *)pbData)[3];
/* Reorder for big endian */
/* Because SEED use little endian order in default */
#ifndef SEED_BIG_ENDIAN
L0 = EndianChange(L0);
L1 = EndianChange(L1);
R0 = EndianChange(R0);
R1 = EndianChange(R1);
#endif
SeedRound(L0, L1, R0, R1, K ); /* Round 1 */
SeedRound(R0, R1, L0, L1, K+ 2); /* Round 2 */
SeedRound(L0, L1, R0, R1, K+ 4); /* Round 3 */
SeedRound(R0, R1, L0, L1, K+ 6); /* Round 4 */
SeedRound(L0, L1, R0, R1, K+ 8); /* Round 5 */
SeedRound(R0, R1, L0, L1, K+10); /* Round 6 */
SeedRound(L0, L1, R0, R1, K+12); /* Round 7 */
SeedRound(R0, R1, L0, L1, K+14); /* Round 8 */
SeedRound(L0, L1, R0, R1, K+16); /* Round 9 */
SeedRound(R0, R1, L0, L1, K+18); /* Round 10 */
SeedRound(L0, L1, R0, R1, K+20); /* Round 11 */
SeedRound(R0, R1, L0, L1, K+22); /* Round 12 */
SeedRound(L0, L1, R0, R1, K+24); /* Round 13 */
SeedRound(R0, R1, L0, L1, K+26); /* Round 14 */
SeedRound(L0, L1, R0, R1, K+28); /* Round 15 */
SeedRound(R0, R1, L0, L1, K+30); /* Round 16 */
#ifndef SEED_BIG_ENDIAN
L0 = EndianChange(L0);
L1 = EndianChange(L1);
R0 = EndianChange(R0);
R1 = EndianChange(R1);
#endif
/* Copying output values from last round to pbData */
((DWORD *)pbData)[0] = R0;
((DWORD *)pbData)[1] = R1;
((DWORD *)pbData)[2] = L0;
((DWORD *)pbData)[3] = L1;
}
/********************************* Decryption *********************************/
/* Same as encrypt, except that round keys are applied in reverse order */
void SeedDecrypt (
BYTE *pbData, /* [in,out] data to be decrypted */
DWORD *pdwRoundKey) /* [in] round keys for decryption */
{
DWORD L0, L1, R0, R1; /* Iuput/output values at each rounds */
DWORD T0, T1; /* Temporary variables for round function F */
DWORD *K = pdwRoundKey; /* Pointer of round keys */
/* Set up input values for first round */
L0 = ((DWORD *)pbData)[0];
L1 = ((DWORD *)pbData)[1];
R0 = ((DWORD *)pbData)[2];
R1 = ((DWORD *)pbData)[3];
/* Reorder for big endian */
#ifndef SEED_BIG_ENDIAN
L0 = EndianChange(L0);
L1 = EndianChange(L1);
R0 = EndianChange(R0);
R1 = EndianChange(R1);
#endif
SeedRound(L0, L1, R0, R1, K+30); /* Round 1 */
SeedRound(R0, R1, L0, L1, K+28); /* Round 2 */
SeedRound(L0, L1, R0, R1, K+26); /* Round 3 */
SeedRound(R0, R1, L0, L1, K+24); /* Round 4 */
SeedRound(L0, L1, R0, R1, K+22); /* Round 5 */
SeedRound(R0, R1, L0, L1, K+20); /* Round 6 */
SeedRound(L0, L1, R0, R1, K+18); /* Round 7 */
SeedRound(R0, R1, L0, L1, K+16); /* Round 8 */
SeedRound(L0, L1, R0, R1, K+14); /* Round 9 */
SeedRound(R0, R1, L0, L1, K+12); /* Round 10 */
SeedRound(L0, L1, R0, R1, K+10); /* Round 11 */
SeedRound(R0, R1, L0, L1, K+ 8); /* Round 12 */
SeedRound(L0, L1, R0, R1, K+ 6); /* Round 13 */
SeedRound(R0, R1, L0, L1, K+ 4); /* Round 14 */
SeedRound(L0, L1, R0, R1, K+ 2); /* Round 15 */
SeedRound(R0, R1, L0, L1, K+ 0); /* Round 16 */
#ifndef SEED_BIG_ENDIAN
L0 = EndianChange(L0);
L1 = EndianChange(L1);
R0 = EndianChange(R0);
R1 = EndianChange(R1);
#endif
/* Copy output values from last round to pbData */
((DWORD *)pbData)[0] = R0;
((DWORD *)pbData)[1] = R1;
((DWORD *)pbData)[2] = L0;
((DWORD *)pbData)[3] = L1;
}
/************************ Constants for Key schedule **************************/
/* KC0 = golden ratio; KCi = ROTL(KCi-1, 1) */
#define KC0 0x9e3779b9UL
#define KC1 0x3c6ef373UL
#define KC2 0x78dde6e6UL
#define KC3 0xf1bbcdccUL
#define KC4 0xe3779b99UL
#define KC5 0xc6ef3733UL
#define KC6 0x8dde6e67UL
#define KC7 0x1bbcdccfUL
#define KC8 0x3779b99eUL
#define KC9 0x6ef3733cUL
#define KC10 0xdde6e678UL
#define KC11 0xbbcdccf1UL
#define KC12 0x779b99e3UL
#define KC13 0xef3733c6UL
#define KC14 0xde6e678dUL
#define KC15 0xbcdccf1bUL
/************************** Macros for Key schedule ***************************/
#define RoundKeyUpdate0(K, A, B, C, D, KC) { \
T0 = A + C - KC; \
T1 = B + KC - D; \
(K)[0] = SS0[GetB0(T0)] ^ SS1[GetB1(T0)] ^ \
SS2[GetB2(T0)] ^ SS3[GetB3(T0)]; \
(K)[1] = SS0[GetB0(T1)] ^ SS1[GetB1(T1)] ^ \
SS2[GetB2(T1)] ^ SS3[GetB3(T1)]; \
T0 = A; \
A = (A>>8) ^ (B<<24); \
B = (B>>8) ^ (T0<<24); \
}
#define RoundKeyUpdate1(K, A, B, C, D, KC) { \
T0 = A + C - KC; \
T1 = B + KC - D; \
(K)[0] = SS0[GetB0(T0)] ^ SS1[GetB1(T0)] ^ \
SS2[GetB2(T0)] ^ SS3[GetB3(T0)]; \
(K)[1] = SS0[GetB0(T1)] ^ SS1[GetB1(T1)] ^ \
SS2[GetB2(T1)] ^ SS3[GetB3(T1)]; \
T0 = C; \
C = (C<<8) ^ (D>>24); \
D = (D<<8) ^ (T0>>24); \
}
/******************************** Key Schedule ********************************/
void SeedRoundKey(
DWORD *pdwRoundKey, /* [out] round keys for encryption or decryption */
BYTE *pbUserKey) /* [in] secret user key */
{
DWORD A, B, C, D; /* Iuput/output values at each rounds */
DWORD T0, T1; /* Temporary variable */
DWORD *K = pdwRoundKey; /* Pointer of round keys */
/* Set up input values for Key Schedule */
A = ((DWORD *)pbUserKey)[0];
B = ((DWORD *)pbUserKey)[1];
C = ((DWORD *)pbUserKey)[2];
D = ((DWORD *)pbUserKey)[3];
/* Reorder for big endian */
#ifndef SEED_BIG_ENDIAN
A = EndianChange(A);
B = EndianChange(B);
C = EndianChange(C);
D = EndianChange(D);
#endif
/* i-th round keys( K_i,0 and K_i,1 ) are denoted as K[2*(i-1)] and K[2*i-1], respectively */
RoundKeyUpdate0(K , A, B, C, D, KC0 ); /* K_1,0 and K_1,1 */
RoundKeyUpdate1(K+ 2, A, B, C, D, KC1 ); /* K_2,0 and K_2,1 */
RoundKeyUpdate0(K+ 4, A, B, C, D, KC2 ); /* K_3,0 and K_3,1 */
RoundKeyUpdate1(K+ 6, A, B, C, D, KC3 ); /* K_4,0 and K_4,1 */
RoundKeyUpdate0(K+ 8, A, B, C, D, KC4 ); /* K_5,0 and K_5,1 */
RoundKeyUpdate1(K+10, A, B, C, D, KC5 ); /* K_6,0 and K_6,1 */
RoundKeyUpdate0(K+12, A, B, C, D, KC6 ); /* K_7,0 and K_7,1 */
RoundKeyUpdate1(K+14, A, B, C, D, KC7 ); /* K_8,0 and K_8,1 */
RoundKeyUpdate0(K+16, A, B, C, D, KC8 ); /* K_9,0 and K_9,1 */
RoundKeyUpdate1(K+18, A, B, C, D, KC9 ); /* K_10,0 and K_10,1 */
RoundKeyUpdate0(K+20, A, B, C, D, KC10); /* K_11,0 and K_11,1 */
RoundKeyUpdate1(K+22, A, B, C, D, KC11); /* K_12,0 and K_12,1 */
RoundKeyUpdate0(K+24, A, B, C, D, KC12); /* K_13,0 and K_13,1 */
RoundKeyUpdate1(K+26, A, B, C, D, KC13); /* K_14,0 and K_14,1 */
RoundKeyUpdate0(K+28, A, B, C, D, KC14); /* K_15,0 and K_15,1 */
T0 = A + C - KC15;
T1 = B - D + KC15;
K[30] = SS0[GetB0(T0)] ^ SS1[GetB1(T0)] ^ /* K_16,0 */
SS2[GetB2(T0)] ^ SS3[GetB3(T0)];
K[31] = SS0[GetB0(T1)] ^ SS1[GetB1(T1)] ^ /* K_16,1 */
SS2[GetB2(T1)] ^ SS3[GetB3(T1)];
}
/*********************************** END **************************************/