Algoritmo LSA

De Wikipedia, la enciclopedia libre

En criptografía, LSA (acrónimo de Light Summary Algorithm , Algoritmo Ligero de Resumen) es un algoritmo de reducción criptográfico de 64 bits.

Codificación[editar]

La codificación del LSA de 64 bits es representada típicamente como un número de 16 dígitos hexadecimal. El siguiente código de 28 bytes ASCII será tratado con LSA y veremos su correspondiente hash de salida:

   LSA("Esto si es una prueba de LSA") = cfa26da3a8c76ca3

Un simple cambio en el mensaje nos da un cambio total en la codificación hash, en este caso cambiamos dos letras, el «si» por un «no».

   LSA("Esto no es una prueba de LSA") = d607d93d2556c3b5

Otro ejemplo sería la codificación de un campo vacío:

   LSA("") = bb52e9b27ef418a3

Algoritmo[editar]

El algoritmo LSA se basa en el reordenamiento de una tabla de valores, en base al mensaje a codificar. A partir de este punto, se hacen uso de funciones lógicas para determinar el valor de salida.

Implementación en C#:

    /// <summary>
    /// LSA(Light Summary Algorithm) Algoritmo de reducción criptográfico de 64 bits.
    /// Copyright(C) Ronald Anderson 2007-2008
    /// </summary>
    public class LSA
    {
        private static byte[] keyStream = new byte[512];
  
        public static byte[] ComputeHash(byte[] buffer)
        {
            for (int i = 0; i < 512; i++)
            {
                keyStream[i] = (byte)i;
            }
  
            if (buffer.Length == 0) buffer = new byte[1]; buffer[0] = 0;
  
            while ((buffer.Length % 512) != 0)
            {
                Array.Resize<byte>(ref buffer, buffer.Length + 1);
                buffer[buffer.Length - 1] = 0;
            }
  
            int index1 = 0;
            int index2 = 0;
            byte swap = 0;
  
            for (int i = 0; i < (buffer.Length / 512); i++ )
            {
                for (int n = 0; n < keyStream.Length; n++)
                {
                    index2 = (buffer[index1] + keyStream[n] + index2) % 512;
                    swap = keyStream[n];
                    keyStream[n] = keyStream[index2];
                    keyStream[index2] = swap;
                    index1 = (index1 + 1) % buffer.Length;
                }
            }
  
            return Cipher(keyStream);
        }
  
        private static byte[] Cipher(byte[] keyStream)
        {
            byte[] result = new byte[8];
            string[] keyParts = new string[128];
  
            for (int m = 0; m < keyParts.Length; m++)
            {
                int index = m * 4;
                keyParts[m] = string.Concat(string.Format("{0:x2}", keyStream[index]),
                                            string.Format("{0:x2}", keyStream[index + 1]),
                                            string.Format("{0:x2}", keyStream[index + 2]),
                                            string.Format("{0:x2}", keyStream[index + 3]));
            }
  
            ulong xa = 0xFC, ya = 0xEF, za = 0xBA, na = 0xDC;
            ulong xb = 0xCD, yb = 0xAE, zb = 0xFE, nb = 0xAD;
            for (int j = 0; j < keyParts.Length; j++)
            {
                ulong lX = ulong.Parse(string.Concat(keyParts[j][0], keyParts[j][1]), NumberStyles.HexNumber);
                ulong lY = ulong.Parse(string.Concat(keyParts[j][2], keyParts[j][3]), NumberStyles.HexNumber);
                ulong lZ = ulong.Parse(string.Concat(keyParts[j][4], keyParts[j][5]), NumberStyles.HexNumber);
                ulong lN = ulong.Parse(string.Concat(keyParts[j][6], keyParts[j][7]), NumberStyles.HexNumber);
  
                xa = AA(lX, ya, za, na);
                ya = AA(xa, lY, za, na);
                za = AA(xa, ya, lZ, na);
                na = AA(xa, ya, za, lN);
  
                xb = BB(lX, yb, zb, nb);
                yb = BB(xb, lY, zb, nb);
                zb = BB(xb, yb, lZ, nb);
                nb = BB(xb, yb, zb, lN);
  
                xa = CC(lX, yb, zb, nb);
                ya = CC(xb, lY, zb, nb);
                za = CC(xb, yb, lZ, nb);
                na = CC(xb, yb, zb, lN);
  
                xb = AA(lX, ya, za, na);
                yb = AA(xa, lY, za, na);
                zb = AA(xa, ya, lZ, na);
                nb = AA(xa, ya, za, lN);
  
                xa = BB(lX, ya, za, na);
                ya = BB(xb, lY, zb, nb);
                za = BB(xa, ya, lZ, na);
                na = BB(xb, yb, zb, lN);
  
                xb = CC(lX, yb, zb, nb);
                yb = CC(xa, lY, za, na);
                zb = CC(xb, yb, lZ, nb);
                nb = CC(xa, ya, za, lN);
            }
  
            result[0] = (byte)xa;
            result[1] = (byte)ya;
            result[2] = (byte)za;
            result[3] = (byte)na;
            result[4] = (byte)xb;
            result[5] = (byte)yb;
            result[6] = (byte)zb;
            result[7] = (byte)nb;
  
            return result;
        }
  
        private static ulong AA(ulong x, ulong y, ulong z, ulong n)
        {
            return (x & y) | ((~n) & z);
        }
  
        private static ulong BB(ulong x, ulong y, ulong z, ulong n)
        {
            return (x ^ y) | (n & (~z));
        }
  
        private static ulong CC(ulong x, ulong y, ulong z, ulong n)
        {
            return (x ^ y ^ z ^ n);
        }
    }