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

org.netxms.base.IceCrypto Maven / Gradle / Ivy

The newest version!
/**
 * This class implements the ICE encryption algorithm.
 *
 * Written by Matthew Kwan - December 1996
 */
package org.netxms.base;


/**
 * ICE encryption algorithm implementation
 */
public class IceCrypto
{
   private int size;
   private int rounds;
   private int keySchedule[][];

   private static int spBox[][];
   private static boolean spBoxInitialised = false;

   private static final int sMod[][] = { { 333, 313, 505, 369 }, { 379, 375, 319, 391 }, { 361, 445, 451, 397 },
         { 397, 425, 395, 505 } };

   private static final int sXor[][] = { { 0x83, 0x85, 0x9b, 0xcd }, { 0xcc, 0xa7, 0xad, 0x41 }, { 0x4b, 0x2e, 0xd4, 0x33 },
         { 0xea, 0xcb, 0x2e, 0x04 } };

   private static final int pBox[] = { 0x00000001, 0x00000080, 0x00000400, 0x00002000, 0x00080000, 0x00200000, 0x01000000,
         0x40000000, 0x00000008, 0x00000020, 0x00000100, 0x00004000, 0x00010000, 0x00800000, 0x04000000, 0x20000000, 0x00000004,
         0x00000010, 0x00000200, 0x00008000, 0x00020000, 0x00400000, 0x08000000, 0x10000000, 0x00000002, 0x00000040, 0x00000800,
         0x00001000, 0x00040000, 0x00100000, 0x02000000, 0x80000000 };

   private static final int keyrot[] = { 0, 1, 2, 3, 2, 1, 3, 0, 1, 3, 2, 0, 3, 1, 0, 2 };

   /**
    * 8-bit Galois Field multiplication of a by b, modulo m.
    * Just like arithmetic multiplication, except that
    * additions and subtractions are replaced by XOR.
    *  
    * @param a
    * @param b
    * @param m
    * @return
    */
   private int gf_mult(int a, int b, int m)
   {
      int res = 0;

      while(b != 0)
      {
         if ((b & 1) != 0)
            res ^= a;

         a <<= 1;
         b >>>= 1;

         if (a >= 256)
            a ^= m;
      }

      return (res);
   }

   /**
    * 8-bit Galois Field exponentiation.
    * Raise the base to the power of 7, modulo m.
    * 
    * @param b
    * @param m
    * @return
    */
   private int gf_exp7(int b, int m)
   {
      int x;

      if (b == 0)
         return (0);

      x = gf_mult(b, b, m);
      x = gf_mult(b, x, m);
      x = gf_mult(x, x, m);
      return (gf_mult(b, x, m));
   }

   /**
    * Carry out the ICE 32-bit permutation.
    * @param x
    * @return
    */
   private int perm32(int x)
   {
      int res = 0;
      int i = 0;

      while(x != 0)
      {
         if ((x & 1) != 0)
            res |= pBox[i];
         i++;
         x >>>= 1;
      }

      return (res);
   }

   /**
    *  Initialise the substitution/permutation boxes.
    */
   private void spBoxInit()
   {
      int i;

      spBox = new int[4][1024];

      for(i = 0; i < 1024; i++)
      {
         int col = (i >>> 1) & 0xff;
         int row = (i & 0x1) | ((i & 0x200) >>> 8);
         int x;

         x = gf_exp7(col ^ sXor[0][row], sMod[0][row]) << 24;
         spBox[0][i] = perm32(x);

         x = gf_exp7(col ^ sXor[1][row], sMod[1][row]) << 16;
         spBox[1][i] = perm32(x);

         x = gf_exp7(col ^ sXor[2][row], sMod[2][row]) << 8;
         spBox[2][i] = perm32(x);

         x = gf_exp7(col ^ sXor[3][row], sMod[3][row]);
         spBox[3][i] = perm32(x);
      }
   }

   /**
    * Create a new ICE key with the specified level.
    * 
    * @param level key level
    */
   public IceCrypto(int level)
   {
      if (!spBoxInitialised)
      {
         spBoxInit();
         spBoxInitialised = true;
      }

      if (level < 1)
      {
         size = 1;
         rounds = 8;
      }
      else
      {
         size = level;
         rounds = level * 16;
      }

      keySchedule = new int[rounds][3];
   }

   /**
    * Set 8 rounds [n, n+7] of the key schedule of an ICE key.
    * @param kb
    * @param n
    * @param krot_idx
    */
   private void scheduleBuild(int kb[], int n, int krot_idx)
   {
      int i;

      for(i = 0; i < 8; i++)
      {
         int j;
         int kr = keyrot[krot_idx + i];
         int subkey[] = keySchedule[n + i];

         for(j = 0; j < 3; j++)
            keySchedule[n + i][j] = 0;

         for(j = 0; j < 15; j++)
         {
            int k;
            int curr_sk = j % 3;

            for(k = 0; k < 4; k++)
            {
               int curr_kb = kb[(kr + k) & 3];
               int bit = curr_kb & 1;

               subkey[curr_sk] = (subkey[curr_sk] << 1) | bit;
               kb[(kr + k) & 3] = (curr_kb >>> 1) | ((bit ^ 1) << 15);
            }
         }
      }
   }

   /**
    * Set the key schedule of an ICE key.
    * 
    * @param key new key
    */
   public void set(byte key[])
   {
      int i;
      int kb[] = new int[4];

      if (rounds == 8)
      {
         for(i = 0; i < 4; i++)
            kb[3 - i] = ((key[i * 2] & 0xff) << 8) | (key[i * 2 + 1] & 0xff);

         scheduleBuild(kb, 0, 0);
         return;
      }

      for(i = 0; i < size; i++)
      {
         int j;

         for(j = 0; j < 4; j++)
            kb[3 - j] = ((key[i * 8 + j * 2] & 0xff) << 8) | (key[i * 8 + j * 2 + 1] & 0xff);

         scheduleBuild(kb, i * 8, 0);
         scheduleBuild(kb, rounds - 8 - i * 8, 8);
      }
   }

   /**
    * Clear the key schedule to prevent memory snooping.
    */
   public void clear()
   {
      int i, j;

      for(i = 0; i < rounds; i++)
         for(j = 0; j < 3; j++)
            keySchedule[i][j] = 0;
   }

   /**
    * The single round ICE f function.
    * @param p
    * @param subkey
    * @return
    */
   private int roundFunc(int p, int subkey[])
   {
      int tl, tr;
      int al, ar;

      tl = ((p >>> 16) & 0x3ff) | (((p >>> 14) | (p << 18)) & 0xffc00);
      tr = (p & 0x3ff) | ((p << 2) & 0xffc00);

      // al = (tr & subkey[2]) | (tl & ~subkey[2]);
      // ar = (tl & subkey[2]) | (tr & ~subkey[2]);
      al = subkey[2] & (tl ^ tr);
      ar = al ^ tr;
      al ^= tl;

      al ^= subkey[0];
      ar ^= subkey[1];

      return (spBox[0][al >>> 10] | spBox[1][al & 0x3ff] | spBox[2][ar >>> 10] | spBox[3][ar & 0x3ff]);
   }

   /**
    * Encrypt a block of 8 bytes of data.
    *
    * @param plaintext unencrypted data
    * @param ciphertext buffer for encrypted data
    */
   public void encryptBlock(byte plaintext[], byte ciphertext[])
   {
      int i;
      int l = 0, r = 0;

      for(i = 0; i < 4; i++)
      {
         l |= (plaintext[i] & 0xff) << (24 - i * 8);
         r |= (plaintext[i + 4] & 0xff) << (24 - i * 8);
      }

      for(i = 0; i < rounds; i += 2)
      {
         l ^= roundFunc(r, keySchedule[i]);
         r ^= roundFunc(l, keySchedule[i + 1]);
      }

      for(i = 0; i < 4; i++)
      {
         ciphertext[3 - i] = (byte)(r & 0xff);
         ciphertext[7 - i] = (byte)(l & 0xff);

         r >>>= 8;
         l >>>= 8;
      }
   }

   /**
    * Decrypt a block of 8 bytes of data.
    *
    * @param ciphertext encrypted data
    * @param plaintext buffer for decrypted data
    */
   public void decryptBlock(byte ciphertext[], byte plaintext[])
   {
      int i;
      int l = 0, r = 0;

      for(i = 0; i < 4; i++)
      {
         l |= (ciphertext[i] & 0xff) << (24 - i * 8);
         r |= (ciphertext[i + 4] & 0xff) << (24 - i * 8);
      }

      for(i = rounds - 1; i > 0; i -= 2)
      {
         l ^= roundFunc(r, keySchedule[i]);
         r ^= roundFunc(l, keySchedule[i - 1]);
      }

      for(i = 0; i < 4; i++)
      {
         plaintext[3 - i] = (byte)(r & 0xff);
         plaintext[7 - i] = (byte)(l & 0xff);

         r >>>= 8;
         l >>>= 8;
      }
   }

   /**
    * Return the key size, in bytes.
    *
    * @return key size in bytes
    */
   public int keySize()
   {
      return (size * 8);
   }

   /**
    * Return the block size, in bytes.
    *
    * @return block size in bytes
    */
   public int blockSize()
   {
      return (8);
   }
   
   /**
    * Copy bytes from source array to destination
    * 
    * @param src source array
    * @param srcStart start index in source array
    * @param length length of data block
    * @param dst destination array
    * @param dstStart start index in destination array
    */
   private static void copyBytes(byte[] src, int srcStart, int length, byte[] dst, int dstStart)
   {
      for(int i = 0, sp = srcStart, dp = dstStart; i < length; i++)
         dst[dp++] = src[sp++];
   }
   
   /**
    * Encrypt data using given key.
    * 
    * @param in clear text data
    * @param key encryption key
    * @return encrypted data
    */
   public static byte[] encrypt(byte[] in, byte[] key)
   {
      if (in.length == 0)
         return new byte[0];
      
      IceCrypto ice = new IceCrypto(1);
      ice.set(key);

      byte[] out = new byte[(in.length % 8 == 0) ? in.length : in.length + (8 - in.length % 8)];
      
      byte[] plainText = new byte[8];
      byte[] encrypted = new byte[8];
      int stopPos = in.length - (in.length % 8);
      for(int pos = 0; pos < stopPos; pos += 8)
      {
         copyBytes(in, pos, 8, plainText, 0);
         ice.encryptBlock(plainText, encrypted);
         copyBytes(encrypted, 0, 8, out, pos);
      }

      if (stopPos < in.length)
      {
         copyBytes(in, stopPos, in.length - stopPos, plainText, 0);
         ice.encryptBlock(plainText, encrypted);
         copyBytes(encrypted, 0, 8, out, stopPos);
      }
      
      return out;
   }
   
   /**
    * Encrypt data using given key.
    * 
    * @param in encrypted data
    * @param key encryption key
    * @return clear text data
    */
   public static byte[] decrypt(byte[] in, byte[] key)
   {
      byte[] out = new byte[in.length];
      if (in.length == 0)
         return out;
      
      IceCrypto ice = new IceCrypto(1);
      ice.set(key);

      byte[] plainText = new byte[8];
      byte[] encrypted = new byte[8];
      int stopPos = in.length - (in.length % 8);
      for(int pos = 0; pos < stopPos; pos += 8)
      {
         copyBytes(in, pos, 8, encrypted, 0);
         ice.decryptBlock(encrypted, plainText);
         copyBytes(plainText, 0, 8, out, pos);
      }

      if (stopPos < in.length)
      {
         copyBytes(in, stopPos, in.length - stopPos, encrypted, 0);
         ice.decryptBlock(encrypted, plainText);
         copyBytes(plainText, 0, in.length - stopPos, out, stopPos);
      }
      
      return out;
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy