All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kr.re.nsri.aria.ARIA Maven / Gradle / Ivy

The newest version!
//
//  ARIA.java
//  
//  A pure Java implementation of ARIA 
//  following the official ARIA specification at
//  http://www.nsri.re.kr/ARIA/
//
//  
//  Created by Aaram Yun on 2005. 11. 30.
//  Copyright 2005 NSRI. All rights reserved.
//

package kr.re.nsri.aria;

import java.util.*;
import java.io.PrintStream;
import java.security.InvalidKeyException;

class ARIAEngine {
  private static final char[] HEX_DIGITS = {
    '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
  };
  
  private static final int[][] KRK = {
  {0x517cc1b7, 0x27220a94, 0xfe13abe8, 0xfa9a6ee0},
  {0x6db14acc, 0x9e21c820, 0xff28b1d5, 0xef5de2b0},
  {0xdb92371d, 0x2126e970, 0x03249775, 0x04e8c90e}
  };
  
  private static final byte[] S1 = new byte[256];
  private static final byte[] S2 = new byte[256];
  private static final byte[] X1 = new byte[256];
  private static final byte[] X2 = new byte[256];
  
  private static final int[] TS1 = new int[256];
  private static final int[] TS2 = new int[256];
  private static final int[] TX1 = new int[256];
  private static final int[] TX2 = new int[256];
  
  // Static initializer.  For setting up the tables
  static {
    int[] exp = new int[256];
    int[] log =  new int[256];
    exp[0] = 1;
    for (int i=1; i < 256; i++) {
      int j = (exp[i-1] << 1) ^ exp[i-1];
      if ((j & 0x100) != 0) j ^= 0x11b;
      exp[i] = j;
    }
    for (int i=1; i < 255; i++)
        log[exp[i]] = i;
    
    int[][] A = {
    {1, 0, 0, 0, 1, 1, 1, 1},
        {1, 1, 0, 0, 0, 1, 1, 1},
        {1, 1, 1, 0, 0, 0, 1, 1},
        {1, 1, 1, 1, 0, 0, 0, 1},
        {1, 1, 1, 1, 1, 0, 0, 0},
        {0, 1, 1, 1, 1, 1, 0, 0},
        {0, 0, 1, 1, 1, 1, 1, 0},
        {0, 0, 0, 1, 1, 1, 1, 1}
    };
    int[][] B = {
    {0, 1, 0, 1, 1, 1, 1, 0},
        {0, 0, 1, 1, 1, 1, 0, 1},
        {1, 1, 0, 1, 0, 1, 1, 1},
        {1, 0, 0, 1, 1, 1, 0, 1},
        {0, 0, 1, 0, 1, 1, 0, 0},
        {1, 0, 0, 0, 0, 0, 0, 1},
        {0, 1, 0, 1, 1, 1, 0, 1},
        {1, 1, 0, 1, 0, 0, 1, 1}
    };
    
    for (int i=0; i<256; i++) {
        int t=0, p;
        if (i==0)
          p=0;
        else
          p=exp[255-log[i]];
        for (int j=0; j<8; j++) {
          int s=0;
          for (int k=0; k<8; k++) {
            if (((p>>>(7-k))&0x01)!=0)
              s^=A[k][j];
          }
          t=(t<<1)^s;
        }
        t^=0x63;
        S1[i]=(byte)t;
        X1[t]=(byte)i;
    }
    for (int i = 0; i < 256; i++) {
      int t = 0, p;
      if (i==0)
        p=0;
      else
        p=exp[(247*log[i])%255];
      for (int j = 0; j < 8; j++) {
        int s = 0;
        for (int k = 0; k < 8; k++) {
          if (((p >>> k) & 0x01) != 0)
            s ^= B[7-j][k];
        }
        t = (t << 1) ^ s;
      }
      t^=0xe2;
      S2[i] = (byte) t;
      X2[t] = (byte) i;
    }
    
    for (int i = 0; i < 256; i++) {
      TS1[i]=0x00010101*(S1[i]&0xff);
      TS2[i]=0x01000101*(S2[i]&0xff);
      TX1[i]=0x01010001*(X1[i]&0xff);
      TX2[i]=0x01010100*(X2[i]&0xff);
    }
  }
  
