Bel-T Block Cipher

Introduction

Bel-T is a 128-bit block cipher that was adopted as a standard by the Republic of Belarus in 2011 and defined in STB 34.101.31-2011. It takes 128-bits of data and encrypts using an N-bit key (where N can be 128, 192 or 256). It uses 8 rounds of a function based on the Lai-Massey scheme also used by IDEA and IDEA-NXT. There’s a key schedule procedure, but because it’s only relevant for 128 and 192-bit keys, it’s not included here. If you’re interested in the key scheduling function, you can find it in this implementation written by Philipp Jovanovic. This implementation only performs encryption and is optimized for size rather than speed.

Compact code

#define R(v,n)(((v)<<(n))|((v)>>(32-(n))))
#define X(u,v)t=u,u=v,v=t
#define F(n)for(i=0;i<n;i++)
typedef unsigned char B;
typedef unsigned int W;

#ifdef LUT
// sbox
B H[256] =
  { 0xB1, 0x94, 0xBA, 0xC8, 0x0A, 0x08, 0xF5, 0x3B,
    0x36, 0x6D, 0x00, 0x8E, 0x58, 0x4A, 0x5D, 0xE4,
    0x85, 0x04, 0xFA, 0x9D, 0x1B, 0xB6, 0xC7, 0xAC,
    0x25, 0x2E, 0x72, 0xC2, 0x02, 0xFD, 0xCE, 0x0D,
    0x5B, 0xE3, 0xD6, 0x12, 0x17, 0xB9, 0x61, 0x81,
    0xFE, 0x67, 0x86, 0xAD, 0x71, 0x6B, 0x89, 0x0B,
    0x5C, 0xB0, 0xC0, 0xFF, 0x33, 0xC3, 0x56, 0xB8,
    0x35, 0xC4, 0x05, 0xAE, 0xD8, 0xE0, 0x7F, 0x99,
    0xE1, 0x2B, 0xDC, 0x1A, 0xE2, 0x82, 0x57, 0xEC,
    0x70, 0x3F, 0xCC, 0xF0, 0x95, 0xEE, 0x8D, 0xF1,
    0xC1, 0xAB, 0x76, 0x38, 0x9F, 0xE6, 0x78, 0xCA,
    0xF7, 0xC6, 0xF8, 0x60, 0xD5, 0xBB, 0x9C, 0x4F,
    0xF3, 0x3C, 0x65, 0x7B, 0x63, 0x7C, 0x30, 0x6A,
    0xDD, 0x4E, 0xA7, 0x79, 0x9E, 0xB2, 0x3D, 0x31,
    0x3E, 0x98, 0xB5, 0x6E, 0x27, 0xD3, 0xBC, 0xCF,
    0x59, 0x1E, 0x18, 0x1F, 0x4C, 0x5A, 0xB7, 0x93,
    0xE9, 0xDE, 0xE7, 0x2C, 0x8F, 0x0C, 0x0F, 0xA6,
    0x2D, 0xDB, 0x49, 0xF4, 0x6F, 0x73, 0x96, 0x47,
    0x06, 0x07, 0x53, 0x16, 0xED, 0x24, 0x7A, 0x37,
    0x39, 0xCB, 0xA3, 0x83, 0x03, 0xA9, 0x8B, 0xF6,
    0x92, 0xBD, 0x9B, 0x1C, 0xE5, 0xD1, 0x41, 0x01,
    0x54, 0x45, 0xFB, 0xC9, 0x5E, 0x4D, 0x0E, 0xF2,
    0x68, 0x20, 0x80, 0xAA, 0x22, 0x7D, 0x64, 0x2F,
    0x26, 0x87, 0xF9, 0x34, 0x90, 0x40, 0x55, 0x11,
    0xBE, 0x32, 0x97, 0x13, 0x43, 0xFC, 0x9A, 0x48,
    0xA0, 0x2A, 0x88, 0x5F, 0x19, 0x4B, 0x09, 0xA1,
    0x7E, 0xCD, 0xA4, 0xD0, 0x15, 0x44, 0xAF, 0x8C,
    0xA5, 0x84, 0x50, 0xBF, 0x66, 0xD2, 0xE8, 0x8A,
    0xA2, 0xD7, 0x46, 0x52, 0x42, 0xA8, 0xDF, 0xB3,
    0x69, 0x74, 0xC5, 0x51, 0xEB, 0x23, 0x29, 0x21,
    0xD4, 0xEF, 0xD9, 0xB4, 0x3A, 0x62, 0x28, 0x75,
    0x91, 0x14, 0x10, 0xEA, 0x77, 0x6C, 0xDA, 0x1D };
#else
B H(B x) {
    W i, j;
    B t = 0x1d, w;
    
    if(x==10) return 0;
    if(x<10) x++;
    
    do {
      j=116;
      do {
        w=t&99,
        w^=w>>1,w^=w>>2,w^=w>>4,
        t=t>>1|w<<7;
      } while(--j);
    } while (--x);
    return t;
}
#endif

// non-linear + linear layer
W G(W x, W *key, int idx, int r) {
    W i, w;
    
    w=key[idx%8]+x;
    F(4)w=(w&-256)| 
#ifdef LUT
      H[w&255],
#else
      H(w&255),
#endif
      w=R(w,8);
    return R(w, r);
}

