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:
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».
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.
/// <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);
}
}