Noekeon Block cipher

Introduction

Noekeon (pronounced Nukion) is a 128-bit block cipher with support for 128-bit keys. It was designed by Joan Daemen, Michaël Peeters, Gilles Van Assche, Vincent Rijmen and submitted to the NESSIE project in September 2000. The two ciphers are “direct mode” Noekeon, to be used for maximum efficiency where related-key attacks are not possible, and “indirect mode” Noekeon where they are.

Cryptanalysis by Lars Knudsen and Håvard Raddum in April 2001 showed that “indirect mode” Noekeon was still vulnerable to certain peculiar kinds of related-key cryptanalysis, and showed weaknesses in Noekeon-variant ciphers which cast doubt on the design strategy behind Noekeon and thus on its security. As a result, it was not a NESSIE selected algorithm.

Noekeon (and its inverse) can be implemented in a circuit that is an order of magnitude smaller than that of other known 128-bit block ciphers and has a high speed in software on a wide range of platforms. Noekeon has the unique property that it has been designed with the protection against side-channel attacks (timing, SPA, DPA, …) in mind. Indeed, its high degree of symmetry, low portion of non-linear operations, exclusive usage of cyclic shift and bit-wise Boolean operations and optional key schedule allow efficient secure implementations on Smart Cards applying techniques introduced in our paper Bitslice Ciphers and Power Analysis Attacks.

The authors of Noekeon contend in On Noekeon, no! that the related-key attacks required to break “indirect mode” Noekeon are not a practical concern, and that it is as a result of deliberate design that Noekeon is not vulnerable to the attacks that break the variant ciphers; they assert that Noekeon is still a good and useful cipher.

Noekeon, The Return presented in Jan 2010 argues hardened versions are still suitable for resource constrained environments.

Compact code

This function combines key scheduling and encryption. The mk parameter should point to a 128-bit master key and data should point to a 128-bit block of plaintext to encrypt.

#define R(v,n)(((v)>>(n))|((v)<<(32-(n))))

void noekeon(void*mk,void*p){
    unsigned int a,b,c,d,t,*k=mk,*x=p;
    unsigned char rc=128;

    a=*x;b=x[1];c=x[2];d=x[3];

    for(;;){
      a^=rc;t=a^c;t^=R(t,8)^R(t,24);
      b^=t;d^=t;a^=k[0];b^=k[1];
      c^=k[2];d^=k[3];t=b^d;
      t^=R(t,8)^R(t,24);a^=t;c^=t;
      if(rc==212)break;
      rc=((rc<<1)^((rc>>7)*27));
      b=R(b,31);c=R(c,27);d=R(d,30);
      b^=~((d)|(c));t=d;d=a^c&b;a=t;
      c^=a^b^d;b^=~((d)|(c));a^=c&b;
      b=R(b,1);c=R(c,5);d=R(d,2);
    }
    *x=a;x[1]=b;x[2]=c;x[3]=d;
}

x86 assembly

; -----------------------------------------------
; Noekeon-128/128 Block Cipher in x86 assembly (Encryption only)
;
; size: 152 bytes
;
; global calls use cdecl convention
;
; -----------------------------------------------

    bits 32
 
    %ifndef BIN
      global noekeon
      global _noekeon
    %endif
    
%define w0 ecx
%define w1 edx
%define w2 ebp
%define w3 esi

_noekeon:
noekeon:
    pushad
    mov    edi, [esp+32+4]  ; edi = key
    mov    esi, [esp+32+8]  ; esi = data
    ; save ptr to data
    push   esi
    ; load plaintext
    lodsd
    xchg   w0, eax
    lodsd
    xchg   w1, eax
    lodsd
    xchg   w2, eax
    lodsd
    xchg   w3, eax
    push   127
    pop    eax
    inc    eax    
nk_l0:  
    push   eax
    ; s[0] ^= rc;
    xor    w0, eax
    ; t = s[0] ^ s[2];
    mov    eax, w0
    xor    eax, w2
    ; t ^= ROTR32(t, 8) ^ ROTR32(t, 24);
    mov    ebx, eax
    ror    ebx, 8
    xor    eax, ebx
    ror    ebx, 16
    xor    eax, ebx
    ; s[1] ^= t; s[3] ^= t;
    xor    w1, eax
    xor    w3, eax    
    ; s[0]^= k[0]; s[1]^= k[1];
    xor    w0, [edi+4*0]    
    xor    w1, [edi+4*1] 
    ; s[2]^= k[2]; s[3]^= k[3];    
    xor    w2, [edi+4*2]    
    xor    w3, [edi+4*3]
    ; t = s[1] ^ s[3];
    mov    eax, w1
    xor    eax, w3
    ; t ^= ROTR32(t, 8) ^ ROTR32(t, 24);
    mov    ebx, eax
    ror    ebx, 8
    xor    eax, ebx
    ror    ebx, 16
    xor    eax, ebx
    ; s[0]^= t; s[2] ^= t;
    xor    w0, eax
    xor    w2, eax
    
    ; if (i==Nr) break;
    pop    eax
    cmp    al, 0xd4
    je     nk_l1
    
    add    al, al             ; al <<= 1
    jnc    $+4                ;
    xor    al, 27             ;
    ; Pi1
    ; s[1] = ROTR32(s[1], 31);
    rol    w1, 1
    ; s[2] = ROTR32(s[2], 27);
    ror    w2, 27
    ; s[3] = ROTR32(s[3], 30);
    ror    w3, 30
    
    ; Gamma
    ; s[1]^= ~((s[3]) | (s[2]));
    mov    ebx, w3
    or     ebx, w2
    not    ebx
    xor    w1, ebx

    ; s[0] = s[0] ^ s[2] & s[1];
    mov    ebx, w2
    and    ebx, w1
    xor    w0, ebx

    ; XCHG(s[0], s[3]);
    xchg   w0, w3
    
    ; s[2]^= s[0] ^ s[1] ^ s[3];
    xor    w2, w0
    xor    w2, w1
    xor    w2, w3

    ; s[1]^= ~((s[3]) | (s[2]));
    mov    ebx, w3
    or     ebx, w2
    not    ebx
    xor    w1, ebx
    
    ; s[0]^= s[2] & s[1];
    mov    ebx, w2
    and    ebx, w1
    xor    w0, ebx
    
    ; Pi2
    ; s[1] = ROTR32(s[1], 1);
    ror    w1, 1
    ; s[2] = ROTR32(s[2], 5);
    ror    w2, 5
    ; s[3] = ROTR32(s[3], 2);
    ror    w3, 2
    jmp    nk_l0
nk_l1:    
    ; restore ptr to data
    pop    edi
    ; store ciphertext
    xchg   w0, eax
    stosd
    xchg   w1, eax
    stosd
    xchg   w2, eax
    stosd
    xchg   w3, eax
    stosd    
    popad
    ret

ARM64 /Aarch64

// NOEKEON in ARM64 assembly
// 212 bytes

    .arch armv8-a
    .text

    .global noekeon

noekeon:
    mov    x12, x1

    // load 128-bit key
    ldp    w4, w5, [x0]
    ldp    w6, w7, [x0, 8]

    // load 128-bit plain text
    ldp    w2, w3, [x1, 8]
    ldp    w0, w1, [x1]

    // c = 128
    mov    w8, 128
    mov    w9, 27
L0:
    // a^=rc;t=a^c;t^=R(t,8)^R(t,24);
    eor    w0, w0, w8
    eor    w10, w0, w2
    eor    w11, w10, w10, ror 8
    eor    w10, w11, w10, ror 24

    // b^=t;d^=t;a^=k[0];b^=k[1];
    eor    w1, w1, w10
    eor    w3, w3, w10
    eor    w0, w0, w4
    eor    w1, w1, w5

    // c^=k[2];d^=k[3];t=b^d;
    eor    w2, w2, w6
    eor    w3, w3, w7
    eor    w10, w1, w3

    // t^=R(t,8)^R(t,24);a^=t;c^=t;
    eor    w11, w10, w10, ror 8 
    eor    w10, w11, w10, ror 24 
    eor    w0, w0, w10
    eor    w2, w2, w10

    // if(rc==212)break;
    cmp    w8, 212
    beq    L1

    // rc=((rc<<1)^((rc>>7)*27));
    lsr    w10, w8, 7
    mul    w10, w10, w9
    eor    w8, w10, w8, lsl 1
    uxtb   w8, w8

    // b=R(b,31);c=R(c,27);d=R(d,30);
    ror    w1, w1, 31
    ror    w2, w2, 27
    ror    w3, w3, 30
    
    // b^=~(d|c);t=d;d=a^(c&b);a=t;
    orr    w10, w3, w2
    eon    w1, w1, w10
    mov    w10, w3
    and    w3, w2, w1
    eor    w3, w3, w0
    mov    w0, w10 
    
    // c^=a^b^d;b^=~(d|c);a^=c&b;
    eor    w2, w2, w0
    eor    w2, w2, w1
    eor    w2, w2, w3
    orr    w10, w3, w2
    eon    w1, w1, w10
    and    w10, w2, w1
    eor    w0, w0, w10
 
    // b=R(b,1);c=R(c,5);d=R(d,2);
    ror    w1, w1, 1
    ror    w2, w2, 5
    ror    w3, w3, 2
    b      L0
L1:
    // *x=a;x[1]=b;x[2]=c;x[3]=d;
    stp    w0, w1, [x12]
    stp    w2, w3, [x12, 8]
    ret

Sources here.

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

1 Response to Noekeon Block cipher

  1. Pingback: Shellcode: Encryption Algorithms in ARM Assembly | modexp

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s