  private int keySize=0;
  private int numberOfRounds=0;
  private byte[] masterKey=null;
  private int[] encRoundKeys=null, decRoundKeys=null;
  
  public ARIAEngine(int keySize) throws InvalidKeyException {
      setKeySize(keySize);
  }
  
  /**
    * Resets the class so that it can be reused for another master key.
   */
  void reset() {
      this.keySize=0;
      this.numberOfRounds=0;
      this.masterKey=null;
      this.encRoundKeys=null;
      this.decRoundKeys=null;
  }
  
  int getKeySize() {
      return this.keySize;
  }
  
  void setKeySize(int keySize) throws InvalidKeyException {
      this.reset();
      if (keySize!=128 && keySize!=192 && keySize!=256)
        throw new InvalidKeyException("keySize="+keySize);
      this.keySize = keySize;
      switch (keySize) {
        case 128:
          this.numberOfRounds = 12;
          break;
        case 192:
          this.numberOfRounds = 14;
          break;
        case 256:
          this.numberOfRounds = 16;
      }
  }
  
  void setKey(byte[] masterKey) throws InvalidKeyException {
      if (masterKey.length*8>>24)&0xff]^TS2[(t0>>>16)&0xff]^TX1[(t0>>>8)&0xff]^TX2[t0&0xff];
        t1=TS1[(t1>>>24)&0xff]^TS2[(t1>>>16)&0xff]^TX1[(t1>>>8)&0xff]^TX2[t1&0xff];
        t2=TS1[(t2>>>24)&0xff]^TS2[(t2>>>16)&0xff]^TX1[(t2>>>8)&0xff]^TX2[t2&0xff];
        t3=TS1[(t3>>>24)&0xff]^TS2[(t3>>>16)&0xff]^TX1[(t3>>>8)&0xff]^TX2[t3&0xff];         
        t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
        t1=badc(t1); t2=cdab(t2); t3=dcba(t3);
        t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
        
        t0^=rk[j++]; t1^=rk[j++]; t2^=rk[j++]; t3^=rk[j++];
        t0=TX1[(t0>>>24)&0xff]^TX2[(t0>>>16)&0xff]^TS1[(t0>>>8)&0xff]^TS2[t0&0xff];
        t1=TX1[(t1>>>24)&0xff]^TX2[(t1>>>16)&0xff]^TS1[(t1>>>8)&0xff]^TS2[t1&0xff];
        t2=TX1[(t2>>>24)&0xff]^TX2[(t2>>>16)&0xff]^TS1[(t2>>>8)&0xff]^TS2[t2&0xff];
        t3=TX1[(t3>>>24)&0xff]^TX2[(t3>>>16)&0xff]^TS1[(t3>>>8)&0xff]^TS2[t3&0xff];  
        t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
        t3=badc(t3); t0=cdab(t0); t1=dcba(t1);        
        t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
    }
    t0^=rk[j++]; t1^=rk[j++]; t2^=rk[j++]; t3^=rk[j++];
    t0=TS1[(t0>>>24)&0xff]^TS2[(t0>>>16)&0xff]^TX1[(t0>>>8)&0xff]^TX2[t0&0xff];
    t1=TS1[(t1>>>24)&0xff]^TS2[(t1>>>16)&0xff]^TX1[(t1>>>8)&0xff]^TX2[t1&0xff];
    t2=TS1[(t2>>>24)&0xff]^TS2[(t2>>>16)&0xff]^TX1[(t2>>>8)&0xff]^TX2[t2&0xff];
    t3=TS1[(t3>>>24)&0xff]^TS2[(t3>>>16)&0xff]^TX1[(t3>>>8)&0xff]^TX2[t3&0xff];
    t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
    t1=badc(t1); t2=cdab(t2); t3=dcba(t3);
    t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
    
    t0^=rk[j++]; t1^=rk[j++]; t2^=rk[j++]; t3^=rk[j++]; 
    o[ 0+ooffset] = (byte)(X1[0xff&(t0>>>24)] ^ (rk[j  ]>>>24));
    o[ 1+ooffset] = (byte)(X2[0xff&(t0>>>16)] ^ (rk[j  ]>>>16));
    o[ 2+ooffset] = (byte)(S1[0xff&(t0>>> 8)] ^ (rk[j  ]>>> 8));
    o[ 3+ooffset] = (byte)(S2[0xff&(t0     )] ^ (rk[j  ]     ));
    o[ 4+ooffset] = (byte)(X1[0xff&(t1>>>24)] ^ (rk[j+1]>>>24));
    o[ 5+ooffset] = (byte)(X2[0xff&(t1>>>16)] ^ (rk[j+1]>>>16));
    o[ 6+ooffset] = (byte)(S1[0xff&(t1>>> 8)] ^ (rk[j+1]>>> 8));
    o[ 7+ooffset] = (byte)(S2[0xff&(t1     )] ^ (rk[j+1]     ));
    o[ 8+ooffset] = (byte)(X1[0xff&(t2>>>24)] ^ (rk[j+2]>>>24));
    o[ 9+ooffset] = (byte)(X2[0xff&(t2>>>16)] ^ (rk[j+2]>>>16));
    o[10+ooffset] = (byte)(S1[0xff&(t2>>> 8)] ^ (rk[j+2]>>> 8));
    o[11+ooffset] = (byte)(S2[0xff&(t2     )] ^ (rk[j+2]     ));
    o[12+ooffset] = (byte)(X1[0xff&(t3>>>24)] ^ (rk[j+3]>>>24));
    o[13+ooffset] = (byte)(X2[0xff&(t3>>>16)] ^ (rk[j+3]>>>16));
    o[14+ooffset] = (byte)(S1[0xff&(t3>>> 8)] ^ (rk[j+3]>>> 8));
    o[15+ooffset] = (byte)(S2[0xff&(t3     )] ^ (rk[j+3]     ));
  }
  
  void encrypt(byte[] i, int ioffset, byte[] o, int ooffset) throws InvalidKeyException {
      if (this.keySize==0)
        throw new InvalidKeyException("keySize");
      if (this.encRoundKeys==null)
        if (this.masterKey==null)
          throw new InvalidKeyException("masterKey");
        else
          setupEncRoundKeys();
      doCrypt(i, ioffset, this.encRoundKeys, this.numberOfRounds, o, ooffset);
  }
  
  byte[] encrypt(byte[] i, int ioffset) throws InvalidKeyException {
      byte[] o = new byte[16];
      this.encrypt(i, ioffset, o, 0);
      return o;
  }
  
  void decrypt(byte[] i, int ioffset, byte[] o, int ooffset) throws InvalidKeyException {
      if (this.keySize==0)
        throw new InvalidKeyException("keySize");
      if (this.decRoundKeys==null)
        if (this.masterKey==null)
          throw new InvalidKeyException("masterKey");
        else
          setupDecRoundKeys();
      doCrypt(i, ioffset, this.decRoundKeys, this.numberOfRounds, o, ooffset);
  }
  
  byte[] decrypt(byte[] i, int ioffset) throws InvalidKeyException {
      byte[] o = new byte[16];
      this.decrypt(i, ioffset, o, 0);
      return o;
  }
  
  private static void doEncKeySetup(byte[] mk, int[] rk, int keyBits) {      
    int t0, t1, t2, t3, q, j=0;
    int[] w0 = new int[4];
    int[] w1 = new int[4];
    int[] w2 = new int[4];
    int[] w3 = new int[4];
    
    w0[0] = toInt(mk[ 0], mk[ 1], mk[ 2], mk[ 3]);
    w0[1] = toInt(mk[ 4], mk[ 5], mk[ 6], mk[ 7]);
    w0[2] = toInt(mk[ 8], mk[ 9], mk[10], mk[11]);
    w0[3] = toInt(mk[12], mk[13], mk[14], mk[15]);
    
    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];  
    t0=TS1[(t0>>>24)&0xff]^TS2[(t0>>>16)&0xff]^TX1[(t0>>>8)&0xff]^TX2[t0&0xff];
    t1=TS1[(t1>>>24)&0xff]^TS2[(t1>>>16)&0xff]^TX1[(t1>>>8)&0xff]^TX2[t1&0xff];
    t2=TS1[(t2>>>24)&0xff]^TS2[(t2>>>16)&0xff]^TX1[(t2>>>8)&0xff]^TX2[t2&0xff];
    t3=TS1[(t3>>>24)&0xff]^TS2[(t3>>>16)&0xff]^TX1[(t3>>>8)&0xff]^TX2[t3&0xff];   
    t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
    t1=badc(t1); t2=cdab(t2); t3=dcba(t3);
    t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
    
    if (keyBits > 128) {
      w1[0] = toInt(mk[16], mk[17], mk[18], mk[19]);
      w1[1] = toInt(mk[20], mk[21], mk[22], mk[23]);
      if (keyBits > 192) {
        w1[2] = toInt(mk[24], mk[25], mk[26], mk[27]);
        w1[3] = toInt(mk[28], mk[29], mk[30], mk[31]);
      } 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];
    t0=TX1[(t0>>>24)&0xff]^TX2[(t0>>>16)&0xff]^TS1[(t0>>>8)&0xff]^TS2[t0&0xff];
    t1=TX1[(t1>>>24)&0xff]^TX2[(t1>>>16)&0xff]^TS1[(t1>>>8)&0xff]^TS2[t1&0xff];
    t2=TX1[(t2>>>24)&0xff]^TX2[(t2>>>16)&0xff]^TS1[(t2>>>8)&0xff]^TS2[t2&0xff];
    t3=TX1[(t3>>>24)&0xff]^TX2[(t3>>>16)&0xff]^TS1[(t3>>>8)&0xff]^TS2[t3&0xff]; 
    t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
    t3=badc(t3); t0=cdab(t0); t1=dcba(t1);        
    t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
    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];
    t0=TS1[(t0>>>24)&0xff]^TS2[(t0>>>16)&0xff]^TX1[(t0>>>8)&0xff]^TX2[t0&0xff];
    t1=TS1[(t1>>>24)&0xff]^TS2[(t1>>>16)&0xff]^TX1[(t1>>>8)&0xff]^TX2[t1&0xff];
    t2=TS1[(t2>>>24)&0xff]^TS2[(t2>>>16)&0xff]^TX1[(t2>>>8)&0xff]^TX2[t2&0xff];
    t3=TS1[(t3>>>24)&0xff]^TS2[(t3>>>16)&0xff]^TX1[(t3>>>8)&0xff]^TX2[t3&0xff];   
    t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
    t1=badc(t1); t2=cdab(t2); t3=dcba(t3);
    t1^=t2; t2^=t3; t0^=t1; t3^=t1; t2^=t0; t1^=t2;
    w3[0]=t0^w1[0]; w3[1]=t1^w1[1]; w3[2]=t2^w1[2]; w3[3]=t3^w1[3];
    
    gsrk(w0, w1, 19, rk, j); j+=4;
    gsrk(w1, w2, 19, rk, j); j+=4;
    gsrk(w2, w3, 19, rk, j); j+=4;
    gsrk(w3, w0, 19, rk, j); j+=4;
    gsrk(w0, w1, 31, rk, j); j+=4;
    gsrk(w1, w2, 31, rk, j); j+=4;
    gsrk(w2, w3, 31, rk, j); j+=4;
    gsrk(w3, w0, 31, rk, j); j+=4;
    gsrk(w0, w1, 67, rk, j); j+=4;
    gsrk(w1, w2, 67, rk, j); j+=4;
    gsrk(w2, w3, 67, rk, j); j+=4;
    gsrk(w3, w0, 67, rk, j); j+=4;
    gsrk(w0, w1, 97, rk, j); j+=4;
    if (keyBits > 128) {  
      gsrk(w1, w2, 97, rk, j); j+=4;
      gsrk(w2, w3, 97, rk, j); j+=4;
    }
    if (keyBits > 192) {
      gsrk(w3, w0,  97, rk, j); j+=4;
      gsrk(w0, w1, 109, rk, j);
    }
  }
  
  /**
    * Main bulk of the decryption key setup method.  Here we assume that
   * the int array rk already contains the encryption round keys.
   * @param mk the master key
   * @param rk the array which contains the encryption round keys at the
   * beginning of the method execution.  At the end of method execution
   * this will hold the decryption round keys.
   * @param keyBits the length of the master key
   * @return
   */
  private static void doDecKeySetup(byte[] mk, int[] rk, int keyBits) {
    int a=0, z;
    int[] t = new int[4];
    
    z=32+keyBits/8;
    swapBlocks(rk, 0, z);
    a+=4; z-=4;
    
    for (; a>>24);
    b[offset+1] = (byte)(i>>>16);
    b[offset+2] = (byte)(i>>> 8);
    b[offset+3] = (byte)(i     );
  }
  
  private static int m(int t) {
      return 0x00010101*((t>>>24)&0xff) ^ 0x01000101*((t>>>16)&0xff) ^ 
    0x01010001*((t>>>8)&0xff) ^ 0x01010100*(t&0xff);
  }
  
  //  private static final int ms(int t) {
  //    return TS1[(t>>>24)&0xff]^TS2[(t>>>16)&0xff]^TX1[(t>>>8)&0xff]^TX2[t&0xff];
  //  }
  //  private static final int mx(int t) {
  //    return TX1[(t>>>24)&0xff]^TX2[(t>>>16)&0xff]^TS1[(t>>>8)&0xff]^TS2[t&0xff];
  //  }
  private static final int badc(int t) {
    return ((t<<8)&0xff00ff00) ^ ((t>>>8)&0x00ff00ff);
  }
  
  private static final int cdab(int t) {
    return ((t<<16)&0xffff0000) ^ ((t>>>16)&0x0000ffff);
  }
  
  private static final int dcba(int t) {
    return (t&0x000000ff)<<24 ^ (t&0x0000ff00)<<8 ^ (t&0x00ff0000)>>>8 ^ (t&0xff000000)>>>24;
  }
  
  private static final void gsrk(int[] x, int[] y, int rot, int[] rk, int offset) {
    int q=4-(rot/32), r=rot%32, s=32-r;
    
    rk[offset]   = x[0] ^ y[(q  )%4]>>>r ^ y[(q+3)%4]<>>r ^ y[(q  )%4]<>>r ^ y[(q+1)%4]<>>r ^ y[(q+2)%4]<>> 4) & 0x0F],
      HEX_DIGITS[ b        & 0x0F]
    };
    out.print(new String(buf));    
  }
  
  private static void intToHex(PrintStream out, int i) {
    byte[] b = new byte[4];
    toByteArray(i, b, 0);
    byteToHex(out, b[0]);
    byteToHex(out, b[1]);
    byteToHex(out, b[2]);
    byteToHex(out, b[3]);
  }
  
  private static void printRoundKeys(PrintStream out, int[] roundKeys) {
    for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy