ASCII a Base64 (encoder - javascript)

Iniciado por @XSStringManolo, 8 Agosto 2019, 03:58 AM

0 Miembros y 1 Visitante están viendo este tema.

@XSStringManolo

Decoder https://foro.elhacker.net/desarrollo_web/base64_a_ascii_decoder-t498429.0.html
Cambiarle las etiquetas <js> y </js> por las correspondientes para añadir el javascript al html. Lo puse así para que el Cloudfare no me detecte los scripts y no me rediriga en bucle a captchas al publicar el código en el foro.

Podeis probarlo offline con un copia y pega, substituyendo las etiquetas y guardándolo con extensión html o htm con el bloc de notas o cualquier otro editor de texto dándole a "guardar como". Por ejemplo: cifradobase64.html

Podeis añadirlo a vuestra web o usarlo como querais y para lo que querais.

Características.
-La implementación es super sencilla de entender. Así quien no sepa como funciona exactamente el cifrado base64, buscándolo en wikipedia (o en el propio foro de criptografía se lo expliqué a un usuario) y mirando el código pueda entenderlo. A parte es fácilmente portable a cualquier otro lenguaje.
-Filtra todos los espacios y carácteres no contemplados en la tabla común del cifrado base64 del texto original. Se le añaden fácilmente si se desea.
-Facil cambiar la base de 64 a otra base.
-Solo cifra, no descifra. Le añadí el igual al texto cifrado (en caso de necesitarlo) para poder descifrarlo con cualquier herramienta online o implementar vosotros el decoder. Puede que lo haga yo y lo suba también cuando me aburra.


Código (javascript) [Seleccionar]
<html>
<head><title>Encoder Base64</title></head>
<body>
<js>
var CadenaEnTexto;
var CadenaEnTextoTamanho;
var CadenaEnASCII = "";
var CadenaDeBits6en6 = "";
var CadenaDeBits6en6Tamanho;
var RestoDeDividirEntre6 = 0;
var ContadorNumDeCerosAnhadidos = 0;
var mantenerseEnBucle = true;
var TempBits6 = "";
var x = 0;
var z = 0;
var CifradoFinal = "";


CadenaEnTexto = prompt("Pon el texto");

CadenaEnTextoTamanho = CadenaEnTexto.length;

for (var i = 0; i < CadenaEnTextoTamanho; ++i)
{
  if (CadenaEnTexto[i] == 'A')
  {
  CadenaEnASCII += "01000001";
  }

if (CadenaEnTexto[i] == 'B')
  {
  CadenaEnASCII += "01000010";
  }

if (CadenaEnTexto[i] == 'C')
  {
  CadenaEnASCII += "01000011";
  }

if (CadenaEnTexto[i] == 'D')
  {
  CadenaEnASCII += "01000100";
  }

if (CadenaEnTexto[i] == 'E')
  {
  CadenaEnASCII += "01000101";
  }

if (CadenaEnTexto[i] == 'F')
  {
  CadenaEnASCII += "01000110";
  }

if (CadenaEnTexto[i] == 'G')
  {
  CadenaEnASCII += "01000111";
  }

if (CadenaEnTexto[i] == 'H')
  {
  CadenaEnASCII += "01001000";
  }

if (CadenaEnTexto[i] == 'I')
  {
  CadenaEnASCII += "01001001";
  }

if (CadenaEnTexto[i] == 'J')
  {
  CadenaEnASCII += "01001010";
  }

if (CadenaEnTexto[i] == 'K')
  {
  CadenaEnASCII += "01001011";
  }

if (CadenaEnTexto[i] == 'L')
  {
  CadenaEnASCII += "01001100";
  }

if (CadenaEnTexto[i] == 'M')
  {
  CadenaEnASCII += "01001101";
  }

if (CadenaEnTexto[i] == 'N')
  {
  CadenaEnASCII += "01001110";
  }

if (CadenaEnTexto[i] == 'O')
  {
  CadenaEnASCII += "01001111";
  }

if (CadenaEnTexto[i] == 'P')
  {
  CadenaEnASCII += "01010000";
  }

if (CadenaEnTexto[i] == 'Q')
  {
  CadenaEnASCII += "01010001";
  }

if (CadenaEnTexto[i] == 'R')
  {
  CadenaEnASCII += "01010010";
  }

if (CadenaEnTexto[i] == 'S')
  {
  CadenaEnASCII += "01010011";
  }

if (CadenaEnTexto[i] == 'T')
  {
  CadenaEnASCII += "01010100";
  }

if (CadenaEnTexto[i] == 'U')
  {
  CadenaEnASCII += "01010101";
  }

if (CadenaEnTexto[i] == 'V')
  {
  CadenaEnASCII += "01010110";
  }

if (CadenaEnTexto[i] == 'W')
  {
  CadenaEnASCII += "01010111";
  }

if (CadenaEnTexto[i] == 'X')
  {
  CadenaEnASCII += "01011000";
  }

if (CadenaEnTexto[i] == 'Y')
  {
  CadenaEnASCII += "01011001";
  }

if (CadenaEnTexto[i] == 'Z')
  {
  CadenaEnASCII += "01011010";
  }

if (CadenaEnTexto[i] == 'a')
  {
  CadenaEnASCII += "01100001" ;
  }

if (CadenaEnTexto[i] == 'b')
  {
  CadenaEnASCII += "01100010";
  }

if (CadenaEnTexto[i] == 'c')
  {
  CadenaEnASCII += "01100011";
  }

if (CadenaEnTexto[i] == 'd')
  {
  CadenaEnASCII += "01100100";
  }

if (CadenaEnTexto[i] == 'e')
  {
  CadenaEnASCII += "01100101";
  }

if (CadenaEnTexto[i] == 'f')
  {
  CadenaEnASCII += "01100110";
  }

if (CadenaEnTexto[i] == 'g')
  {
  CadenaEnASCII += "01100111";
  }

if (CadenaEnTexto[i] == 'h')
  {
  CadenaEnASCII += "01101000";
  }

if (CadenaEnTexto[i] == 'i')
  {
  CadenaEnASCII += "01101001";
  }


if (CadenaEnTexto[i] == 'j')
  {
  CadenaEnASCII += "01101010";
  }

if (CadenaEnTexto[i] == 'k')
  {
  CadenaEnASCII += "01101011";
  }

if (CadenaEnTexto[i] == 'l')
  {
  CadenaEnASCII += "01101100";
  }

if (CadenaEnTexto[i] == 'm')
  {
  CadenaEnASCII += "01101101";
  }

if (CadenaEnTexto[i] == 'n')
  {
  CadenaEnASCII += "01101110";
  }

if (CadenaEnTexto[i] == 'o')
  {
  CadenaEnASCII += "01101111";
  }

if (CadenaEnTexto[i] == 'p')
  {
  CadenaEnASCII += "01110000";
  }

if (CadenaEnTexto[i] == 'q')
  {
  CadenaEnASCII += "01110001";
  }


if (CadenaEnTexto[i] == 'r')
  {
  CadenaEnASCII += "01110010";
  }

if (CadenaEnTexto[i] == 's')
  {
  CadenaEnASCII += "01110011";
  }

if (CadenaEnTexto[i] == 't')
  {
  CadenaEnASCII += "01110100";
  }

if (CadenaEnTexto[i] == 'u')
  {
  CadenaEnASCII += "01110101";
  }

if (CadenaEnTexto[i] == 'v')
  {
  CadenaEnASCII += "01110110";
  }

if (CadenaEnTexto[i] == 'w')
  {
  CadenaEnASCII += "01110111";
  }

if (CadenaEnTexto[i] == 'x')
  {
  CadenaEnASCII += "01111000";
  }

if (CadenaEnTexto[i] == 'y')
  {
  CadenaEnASCII += "01111001";
  }

if (CadenaEnTexto[i] == 'z')
  {
  CadenaEnASCII += "01111010";
  }

if (CadenaEnTexto[i] == '0')
  {
  CadenaEnASCII += "00110000";
  }

if (CadenaEnTexto[i] == '1')
  {
  CadenaEnASCII += "00110001";
  }

if (CadenaEnTexto[i] == '2')
  {
  CadenaEnASCII += "00110010";
  }


if (CadenaEnTexto[i] == '3')
  {
  CadenaEnASCII += "00110011";
  }

if (CadenaEnTexto[i] == '4')
  {
  CadenaEnASCII += "00110100";
  }

if (CadenaEnTexto[i] == '5')
  {
  CadenaEnASCII += "00110101";
  }

if (CadenaEnTexto[i] == '6')
  {
  CadenaEnASCII += "00110110";
  }

if (CadenaEnTexto[i] == '7')
  {
  CadenaEnASCII += "00110111";
  }

if (CadenaEnTexto[i] == '8')
  {
  CadenaEnASCII += "00111000";
  }

if (CadenaEnTexto[i] == '9')
  {
  CadenaEnASCII += "00111001";
  }

if (CadenaEnTexto[i] == '+')
  {
  CadenaEnASCII += "00101011";
  }

if (CadenaEnTexto[i] == '/')
  {
  CadenaEnASCII += "00101111";
  }

}