void belt(void*mk,void*data) {
    W a,b,c,d,i,j,t,e,*x=(W*)data,*k=(W*)mk;
    
    a=x[0],b=x[1],c=x[2],d=x[3];
    
    for(i=0,j=0;i<8;) {
      b^=G(a,k,j++, 5),c^=G(d,k,j++,  21),
      a-=G(b,k,j++,13),e =G(b+c,k,j++,21),
      e^=++i,b+=e,c-=e,d+=G(c,k,j++,  13),
      b^=G(a,k,j++,21),c^=G(d,k,j++,   5),
      X(a,b),X(c,d),X(b,c);
    }
    x[0]=b,x[1]=d,x[2]=a,x[3]=c;
}

x86 assembly

; -----------------------------------------------
; Bel-T block cipher in x86 assembly (encryption only)
;
; size: 210 bytes
;
; global calls use cdecl convention
;
; -----------------------------------------------

    bits 32
    
    %ifndef BIN
      global belt
      global _belt
    %endif
    
struc pushad_t
  _edi dd ?
  _esi dd ?
  _ebp dd ?
  _esp dd ?
  _ebx dd ?
  _edx dd ?
  _ecx dd ?
  _eax dd ?
  .size:
endstruc

%define t   eax

%define a   ebx
%define b   ecx
%define c   edx
%define d   esi
%define e   edi

%define G   ebp

belt:
_belt:
    pushad
    mov    edi, [esp+32+4]   ; k = mk
    mov    esi, [esp+32+8]   ; x = data
    xor    eax, eax
    
    push   esi               ; save x
    push   eax               ; save j
    push   edi               ; save k
    push   eax               ; save i
    
    lodsd
    xchg   a, eax            ; a = x[0]
    lodsd
    xchg   b, eax            ; b = x[1]
    lodsd
    xchg   c, eax            ; c = x[2]
    lodsd
    xchg   d, eax            ; d = x[3]
    call   b_L0
    ; ------------------------
    ; G function
    ; ------------------------
    pushad
    mov    esi, [esp+_esp]   ; esi=esp
    lodsd                    ; eax=return address
    lodsd                    ; edx=x
    xchg   eax, edx          ; 
    lodsd                    ; eax=r
    push   eax               ; save r
    lodsd                    ; eax=i
    lodsd                    ; eax=k
    xchg   eax, edi          ; edi=k
    lodsd                    ; eax=j
    inc    dword[esi-4]      ; j++
    and    eax, 7            ; j &= 7
    add    edx, [edi+eax*4]  ; x += k[j&7]
    mov    al, 4
g_H0:
    ; if (x==10) return 0;
    sub    dl, 10
    jz     g_H3
    ; if (x<10) x++;
    adc    dl, 10
    movzx  ecx, dl
    ; t = 0x1d;
    mov    dl, 0x1d
g_H1:
    push   ecx
    ; j = 116;
    mov    cl, 116
g_H2:
    ; w = t & 99;
    mov    bl, dl
    and    bl, 99
    ; w ^= (w >> 1)
    mov    bh, bl
    shr    bh, 1
    xor    bl, bh
    ; w ^= (w >> 2)
    mov    bh, bl
    shr    bh, 2
    xor    bl, bh
    ; w ^= (w >> 4)
    mov    bh, bl
    shr    bh, 4
    xor    bl, bh
    ; t = t >> 1 | w << 7
    shl    bl, 7
    shr    dl, 1
    or     dl, bl
    loop   g_H2
    pop    ecx
    loop   g_H1
g_H3:
    ror    edx, 8     ; u.w = ROTR(u.w, 8)
    dec    eax
    jnz    g_H0
    
    pop    ecx        ; ecx=r
    rol    edx, cl    ; return ROTL32(u.w, r);
    mov    [esp+_eax], edx
    popad
    retn   2*4
    ; -----------------------
b_L0:    
    pop    G
b_L1:
    push   5
    push   a
    call   G   
    xor    b, t       ; b ^= G(a, k, j+0, 5);
    
    push   21
    push   d
    call   G     
    xor    c, t       ; c ^= G(d, k, j+1,21);
    
    push   13
    push   b
    call   G       
    sub    a, t       ; a -= G(b, k, j+2,13);
    
    push   21
    lea    t, [b + c]
    push   t
    call   G          ; e  = G(b + c, k, j+3,21);
    xchg   t, e
    
    pop    t          ; t = i
    inc    t          ; i++
    push   t          ; save i
    
    xor    e, t       ; e ^= i;
    add    b, e       ; b += e;
    sub    c, e       ; c -= e;
    
    push   13
    push   c
    call   G
    add    d, t       ; d += G(c, k, j+4,13);
    
    push   21
    push   a
    call   G
    xor    b, t       ; b ^= G(a, k, j+5,21);
    
    push   5
    push   d
    call   G
    xor    c, t       ; c ^= G(d, k, j+6, 5);
    
    xchg   a, b
    xchg   c, d
    xchg   b, c
    
    pop    eax
    push   eax
    cmp    al, 8
    jnz    b_L1
    
    pop    eax       ; remove i
    pop    eax       ; remove k
    pop    eax       ; remove j
    pop    edi       ; restore x

    xchg   eax, b
    stosd            ; x[0] = b
    xchg   eax, d
    stosd            ; x[1] = d
    xchg   eax, a
    stosd            ; x[2] = a
    xchg   eax, c
    stosd            ; x[3] = c
    popad            ; restore registers
    ret
    

Summary

Sources here.

Advertisements
This entry was posted in assembly, cryptography, encryption, security and tagged , , , , , . Bookmark the permalink.