function Crypt()
{
  /** Private Eigenschaften. */
  var aCharacterTable = new Array('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',
        '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '_', '-', '.', '!', '?', '@');
  var aReplaceTable = new Array('z', 'v', 'm', 'a', 'p', 'q', '_', 'w', '?', 'u',
        'o', '-', '8', '0', '1', 'c', 'x', '!', '4', 'b', 'f', 'n', 'y', '9', 'd', '2',
        'e', 'g', '6', 'h', 'j', 'k', 'i', 'l', 'r', 't', 's', '@', '3', '5', '.', '7');  
  var sCryptKey = 'ABC';
  var iIndexCryptKey = 0;
  var bWorkWithKey = false;
  
  /**
   * Zuordnung Originalzeichen (aCharacterTable) zum Index des Ersetzungszeichen (aReplaceTable).
   *
   * Das 'assoziative' Array wird hier in Form eines Objekts aufgebaut, das für die 
   * Zuordnung 'Originalzeichen' => 'Index des Ersetzungsarray' sorgt.
   */
  var oReplaceCharIndex = new Object();
  var i;
  for ( i = 0; i < aCharacterTable.length; i++ )
  {
    oReplaceCharIndex[aReplaceTable[i]] = i;
  }
  
  /** Öffentliche Methoden. */
  this.setCryptKey = function(sParamCryptKey)
  {
    var bSetNewKey = true;
    var i;
    for ( i = 0; i < sParamCryptKey.length; i++ )
    {
      if ( !sParamCryptKey.charAt(i).match(/[A-Z]/) )
      {
        bSetNewKey = false;
        alert("Der Schlüssel darf nur Großbuchstaben [A-Z] enthalten.\nDer Default-Schlüssel " + sCryptKey + ' bleibt bestehen');
        break;
      }
    }
    if ( bSetNewKey )
    {
      sCryptKey = sParamCryptKey;
    }
    bWorkWithKey = true;
  }
  
  this.decrypt = function(sString)
  {
    var sDecryptedString = '';
    if ( sString )
    {
      iIndexCryptKey = 0; // Instanzvariable wieder auf setzen, falls mehrere E-Mail Links existieren.
      sString = sString.toLowerCase();
      var iKeyInReplaceTable;
      var i;
      for ( i = 0; i < sString.length; i++ )
      {
        iKeyInReplaceTable = oReplaceCharIndex[sString.charAt(i)];
        if ( bWorkWithKey )
        {
          iKeyInReplaceTable -= getShift();
        }
        // ArrayIndexOutOfRange abfangen.
        if ( iKeyInReplaceTable < 0 )
        {
          iKeyInReplaceTable = aCharacterTable.length + iKeyInReplaceTable;
        }
        sDecryptedString += aCharacterTable[iKeyInReplaceTable];
      }
    }
    return sDecryptedString;
  }
  
  this.setWorkWithKey = function(bValue)
  {
    bWorkWithKey = bValue;
  }
  
  /** Private Methoden. */
  function getShift()
  {
    // ASCII-Wert von A = 65.
    var iShiftValue = getAsciiValue(sCryptKey.charAt(iIndexCryptKey)) - 64;
    iIndexCryptKey++;
    if ( iIndexCryptKey == sCryptKey.length )
    {
      iIndexCryptKey = 0;
    }
    return iShiftValue;
  }
  
  function getAsciiValue(sChar)
  {
    // Nur ein Zeichen soll übergeben werden.
    sChar = sChar.charAt (0);

  	// Durch alle möglichen ASCII-Zeichen iterieren.
    var i;
  	for ( i = 0; i < 256; ++ i )
  	{
      // i in einen 2-Zeichen Hexadezimal-String konvertieren.
      var sHexa = i.toString (16);
      if (sHexa.length == 1)
      {
        sHexa = "0" + sHexa;
      }
      // Ein % Zeichen an den Anfang.
      sHexa = "%" + sHexa;

      // Zeichen bestimmen, das durch den erzeugten Code repräsentiert wird.
      sHexa = unescape (sHexa);

      // Wenn das Zeichen mit dem Übergebenen überein stimmt, ist der ASCII-Wert gefunden.
      if (sHexa == sChar)
      {
        break;
      }
    }
    return i;
  }
}
