597 lines
20 KiB
C
597 lines
20 KiB
C
/*
|
|
* A 32-bit implementation for ARIA
|
|
*
|
|
* follows the specifications given in
|
|
* the ARIA specification at
|
|
* http://www.nsri.re.kr/ARIA/
|
|
*
|
|
* Note:
|
|
* - Main body optimized for speed for 32 bit platforms
|
|
* * Utilizes 32-bit optimization techniques presented in ICISC 2003
|
|
* * Only four 32-bit tables are used
|
|
*
|
|
* - Implemented some ideas for optimization from the creators of ARIA,
|
|
* and adopted some ideas from works submitted to ARIA implementation contest on Aug. 2004.
|
|
*
|
|
* - Handles endian problem pretty well.
|
|
* * For optimization, for little endian architecture key setup functions return
|
|
* endian-reversed round keys; Crypt() function handles this correctly.
|
|
*
|
|
* 17, January 2005
|
|
* Aaram Yun
|
|
* National Security Research Institute, KOREA
|
|
*
|
|
* Substantial portion of the code originally written by Jin Hong.
|
|
*
|
|
*/
|
|
|
|
#include "stdio.h"
|
|
#include "aria.h"
|
|
|
|
/* 사용 플랫폼의 endian 특성에 따라 LITTLE_ENDIAN 혹은
|
|
* BIG_ENDIAN 둘 중 하나를 정의해야 컴파일 됩니다.
|
|
* Windows+Intel 플랫폼의 경우에는 LITTLE_ENDIAN이고,
|
|
* 그 외에는 많은 경우 BIG_ENDIAN입니다. 잘 모르겠으면
|
|
* 아무 쪽이나 선택해서 컴파일 후 실행하십시오. ARIA_test()
|
|
* 함수에서 ENDIAN 확인을 하기 때문에 올바른 선택이었는지를
|
|
* 점검할 수 있습니다. */
|
|
|
|
#define LITTLE_ENDIAN
|
|
//#define BIG_ENDIAN
|
|
|
|
/*********************************************************/
|
|
|
|
#ifdef BIG_ENDIAN
|
|
#undef LITTLE_ENDIAN
|
|
#else
|
|
#ifndef LITTLE_ENDIAN
|
|
#error In order to compile this, you have to \
|
|
define either LITTLE_ENDIAN or BIG_ENDIAN. \
|
|
If unsure, try define either of one and run \
|
|
checkEndian() function to see if your guess \
|
|
is correct.
|
|
#endif
|
|
#endif
|
|
|
|
const DWORD KRK[3][4] = {
|
|
{0x517cc1b7, 0x27220a94, 0xfe13abe8, 0xfa9a6ee0},
|
|
{0x6db14acc, 0x9e21c820, 0xff28b1d5, 0xef5de2b0},
|
|
{0xdb92371d, 0x2126e970, 0x03249775, 0x04e8c90e}
|
|
};
|
|
|
|
/* S-box들을 정의하기 위한 마크로. */
|
|
|
|
#define AAA(V) 0x ## 00 ## V ## V ## V
|
|
#define BBB(V) 0x ## V ## 00 ## V ## V
|
|
#define CCC(V) 0x ## V ## V ## 00 ## V
|
|
#define DDD(V) 0x ## V ## V ## V ## 00
|
|
#define XX(NNN,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc,xd,xe,xf) \
|
|
NNN(x0),NNN(x1),NNN(x2),NNN(x3),NNN(x4),NNN(x5),NNN(x6),NNN(x7), \
|
|
NNN(x8),NNN(x9),NNN(xa),NNN(xb),NNN(xc),NNN(xd),NNN(xe),NNN(xf)
|
|
|
|
const DWORD S1[256] = {
|
|
XX(AAA,63,7c,77,7b,f2,6b,6f,c5,30,01,67,2b,fe,d7,ab,76),
|
|
XX(AAA,ca,82,c9,7d,fa,59,47,f0,ad,d4,a2,af,9c,a4,72,c0),
|
|
XX(AAA,b7,fd,93,26,36,3f,f7,cc,34,a5,e5,f1,71,d8,31,15),
|
|
XX(AAA,04,c7,23,c3,18,96,05,9a,07,12,80,e2,eb,27,b2,75),
|
|
XX(AAA,09,83,2c,1a,1b,6e,5a,a0,52,3b,d6,b3,29,e3,2f,84),
|
|
XX(AAA,53,d1,00,ed,20,fc,b1,5b,6a,cb,be,39,4a,4c,58,cf),
|
|
XX(AAA,d0,ef,aa,fb,43,4d,33,85,45,f9,02,7f,50,3c,9f,a8),
|
|
XX(AAA,51,a3,40,8f,92,9d,38,f5,bc,b6,da,21,10,ff,f3,d2),
|
|
XX(AAA,cd,0c,13,ec,5f,97,44,17,c4,a7,7e,3d,64,5d,19,73),
|
|
XX(AAA,60,81,4f,dc,22,2a,90,88,46,ee,b8,14,de,5e,0b,db),
|
|
XX(AAA,e0,32,3a,0a,49,06,24,5c,c2,d3,ac,62,91,95,e4,79),
|
|
XX(AAA,e7,c8,37,6d,8d,d5,4e,a9,6c,56,f4,ea,65,7a,ae,08),
|
|
XX(AAA,ba,78,25,2e,1c,a6,b4,c6,e8,dd,74,1f,4b,bd,8b,8a),
|
|
XX(AAA,70,3e,b5,66,48,03,f6,0e,61,35,57,b9,86,c1,1d,9e),
|
|
XX(AAA,e1,f8,98,11,69,d9,8e,94,9b,1e,87,e9,ce,55,28,df),
|
|
XX(AAA,8c,a1,89,0d,bf,e6,42,68,41,99,2d,0f,b0,54,bb,16)
|
|
};
|
|
|
|
const DWORD S2[256] = {
|
|
XX(BBB,e2,4e,54,fc,94,c2,4a,cc,62,0d,6a,46,3c,4d,8b,d1),
|
|
XX(BBB,5e,fa,64,cb,b4,97,be,2b,bc,77,2e,03,d3,19,59,c1),
|
|
XX(BBB,1d,06,41,6b,55,f0,99,69,ea,9c,18,ae,63,df,e7,bb),
|
|
XX(BBB,00,73,66,fb,96,4c,85,e4,3a,09,45,aa,0f,ee,10,eb),
|
|
XX(BBB,2d,7f,f4,29,ac,cf,ad,91,8d,78,c8,95,f9,2f,ce,cd),
|
|
XX(BBB,08,7a,88,38,5c,83,2a,28,47,db,b8,c7,93,a4,12,53),
|
|
XX(BBB,ff,87,0e,31,36,21,58,48,01,8e,37,74,32,ca,e9,b1),
|
|
XX(BBB,b7,ab,0c,d7,c4,56,42,26,07,98,60,d9,b6,b9,11,40),
|
|
XX(BBB,ec,20,8c,bd,a0,c9,84,04,49,23,f1,4f,50,1f,13,dc),
|
|
XX(BBB,d8,c0,9e,57,e3,c3,7b,65,3b,02,8f,3e,e8,25,92,e5),
|
|
XX(BBB,15,dd,fd,17,a9,bf,d4,9a,7e,c5,39,67,fe,76,9d,43),
|
|
XX(BBB,a7,e1,d0,f5,68,f2,1b,34,70,05,a3,8a,d5,79,86,a8),
|
|
XX(BBB,30,c6,51,4b,1e,a6,27,f6,35,d2,6e,24,16,82,5f,da),
|
|
XX(BBB,e6,75,a2,ef,2c,b2,1c,9f,5d,6f,80,0a,72,44,9b,6c),
|
|
XX(BBB,90,0b,5b,33,7d,5a,52,f3,61,a1,f7,b0,d6,3f,7c,6d),
|
|
XX(BBB,ed,14,e0,a5,3d,22,b3,f8,89,de,71,1a,af,ba,b5,81)
|
|
};
|
|
|
|
const DWORD X1[256] = {
|
|
XX(CCC,52,09,6a,d5,30,36,a5,38,bf,40,a3,9e,81,f3,d7,fb),
|
|
XX(CCC,7c,e3,39,82,9b,2f,ff,87,34,8e,43,44,c4,de,e9,cb),
|
|
XX(CCC,54,7b,94,32,a6,c2,23,3d,ee,4c,95,0b,42,fa,c3,4e),
|
|
XX(CCC,08,2e,a1,66,28,d9,24,b2,76,5b,a2,49,6d,8b,d1,25),
|
|
XX(CCC,72,f8,f6,64,86,68,98,16,d4,a4,5c,cc,5d,65,b6,92),
|
|
XX(CCC,6c,70,48,50,fd,ed,b9,da,5e,15,46,57,a7,8d,9d,84),
|
|
XX(CCC,90,d8,ab,00,8c,bc,d3,0a,f7,e4,58,05,b8,b3,45,06),
|
|
XX(CCC,d0,2c,1e,8f,ca,3f,0f,02,c1,af,bd,03,01,13,8a,6b),
|
|
XX(CCC,3a,91,11,41,4f,67,dc,ea,97,f2,cf,ce,f0,b4,e6,73),
|
|
XX(CCC,96,ac,74,22,e7,ad,35,85,e2,f9,37,e8,1c,75,df,6e),
|
|
XX(CCC,47,f1,1a,71,1d,29,c5,89,6f,b7,62,0e,aa,18,be,1b),
|
|
XX(CCC,fc,56,3e,4b,c6,d2,79,20,9a,db,c0,fe,78,cd,5a,f4),
|
|
XX(CCC,1f,dd,a8,33,88,07,c7,31,b1,12,10,59,27,80,ec,5f),
|
|
XX(CCC,60,51,7f,a9,19,b5,4a,0d,2d,e5,7a,9f,93,c9,9c,ef),
|
|
XX(CCC,a0,e0,3b,4d,ae,2a,f5,b0,c8,eb,bb,3c,83,53,99,61),
|
|
XX(CCC,17,2b,04,7e,ba,77,d6,26,e1,69,14,63,55,21,0c,7d)
|
|
};
|
|
|
|
const DWORD X2[256] = {
|
|
XX(DDD,30,68,99,1b,87,b9,21,78,50,39,db,e1,72,09,62,3c),
|
|
XX(DDD,3e,7e,5e,8e,f1,a0,cc,a3,2a,1d,fb,b6,d6,20,c4,8d),
|
|
XX(DDD,81,65,f5,89,cb,9d,77,c6,57,43,56,17,d4,40,1a,4d),
|
|
XX(DDD,c0,63,6c,e3,b7,c8,64,6a,53,aa,38,98,0c,f4,9b,ed),
|
|
XX(DDD,7f,22,76,af,dd,3a,0b,58,67,88,06,c3,35,0d,01,8b),
|
|
XX(DDD,8c,c2,e6,5f,02,24,75,93,66,1e,e5,e2,54,d8,10,ce),
|
|
XX(DDD,7a,e8,08,2c,12,97,32,ab,b4,27,0a,23,df,ef,ca,d9),
|
|
XX(DDD,b8,fa,dc,31,6b,d1,ad,19,49,bd,51,96,ee,e4,a8,41),
|
|
XX(DDD,da,ff,cd,55,86,36,be,61,52,f8,bb,0e,82,48,69,9a),
|
|
XX(DDD,e0,47,9e,5c,04,4b,34,15,79,26,a7,de,29,ae,92,d7),
|
|
XX(DDD,84,e9,d2,ba,5d,f3,c5,b0,bf,a4,3b,71,44,46,2b,fc),
|
|
XX(DDD,eb,6f,d5,f6,14,fe,7c,70,5a,7d,fd,2f,18,83,16,a5),
|
|
XX(DDD,91,1f,05,95,74,a9,c1,5b,4a,85,6d,13,07,4f,4e,45),
|
|
XX(DDD,b2,0f,c9,1c,a6,bc,ec,73,90,7b,cf,59,8f,a1,f9,2d),
|
|
XX(DDD,f2,b1,00,94,37,9f,d0,2e,9c,6e,28,3f,80,f0,3d,d3),
|
|
XX(DDD,25,8a,b5,e7,42,b3,c7,ea,f7,4c,11,33,03,a2,ac,60)
|
|
};
|
|
|
|
/* BY(X, Y)는 DWORD X의 Y번째 바이트
|
|
* BRF(T,R)은 T>>R의 하위 1바이트
|
|
* WO(X, Y)는 BYTE array X를 DWORD array로 간주할 때 Y번째 DWORD
|
|
*/
|
|
|
|
#define BY(X,Y) (((BYTE *)(&X))[Y])
|
|
#define BRF(T,R) ((BYTE)((T)>>(R)))
|
|
#define WO(X,Y) (((DWORD *)(X))[Y])
|
|
|
|
/* abcd의 4 BYTEA로 된 DWORD를 dcba로 변환하는 함수 */
|
|
#if defined(_MSC_VER)
|
|
/* MSC 사용 환경의 경우에는 _lrotr() 함수를
|
|
* 이용할 수 있으므로 약간의 속도 향상이 가능하다. */
|
|
#define ReverseDWORD(W) { \
|
|
(W)=(0xff00ff00 & _lrotr((W), 8)) ^ (0x00ff00ff & _lrotl((W), 8)); \
|
|
}
|
|
#else
|
|
#define ReverseDWORD(W) { \
|
|
(W)=(W)<<24 ^ (W)>>24 ^ ((W)&0x0000ff00)<<8 ^ ((W)&0x00ff0000)>>8; \
|
|
}
|
|
#endif
|
|
|
|
/* BYTEA array를 DWORD에 싣는 함수. LITTLE_ENDIAN의 경우
|
|
* 엔디안 변환 과정을 거친다. */
|
|
#ifdef LITTLE_ENDIAN
|
|
#define WordLoad(ORIG, DEST) { \
|
|
DWORD ___t; \
|
|
BY(___t,0)=BY(ORIG,3); \
|
|
BY(___t,1)=BY(ORIG,2); \
|
|
BY(___t,2)=BY(ORIG,1); \
|
|
BY(___t,3)=BY(ORIG,0); \
|
|
DEST=___t; \
|
|
}
|
|
#else
|
|
#define WordLoad(ORIG, DEST) { \
|
|
DEST = ORIG; \
|
|
}
|
|
#endif
|
|
|
|
#if defined(_MSC_VER)
|
|
#undef WordLoad
|
|
#define WordLoad(ORIG, DEST) { \
|
|
(DEST) = (0xff00ff00 & _lrotr((ORIG), 8)) ^ (0x00ff00ff & _lrotl((ORIG), 8)); \
|
|
}
|
|
#endif
|
|
|
|
/* Key XOR Layer */
|
|
#define KXL { \
|
|
t0^=WO(rk,0); t1^=WO(rk,1); t2^=WO(rk,2); t3^=WO(rk,3); \
|
|
rk += 16; \
|
|
}
|
|
|
|
/* S-Box Layer 1 + M 변환 */
|
|
#define SBL1_M(T0,T1,T2,T3) { \
|
|
T0=S1[BRF(T0,24)]^S2[BRF(T0,16)]^X1[BRF(T0,8)]^X2[BRF(T0,0)]; \
|
|
T1=S1[BRF(T1,24)]^S2[BRF(T1,16)]^X1[BRF(T1,8)]^X2[BRF(T1,0)]; \
|
|
T2=S1[BRF(T2,24)]^S2[BRF(T2,16)]^X1[BRF(T2,8)]^X2[BRF(T2,0)]; \
|
|
T3=S1[BRF(T3,24)]^S2[BRF(T3,16)]^X1[BRF(T3,8)]^X2[BRF(T3,0)]; \
|
|
}
|
|
/* S-Box Layer 2 + M 변환 */
|
|
#define SBL2_M(T0,T1,T2,T3) { \
|
|
T0=X1[BRF(T0,24)]^X2[BRF(T0,16)]^S1[BRF(T0,8)]^S2[BRF(T0,0)]; \
|
|
T1=X1[BRF(T1,24)]^X2[BRF(T1,16)]^S1[BRF(T1,8)]^S2[BRF(T1,0)]; \
|
|
T2=X1[BRF(T2,24)]^X2[BRF(T2,16)]^S1[BRF(T2,8)]^S2[BRF(T2,0)]; \
|
|
T3=X1[BRF(T3,24)]^X2[BRF(T3,16)]^S1[BRF(T3,8)]^S2[BRF(T3,0)]; \
|
|
}
|
|
/* 워드 단위의 변환 */
|
|
#define MM(T0,T1,T2,T3) { \
|
|
(T1)^=(T2); (T2)^=(T3); (T0)^=(T1); \
|
|
(T3)^=(T1); (T2)^=(T0); (T1)^=(T2); \
|
|
}
|
|
/* P 변환. 확산 계층의 중간에 들어가는 바이트 단위 변환이다.
|
|
* 이 부분은 endian과 무관하다. */
|
|
#if defined(_MSC_VER)
|
|
#define P(T0,T1,T2,T3) { \
|
|
(T1) = (((T1)<< 8)&0xff00ff00) ^ (((T1)>> 8)&0x00ff00ff); \
|
|
(T2) = _lrotr((T2),16); \
|
|
ReverseDWORD((T3)); \
|
|
}
|
|
#else
|
|
#define P(T0,T1,T2,T3) { \
|
|
(T1) = (((T1)<< 8)&0xff00ff00) ^ (((T1)>> 8)&0x00ff00ff); \
|
|
(T2) = (((T2)<<16)&0xffff0000) ^ (((T2)>>16)&0x0000ffff); \
|
|
ReverseDWORD((T3)); \
|
|
}
|
|
#endif
|
|
|
|
/* FO: 홀수번째 라운드의 F 함수
|
|
* FE: 짝수번째 라운드의 F 함수
|
|
* MM과 P는 바이트 단위에서 endian에 무관하게 동일한 결과를 주며,
|
|
* 또한 endian 변환과 가환이다. 또한, SBLi_M은 LITTLE_ENDIAN에서
|
|
* 결과적으로 DWORD 단위로 endian을 뒤집은 결과를 준다.
|
|
* 즉, FO, FE는 BIG_ENDIAN 환경에서는 ARIA spec과 동일한 결과를,
|
|
* LITTLE_ENDIAN 환경에서는 ARIA spec에서 정의한 변환+endian 변환을
|
|
* 준다. */
|
|
#define FO {SBL1_M(t0,t1,t2,t3) MM(t0,t1,t2,t3) P(t0,t1,t2,t3) MM(t0,t1,t2,t3)}
|
|
#define FE {SBL2_M(t0,t1,t2,t3) MM(t0,t1,t2,t3) P(t2,t3,t0,t1) MM(t0,t1,t2,t3)}
|
|
|
|
/* n-bit right shift of Y XORed to X */
|
|
/* DWORD 단위로 정의된 블록에서의 회전 + XOR이다. */
|
|
#define GSRK(X, Y, n) { \
|
|
q = 4-((n)/32); \
|
|
r = (n) % 32; \
|
|
WO(rk,0) = ((X)[0]) ^ (((Y)[(q )%4])>>r) ^ (((Y)[(q+3)%4])<<(32-r)); \
|
|
WO(rk,1) = ((X)[1]) ^ (((Y)[(q+1)%4])>>r) ^ (((Y)[(q )%4])<<(32-r)); \
|
|
WO(rk,2) = ((X)[2]) ^ (((Y)[(q+2)%4])>>r) ^ (((Y)[(q+1)%4])<<(32-r)); \
|
|
WO(rk,3) = ((X)[3]) ^ (((Y)[(q+3)%4])>>r) ^ (((Y)[(q+2)%4])<<(32-r)); \
|
|
rk += 16; \
|
|
}
|
|
|
|
/* DecKeySetup()에서 사용하는 마크로 */
|
|
#if defined(_MSC_VER)
|
|
#define WordM1(X,Y) { \
|
|
w=_lrotr((X), 8); \
|
|
(Y)=w^_lrotr((X)^w, 16); \
|
|
}
|
|
#else
|
|
#define DWORDM1(X,Y) { \
|
|
Y=(X)<<8 ^ (X)>>8 ^ (X)<<16 ^ (X)>>16 ^ (X)<<24 ^ (X)>>24; \
|
|
}
|
|
#endif
|
|
|
|
/* 암호화 함수.
|
|
* const BYTE *i: 입력
|
|
* int Nr: 라운드 수
|
|
* const BYTE *rk: 라운드 키들
|
|
* BYTE *o: 출력
|
|
*/
|
|
void Crypt(const BYTE* i, int Nr, const BYTE* rk, BYTE* o)
|
|
{
|
|
register DWORD t0, t1, t2, t3;
|
|
|
|
WordLoad(WO(i, 0), t0); WordLoad(WO(i, 1), t1);
|
|
WordLoad(WO(i, 2), t2); WordLoad(WO(i, 3), t3);
|
|
|
|
if (Nr > 12) { KXL FO KXL FE }
|
|
if (Nr > 14) { KXL FO KXL FE }
|
|
KXL FO KXL FE KXL FO KXL FE KXL FO KXL FE
|
|
KXL FO KXL FE KXL FO KXL FE KXL FO KXL
|
|
|
|
/* 최종 라운드는 특별함 */
|
|
#ifdef LITTLE_ENDIAN
|
|
o[0] = (BYTE)(X1[BRF(t0, 24)]) ^ rk[3];
|
|
o[1] = (BYTE)(X2[BRF(t0, 16)] >> 8) ^ rk[2];
|
|
o[2] = (BYTE)(S1[BRF(t0, 8)]) ^ rk[1];
|
|
o[3] = (BYTE)(S2[BRF(t0, 0)]) ^ rk[0];
|
|
o[4] = (BYTE)(X1[BRF(t1, 24)]) ^ rk[7];
|
|
o[5] = (BYTE)(X2[BRF(t1, 16)] >> 8) ^ rk[6];
|
|
o[6] = (BYTE)(S1[BRF(t1, 8)]) ^ rk[5];
|
|
o[7] = (BYTE)(S2[BRF(t1, 0)]) ^ rk[4];
|
|
o[8] = (BYTE)(X1[BRF(t2, 24)]) ^ rk[11];
|
|
o[9] = (BYTE)(X2[BRF(t2, 16)] >> 8) ^ rk[10];
|
|
o[10] = (BYTE)(S1[BRF(t2, 8)]) ^ rk[9];
|
|
o[11] = (BYTE)(S2[BRF(t2, 0)]) ^ rk[8];
|
|
o[12] = (BYTE)(X1[BRF(t3, 24)]) ^ rk[15];
|
|
o[13] = (BYTE)(X2[BRF(t3, 16)] >> 8) ^ rk[14];
|
|
o[14] = (BYTE)(S1[BRF(t3, 8)]) ^ rk[13];
|
|
o[15] = (BYTE)(S2[BRF(t3, 0)]) ^ rk[12];
|
|
#else
|
|
o[0] = (BYTE)(X1[BRF(t0, 24)]);
|
|
o[1] = (BYTE)(X2[BRF(t0, 16)] >> 8);
|
|
o[2] = (BYTE)(S1[BRF(t0, 8)]);
|
|
o[3] = (BYTE)(S2[BRF(t0, 0)]);
|
|
o[4] = (BYTE)(X1[BRF(t1, 24)]);
|
|
o[5] = (BYTE)(X2[BRF(t1, 16)] >> 8);
|
|
o[6] = (BYTE)(S1[BRF(t1, 8)]);
|
|
o[7] = (BYTE)(S2[BRF(t1, 0)]);
|
|
o[8] = (BYTE)(X1[BRF(t2, 24)]);
|
|
o[9] = (BYTE)(X2[BRF(t2, 16)] >> 8);
|
|
o[10] = (BYTE)(S1[BRF(t2, 8)]);
|
|
o[11] = (BYTE)(S2[BRF(t2, 0)]);
|
|
o[12] = (BYTE)(X1[BRF(t3, 24)]);
|
|
o[13] = (BYTE)(X2[BRF(t3, 16)] >> 8);
|
|
o[14] = (BYTE)(S1[BRF(t3, 8)]);
|
|
o[15] = (BYTE)(S2[BRF(t3, 0)]);
|
|
WO(o, 0) ^= WO(rk, 0); WO(o, 1) ^= WO(rk, 1);
|
|
WO(o, 2) ^= WO(rk, 2); WO(o, 3) ^= WO(rk, 3);
|
|
#endif
|
|
}
|
|
|
|
/* 암호화 라운드 키 생성
|
|
* const BYTE *mk: 마스터 키
|
|
* BYTE *rk: 라운드 키
|
|
* int keyBits: 마스터 키의 길이
|
|
*/
|
|
int EncKeySetup(const BYTE* mk, BYTE* rk, int keyBits)
|
|
{
|
|
register DWORD t0, t1, t2, t3;
|
|
DWORD w0[4], w1[4], w2[4], w3[4];
|
|
int q, r;
|
|
|
|
WordLoad(WO(mk, 0), w0[0]); WordLoad(WO(mk, 1), w0[1]);
|
|
WordLoad(WO(mk, 2), w0[2]); WordLoad(WO(mk, 3), w0[3]);
|
|
|
|
q = (keyBits - 128) / 64;
|
|
t0 = w0[0] ^ KRK[q][0]; t1 = w0[1] ^ KRK[q][1];
|
|
t2 = w0[2] ^ KRK[q][2]; t3 = w0[3] ^ KRK[q][3];
|
|
|
|
FO;
|
|
|
|
if (keyBits > 128)
|
|
{
|
|
WordLoad(WO(mk, 4), w1[0]);
|
|
WordLoad(WO(mk, 5), w1[1]);
|
|
if (keyBits > 192)
|
|
{
|
|
WordLoad(WO(mk, 6), w1[2]);
|
|
WordLoad(WO(mk, 7), w1[3]);
|
|
}
|
|
else
|
|
{
|
|
w1[2] = w1[3] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
w1[0] = w1[1] = w1[2] = w1[3] = 0;
|
|
}
|
|
|
|
w1[0] ^= t0; w1[1] ^= t1; w1[2] ^= t2; w1[3] ^= t3;
|
|
t0 = w1[0]; t1 = w1[1]; t2 = w1[2]; t3 = w1[3];
|
|
|
|
q = (q == 2) ? 0 : (q + 1);
|
|
t0 ^= KRK[q][0]; t1 ^= KRK[q][1]; t2 ^= KRK[q][2]; t3 ^= KRK[q][3];
|
|
|
|
FE;
|
|
|
|
t0 ^= w0[0]; t1 ^= w0[1]; t2 ^= w0[2]; t3 ^= w0[3];
|
|
w2[0] = t0; w2[1] = t1; w2[2] = t2; w2[3] = t3;
|
|
|
|
q = (q == 2) ? 0 : (q + 1);
|
|
t0 ^= KRK[q][0]; t1 ^= KRK[q][1]; t2 ^= KRK[q][2]; t3 ^= KRK[q][3];
|
|
|
|
FO;
|
|
|
|
w3[0] = t0 ^ w1[0]; w3[1] = t1 ^ w1[1]; w3[2] = t2 ^ w1[2]; w3[3] = t3 ^ w1[3];
|
|
|
|
GSRK(w0, w1, 19);
|
|
GSRK(w1, w2, 19);
|
|
GSRK(w2, w3, 19);
|
|
GSRK(w3, w0, 19);
|
|
GSRK(w0, w1, 31);
|
|
GSRK(w1, w2, 31);
|
|
GSRK(w2, w3, 31);
|
|
GSRK(w3, w0, 31);
|
|
GSRK(w0, w1, 67);
|
|
GSRK(w1, w2, 67);
|
|
GSRK(w2, w3, 67);
|
|
GSRK(w3, w0, 67);
|
|
GSRK(w0, w1, 97);
|
|
|
|
if (keyBits > 128)
|
|
{
|
|
GSRK(w1, w2, 97);
|
|
GSRK(w2, w3, 97);
|
|
}
|
|
if (keyBits > 192)
|
|
{
|
|
GSRK(w3, w0, 97);
|
|
GSRK(w0, w1, 109);
|
|
}
|
|
|
|
return (keyBits + 256) / 32;
|
|
}
|
|
|
|
/* 복호화 라운드 키 생성
|
|
* const BYTE *mk: 마스터 키
|
|
* BYTE *rk: 라운드 키
|
|
* int keyBits: 마스터 키의 길이
|
|
*/
|
|
int DecKeySetup(const BYTE* mk, BYTE* rk, int keyBits)
|
|
{
|
|
DWORD* a, * z;
|
|
int rValue;
|
|
|
|
#if defined(_MSC_VER)
|
|
register DWORD w;
|
|
#else
|
|
register BYTEA sum;
|
|
#endif
|
|
|
|
register DWORD t0, t1, t2, t3;
|
|
DWORD s0, s1, s2, s3;
|
|
|
|
rValue = EncKeySetup(mk, rk, keyBits);
|
|
a = (DWORD*)(rk); z = a + rValue * 4;
|
|
t0 = a[0]; t1 = a[1]; t2 = a[2]; t3 = a[3];
|
|
a[0] = z[0]; a[1] = z[1]; a[2] = z[2]; a[3] = z[3];
|
|
z[0] = t0; z[1] = t1; z[2] = t2; z[3] = t3;
|
|
a += 4; z -= 4;
|
|
|
|
for (; a < z; a += 4, z -= 4)
|
|
{
|
|
WordM1(a[0], t0); WordM1(a[1], t1); WordM1(a[2], t2); WordM1(a[3], t3);
|
|
MM(t0, t1, t2, t3) P(t0, t1, t2, t3) MM(t0, t1, t2, t3)
|
|
s0 = t0; s1 = t1; s2 = t2; s3 = t3;
|
|
WordM1(z[0], t0); WordM1(z[1], t1); WordM1(z[2], t2); WordM1(z[3], t3);
|
|
MM(t0, t1, t2, t3) P(t0, t1, t2, t3) MM(t0, t1, t2, t3)
|
|
a[0] = t0; a[1] = t1; a[2] = t2; a[3] = t3;
|
|
z[0] = s0; z[1] = s1; z[2] = s2; z[3] = s3;
|
|
}
|
|
|
|
WordM1(a[0], t0); WordM1(a[1], t1); WordM1(a[2], t2); WordM1(a[3], t3);
|
|
MM(t0, t1, t2, t3) P(t0, t1, t2, t3) MM(t0, t1, t2, t3)
|
|
z[0] = t0; z[1] = t1; z[2] = t2; z[3] = t3;
|
|
|
|
return rValue;
|
|
}
|
|
|
|
void ARIA_Crypt(const BYTE* pIn, BYTE* pOut, int nIn, ARIA_Key* aKey)
|
|
{
|
|
int i, p;
|
|
int n = nIn / 16;
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
p = 16 * i;
|
|
Crypt(pIn + p, aKey->nRoundCnt, (BYTE*)&aKey->pRoundKey, pOut + p);
|
|
}
|
|
}
|
|
|
|
void ARIA_EncKeySetup(const BYTE* mk, ARIA_Key* aKey, int keyBits)
|
|
{
|
|
aKey->nRoundCnt = EncKeySetup(mk, (BYTE*)&aKey->pRoundKey, keyBits);
|
|
}
|
|
|
|
void ARIA_DecKeySetup(const BYTE* mk, ARIA_Key* aKey, int keyBits)
|
|
{
|
|
aKey->nRoundCnt = DecKeySetup(mk, (BYTE*)&aKey->pRoundKey, keyBits);
|
|
}
|
|
|
|
void printBlockOfLength(BYTE* b, int len)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++, b++) {
|
|
printf("%02x", *b);
|
|
if (i % 4 == 3 && i < len - 1) printf(" ");
|
|
}
|
|
}
|
|
void printBlock(BYTE* b)
|
|
{
|
|
printBlockOfLength(b, 16);
|
|
}
|
|
|
|
/* ARIA_test(): 기본적인 테스트를 위한 함수로,
|
|
* 주된 목적은 구현 정확성 검증이라기보다는 제대로 포팅이
|
|
* 이루어졌나 기본적인 확인을 위한 것임. 흔하지
|
|
* 않은 환경으로 포팅했을 경우에는 이 테스트 결과에
|
|
* 만족할 것이 아니라 reference 코드의 결과와 비교하여
|
|
* 충분한 구현 정확성 검증을 거칠 것을 권고함.
|
|
*/
|
|
void ARIA_test()
|
|
{
|
|
BYTE rk[16 * 17], c[16], * b, mk[32];
|
|
int i, flag;
|
|
const DWORD NUMBER = 0x00000042;
|
|
BYTE p[16] = { 0x11, 0x11, 0x11, 0x11, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0x11, 0x11, 0x11, 0x11, 0xbb, 0xbb, 0xbb, 0xbb };
|
|
const BYTE cryptResult[] = {
|
|
0x8d, 0x14, 0x70, 0x62, 0x5f, 0x59, 0xeb, 0xac,
|
|
0xb0, 0xe5, 0x5b, 0x53, 0x4b, 0x3e, 0x46, 0x2b };
|
|
|
|
printf("BEGIN testing endianness...\n");
|
|
printf("Since you are running this, it means that you have defined \
|
|
either LITTLE_ENDIAN or BIG_ENDIAN. Let's see if you were correct.\n");
|
|
b = (BYTE*)(&NUMBER);
|
|
if (b[0] == 0x42) {
|
|
printf("We are on LITTLE_ENDIAN platform.\n");
|
|
#ifdef BIG_ENDIAN
|
|
printf("WARNING: BIG_ENDIAN defined on LITTLE_ENDIAN platform.\n");
|
|
printf(" You should define LITTLE_ENDIAN instead of BIG_ENDIAN.\n");
|
|
#else
|
|
printf("Okay. You were correct.\n");
|
|
#endif
|
|
}
|
|
else {
|
|
printf("We are on BIG_ENDIAN platform.\n");
|
|
#ifdef LITTLE_ENDIAN
|
|
printf("WARNING: LITTLE_ENDIAN defined on BIG_ENDIAN platform.\n");
|
|
printf(" You should define BIG_ENDIAN instead of LITTLE_ENDIAN.\n");
|
|
#else
|
|
printf("Okay. You were correct.\n");
|
|
#endif
|
|
}
|
|
printf("END testing endianness.\n\n");
|
|
|
|
for (i = 0; i < 16; i++)
|
|
mk[i] = i * 0x11;
|
|
|
|
for (i = 16; i < 24; i++)
|
|
mk[i] = (i - 16) * 0x11;
|
|
|
|
Crypt(p, EncKeySetup(mk, rk, 192), rk, c);
|
|
printf("BEGIN testing basic encryption...\n");
|
|
printf("Testing whether the encryption would come out correctly, for 14-round ARIA.\n");
|
|
printf("key : "); printBlockOfLength(mk, 24); printf("\n");
|
|
printf("plaintext: "); printBlock(p); printf("\n");
|
|
printf("result is: "); printBlock(c); printf("\n");
|
|
printf("should be: "); printBlock((BYTE*)cryptResult); printf("\n");
|
|
flag = 0;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
if (c[i] != cryptResult[i])
|
|
flag = 1;
|
|
|
|
if (flag == 1)
|
|
printf("The result is incorrect!\n");
|
|
else
|
|
printf("Okay. The result is correct.\n");
|
|
printf("END testing basic encryption.\n\n");
|
|
|
|
for (i = 0; i < 32; i++)
|
|
mk[i] = 0;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
p[i] = 0;
|
|
|
|
printf("BEGIN testing the roundtrip...\n");
|
|
printf("For key size of 192 bits, starting with the zero plaintext and the zero key, let's see if \
|
|
we may recover the plaintext by decrypting the encrypted ciphertext.\n");
|
|
EncKeySetup(mk, rk, 192);
|
|
printf("plaintext : "); printBlock(p); printf("\n");
|
|
Crypt(p, 14, rk, c);
|
|
printf("ciphertext: "); printBlock(c); printf("\n");
|
|
DecKeySetup(mk, rk, 192);
|
|
Crypt(c, 14, rk, p);
|
|
printf("decrypted : "); printBlock(p); printf("\n");
|
|
flag = 0;
|
|
for (i = 0; i < 16; i++)
|
|
if (p[i] != 0)
|
|
flag = 1;
|
|
|
|
if (flag == 1)
|
|
printf("The result is incorrect!\n");
|
|
else
|
|
printf("Okay. The result is correct.\n");
|
|
printf("END testing the roundtrip.\n");
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
|
|
int main(int argc, char **argv) {
|
|
ARIA_test();
|
|
return 0;
|
|
}
|
|
|
|
*/
|