CadenaDeBits6en6 += CadenaEnASCII;
CadenaDeBits6en6Tamanho = CadenaDeBits6en6.length;

RestoDeDividirEntre6 = CadenaDeBits6en6Tamanho % 6;

switch (RestoDeDividirEntre6)
{
  case 2:
  {
  CadenaDeBits6en6 += "0000";
  ContadorNumDeCerosAnhadidos = 4;
  CadenaDeBits6en6Tamanho += 4;
  } break;

  case 4:
  {
  CadenaDeBits6en6 += "00";
  ContadorNumDeCerosAnhadidos = 2;
  CadenaDeBits6en6Tamanho += 2;
  } break;

  default:
  {
 
  } break;
}


do
{

TempBits6 += CadenaDeBits6en6[z];

x++;
z++;


  if (x == 6 )
  {
 
   
if ( TempBits6 == "000000")
      {
      CifradoFinal += "A";
      }
         
if ( TempBits6 == "000001")
      {
      CifradoFinal += "B";
      }

if ( TempBits6 == "000010")
      {
      CifradoFinal += "C";
      }
         
if ( TempBits6 == "000011")
      {
      CifradoFinal += "D";
      }

if ( TempBits6 == "000100")
      {
      CifradoFinal += "E";
      }
         
if ( TempBits6 == "000101")
      {
      CifradoFinal += "F";
      }

if ( TempBits6 == "000110")
      {
      CifradoFinal += "G";
      }
         
if ( TempBits6 == "000111")
      {
      CifradoFinal += "H";
      }

if ( TempBits6 == "001000")
      {
      CifradoFinal += "I";
      }
         
if ( TempBits6 == "001001")
      {
      CifradoFinal += "J";
      }

if ( TempBits6 == "001010")
      {
      CifradoFinal += "K";
      }
         
if ( TempBits6 == "001011")
      {
      CifradoFinal += "L";
      }

if ( TempBits6 == "001100")
      {
      CifradoFinal += "M";
      }
         
if ( TempBits6 == "001101")
      {
      CifradoFinal += "N";
      }

if ( TempBits6 == "001110")
      {
      CifradoFinal += "O";
      }
         
if ( TempBits6 == "001111")
      {
      CifradoFinal += "P";
      }

if ( TempBits6 == "010000")
      {
      CifradoFinal += "Q";
      }
         
if ( TempBits6 == "010001")
      {
      CifradoFinal += "R";
      }

if ( TempBits6 == "010010")
      {
      CifradoFinal += "S";
      }
         
if ( TempBits6 == "010011")
      {
      CifradoFinal += "T";
      }

if ( TempBits6 == "010100")
      {
      CifradoFinal += "U";
      }
         
if ( TempBits6 == "010101")
      {
      CifradoFinal += "V";
      }

if ( TempBits6 == "010110")
      {
      CifradoFinal += "W";
      }
         
if ( TempBits6 == "010111")
      {
      CifradoFinal += "X";
      }

if ( TempBits6 == "011000")
      {
      CifradoFinal += "Y";
      }
         
if ( TempBits6 == "011001")
      {
      CifradoFinal += "Z";
      }

if ( TempBits6 == "011010")
      {
      CifradoFinal += "a";
      }
         
if ( TempBits6 == "011011")
      {
      CifradoFinal += "b";
      }

if ( TempBits6 == "011100")
      {
      CifradoFinal += "c";
      }
         
if ( TempBits6 == "011101")
      {
      CifradoFinal += "d";
      }

if ( TempBits6 == "011110")
      {
      CifradoFinal += "e";
      }
         
if ( TempBits6 == "011111")
      {
      CifradoFinal += "f";
      }

if ( TempBits6 == "100000")
      {
      CifradoFinal += "g";
      }
         
if ( TempBits6 == "100001")
      {
      CifradoFinal += "h";
      }

if ( TempBits6 == "100010")
      {
      CifradoFinal += "i";
      }
         
if ( TempBits6 == "100011")
      {
      CifradoFinal += "j";
      }

if ( TempBits6 == "100100")
      {
      CifradoFinal += "k";
      }
         
if ( TempBits6 == "100101")
      {
      CifradoFinal += "l";
      }

if ( TempBits6 == "100110")
      {
      CifradoFinal += "m";
      }
         
if ( TempBits6 == "100111")
      {
      CifradoFinal += "n";
      }

if ( TempBits6 == "101000")
      {
      CifradoFinal += "o";
      }
         
if ( TempBits6 == "101001")
      {
      CifradoFinal += "p";
      }

if ( TempBits6 == "101010")
      {
      CifradoFinal += "q";
      }
         
if ( TempBits6 == "101011")
      {
      CifradoFinal += "r";
      }

if ( TempBits6 == "101100")
      {
      CifradoFinal += "s";
      }
         
if ( TempBits6 == "101101")
      {
      CifradoFinal += "t";
      }

if ( TempBits6 == "101110")
      {
      CifradoFinal += "u";
      }
         
if ( TempBits6 == "101111")
      {
      CifradoFinal += "v";
      }

if ( TempBits6 == "110000")
      {
      CifradoFinal += "w";
      }
         
if ( TempBits6 == "110001")
      {
      CifradoFinal += "x";
      }

if ( TempBits6 == "110010")
      {
      CifradoFinal += "y";
      }
         
if ( TempBits6 == "110011")
      {
      CifradoFinal += "z";
      }

if ( TempBits6 == "110100")
      {
      CifradoFinal += "0";
      }
         
if ( TempBits6 == "110101")
      {
      CifradoFinal += "1";
      }

if ( TempBits6 == "110110")
      {
      CifradoFinal += "2";
      }
         
if ( TempBits6 == "110111")
      {
      CifradoFinal += "3";
      }

if ( TempBits6 == "111000")
      {
      CifradoFinal += "4";
      }
         
if ( TempBits6 == "111001")
      {
      CifradoFinal += "5";
      }

if ( TempBits6 == "111010")
      {
      CifradoFinal += "6";
      }
         
if ( TempBits6 == "111011")
      {
      CifradoFinal += "7";
      }

if ( TempBits6 == "111100")
      {
      CifradoFinal += "8";
      }
         
if ( TempBits6 == "111101")
      {
      CifradoFinal += "9";
      }

if ( TempBits6 == "111110")
      {
      CifradoFinal += "+";
      }
         
if ( TempBits6 == "111111")
      {
      CifradoFinal += "/";
      }


  x = 0;
  TempBits6 = "";
  }

  if ( z == CadenaDeBits6en6Tamanho )
  {
  mantenerseEnBucle = false;
  }

} while ( mantenerseEnBucle == true )


switch (ContadorNumDeCerosAnhadidos)
{
  case 2:
  {
  CifradoFinal += "=";
  } break;

  case 4:
  {
   CifradoFinal += "==";
  } break;
}

document.write(CifradoFinal);
alert (CifradoFinal);
</js>
</body>
</html>


Comentarios del código:
Los 2 switchs es parte necesaria del cifrado base64. Básicamente lo que hago es usar el operador módulo (%) para obtener el resto de dividir el tamaño del texto que se quiere cifrar entre 6 (los bits, ceros y unos, se agrupan de 6 en 6 en el cifrado base64) Como puede ser que al agrupar de 6 en 6 te queden bits sueltos, es necesario añadirle el símbolo = por cada 2bits. Con un ejemplo se ve mejor:
Si tengo los bits 1 0 0 0 1 0 1 1 y los quiero agrupar de 6 en 6. Tendré dos grupos. 100010 y 11. Lógicamente me faltan bits en el segundo grupo para tener 6 bits en ambos grupos. Entonces le añado ceros hasta tener 6 bits: 11 -> 110000
Y los simbolos igual entonces para que?
Para identificar si al número se le añadieron ceros o el número ya era así, ya que si no usamos los iguales, no podrías diferenciar cuando el texto a cifrar fue 1 0 0 0 1 0 1 1 de cuando el texo a cifrar fue 1 0 0 0 1 0 1 1 0 0 0 0.
Al no poder diferenciar tendríamos un serio problema al descifrar el cifrado y por eso se añade un igual por cada grupo de 2 bits añadidos.

Y por qué por cada 2 bits 1 igual y no por cada bit un igual? Porque solo existen 2 posibilidades. Que falten 2 bits para llegar a tener los 6 bits, o que falten 4 bits para llegar a tener los 6 bits. No tendría sentido usar 2 iguales y 4 iguales cuando podemos representar lo mismo con 1 igual y 2 iguales.

Si te parece complejo en realidad es una tontería, leete la entrada sobre el cifrado en wikipedia y lo acabarás entendiendo. Yo aprendí a implementar el cifrado usando como único recurso la wikipedia y un cifrador online psra ver si lo estaba haciendo bien.
Cuando pone case 2 en el switch del resto significa que sobraron 2 bits, por eso hay que añadirle 4 bits más para llegar a los 6.

El código dentro del bucle do while lo único que hace es añadir bits a una variable y en cuanto tiene 6 bits guarda en otra variable ese número binario pasado a caracter usando la tabla comun de base64. 000000 = A, 000001 = B, etc.
Tras obtener la cadena, vuelve a tomar los 6 siguientes bits repitiendo este proceso hasta que no queden bits que tomar.

Pueden usarse arrays para la comparación y breaks en los if para mejorar el rendimiento y reducir drásticamente las líneas del código. Pero así es más visual y fácil de entender para newbies. Lo mismo con reducir el uso de variables, etc.

Si no entendeis algo comentarlo.

engel lex

Base64 no es un cifrado, es una codificación (un cifrado es un método de seguridad, una codificación es un cambio de medio para un mensaje)

Fuera de todo, tengo una curiosidad, por que no usar

Código (javascript) [Seleccionar]
codigo = btoa(mensaje);
// O
mensaje = atob(codigo);


Intentas saltar algún filtro de funciones?
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

animanegra

Entiendo que es por realizar el ejercicio de implementarlo y por dejarlo como guía o manual de como hacer la codificación.
Enhorabuena por el código, este tipo de cosas las deberíamos de hacer todos, aunque después igual utilicemos librerías. Pero para entender bien como funcionan los algoritmos creo que es la manera más efectiva. Y eso es algo que a la gente se le suele olvidar o suele pasar de ello.

42
No contesto mensajes por privado, si tienes alguna pregunta, consulta o petición plantéala en el foro para que se aproveche toda la comunidad.

@XSStringManolo

Cita de: engel lex en  8 Agosto 2019, 07:29 AM
Base64 no es un cifrado, es una codificación (un cifrado es un método de seguridad, una codificación es un cambio de medio para un mensaje)

Fuera de todo, tengo una curiosidad, por que no usar

Código (javascript) [Seleccionar]
codigo = btoa(mensaje);
// O
mensaje = atob(codigo);


Intentas saltar algún filtro de funciones?
Básicamente es para lo que comenta animanegra. Me gusta implementar cifrados para entenderlos a la perfección. Así al conocer como funcionan varios cifrados puedo hacer mi propio cifrado con las técnicas que voy aprendiendo al implementarlos.
A parte al tener el cifrado implementado puedes hacer cambios en la implementación para por ejemplo cambiar la base, la tabla para usar tu propio diccionario de 64 carácteres o 128 con unicode o 32 con no case sensitive...
A parte así la gente puede revisarlo y entenderlo simplemente por curiosidad de como funciona. Las librerías e implementaciones que veo por ahí hacen un montón de operaciones y son un caos aunque sean más eficientes o no.

Igual voy subiendo más implementaciones un poco más complejo tipo serpent o un algoritmo propio que tengo para compresión de texto.

MinusFour

Es más simple si utilizas operadores bitwise:

Código (javascript) [Seleccionar]

let b64 = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T','U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '='];

function asciiToBase64(str){
       if(!str.length) return "";
       let [f8, s8, t8] = str.substring(0,3).split('').map(c => c.charCodeAt(0));
       let firstB = (f8 & 0b11111100) >>> 2;
       let secondB = ((f8 & 0b00000011) << 4) | ((s8 & 0b11110000) >>> 4);
       let thirdB = s8 ? (((s8 & 0b00001111) << 2) | ((t8 & 0b11000000) >>> 6)) : 64;
       let fourthB = t8 ? (t8 & 0b00111111) : 64;
       return b64[firstB] + b64[secondB] + b64[thirdB] + b64[fourthB] + asciiToBase64(str.slice(3));
}


@XSStringManolo

Cita de: MinusFour en  9 Agosto 2019, 03:16 AM
Es más simple si utilizas operadores bitwise:

Código (javascript) [Seleccionar]

let b64 = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T','U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '='];

function asciiToBase64(str){
       if(!str.length) return "";
       let [f8, s8, t8] = str.substring(0,3).split('').map(c => c.charCodeAt(0));
       let firstB = (f8 & 0b11111100) >>> 2;
       let secondB = ((f8 & 0b00000011) << 4) | ((s8 & 0b11110000) >>> 4);
       let thirdB = s8 ? (((s8 & 0b00001111) << 2) | ((t8 & 0b11000000) >>> 6)) : 64;
       let fourthB = t8 ? (t8 & 0b00111111) : 64;
       return b64[firstB] + b64[secondB] + b64[thirdB] + b64[fourthB] + asciiToBase64(str.slice(3));
}


--------------------------------------------------------------------

Sí, mucho más sencillo, corto y eficiente. Lo hice a lo bruto para poder modificarlo fácilmente y tener control en cualquier parte del proceso. Si te fijas por el nombre de la variable iba a poner primero el valor en ASCII traduciendo la A a 65, por si se quería realizar alguna operación con los valores en ASCII y los valores que no estuviesen en el rango de caracteres de base64 hacer saltos hacia los siguientes pero no quería usar un array y me iba a dar pereza y por eso puse el binario directo xD.

Por si alguien va usar los operadores de bits para implementar la codificación, según el standart de javascript se necesita tirar una excepción en caso de que los valores no estén dentro del rango 0-255 (que son los que contempla el ASCII) en el momento de hacer el encode:
Código (javascript) [Seleccionar]
if (/([^\u0000-\u00ff])/.cadenaCodificar(cadenaCodificar)){ throw new Error("No se pueden codificar caracteres no ASCII.");

Para el decoder:
Código (javascript) [Seleccionar]
CadenaDecodificar = CadenaDecodificar.replace(/\s/g,""); if(!(/^[a-z0-9\+\/\s]+\={0,2}$/i.test(text)) || text.length % 4 > 0){ throw new Error("El texto no es una cadena base64.");

Hace 10 mins me puse a hacer el decoder de la misma forma que el encoder, ya funciona todo, pero de momento solo decodifica el binario de la letra A. Me falta ponerle los 62 if restantes asique igual lo acabo mañana que no me apetece xD

El decoder lo debería poner en este mismo hilo? O creo otro independiente y pongo links del uno al otro? Funcionan ambos por separado aunque le cambié el nombre a las variables para que no coincidiesen por si se quieren usar en las mismas etiquetas los 2 juntos.
Cuando tenga datos los meto en un blogspot y los linkeo también por si alguien los quiere probar antes de usarlos.