Source code of vigenere.class.php
<?php
/**
* @class Vigenere
*
* Crypt messages via Vigenère
*
* @author Frank Bo"es <info@3960.org>
* @copyright CC-BY <http://creativecommons.org/licenses/by/3.0/>
*/
class Vigenere
{
protected $key = array();
protected $replacement = array(
'.' => 'X',
'!' => 'X',
'?' => 'Q',
'@' => 'AT',
'1' => 'ONE',
'2' => 'TWO',
'3' => 'THREE',
'4' => 'FOUR',
'5' => 'FIVE',
'6' => 'SIX',
'7' => 'SEVEN',
'8' => 'EIGHT',
'9' => 'NINE',
'0' => 'ZERO',
'Ä' => 'AE',
'Ö' => 'OE',
'Ü' => 'UE',
);
const ALPHABET_LENGTH = 26;
/**
* Set key for coding.
*
* @param string $key May only consist of latin letters
*/
public function __construct ($key)
{
$key = mb_strtoupper($key, mb_detect_encoding($key));
$key = str_replace(
array_keys($this->replacement),
$this->replacement,
$key
);
$key = preg_replace('#[^A-Za-z]#','',$key);
$this->key = str_split(strtoupper($key));
}
/**
* Show current key. This key may have been altered, but is only
* needed for internal encoding.
*
* @return string
*/
public function showKey ()
{
return implode($this->key);
}
/**
* Encrypt message via $this->key.
*
* @param string $message plain message
* @return string crypted message
*/
public function encryptMessage ($message)
{
$message = mb_strtoupper($message, mb_detect_encoding($message));
$message = preg_replace('#[!\?\.]$#','',$message);
$message = str_replace(
array_keys($this->replacement),
$this->replacement,
$message
);
$message = preg_replace('#[^A-Za-z]#','',$message);
$encryptedMessage = $this->workRotor($message);
$encryptedMessage = implode(" ",str_split($encryptedMessage, 4));
return $encryptedMessage;
}
/**
* Decrypt message via $this->key.
*
* @param string $message encrypted message
* @return string decrypted message
*/
public function decryptMessage ($encryptedMessage)
{
$encryptedMessage = preg_replace('#[^A-Za-z]#','',$encryptedMessage);
$message = $this->workRotor($encryptedMessage, TRUE);
$message = mb_strtolower($message, mb_detect_encoding($message));
return ucwords($message);
}
/**
* Move all characters of $in through rotor with $this->keys.
*
* @param string $in
* @param bool $reverese Use rotor the other way round.
* Optional, defaults to FALSE.
* @return string out
*/
public function workRotor ($in, $reverse = FALSE)
{
$posAsciiA = ord('A');
$rotor = 0;
$in = str_split($in);
$out = NULL;
foreach ($in as $char)
{
$rotorValue = ord($this->key[$rotor]) - $posAsciiA;
$charValue = ord($char) - $posAsciiA;
if ($reverse)
{
$charValue -= $rotorValue;
}
else
{
$charValue += $rotorValue;
}
while ($charValue >= self::ALPHABET_LENGTH)
{
$charValue -= self::ALPHABET_LENGTH;
}
while ($charValue < 0)
{
$charValue += self::ALPHABET_LENGTH;
}
$out .= chr($charValue + $posAsciiA);
$rotor = $this->moveRotor($rotor);
}
return $out;
}
/**
* Turn rotor. If rotor is smaller than 0 or bigger than $max, hop
* to new position of rotor;
*
* @param int $oldPosition of rotor
* @param int $by how to increment rotor. you may use negative values.
* Optional, defaults to 1
* @param int $max Max lentgh of rotor. Optional, defaults to
* length of $this->keys
* @return int new position of rotor
*/
protected function moveRotor ($oldPosition, $by = 1, $max = NULL)
{
if (empty($max))
{
$max = count($this->key);
}
$newPosition = $oldPosition + $by;
while ($newPosition >= $max)
{
$newPosition -= $max;
}
while ($newPosition < 0)
{
$newPosition += $max;
}
return $newPosition;
}
}
?>
Vigenere = {
replacement : {
'.' : 'X',
'!' : 'X',
'?' : 'Q',
'@' : 'AT',
'1' : 'ONE',
'2' : 'TWO',
'3' : 'THREE',
'4' : 'FOUR',
'5' : 'FIVE',
'6' : 'SIX',
'7' : 'SEVEN',
'8' : 'EIGHT',
'9' : 'NINE',
'0' : 'ZERO',
'Ä' : 'AE',
'Ö' : 'OE',
'Ü' : 'UE',
},
alphabetLength : 26,
key : '',
init: function (key) {
key = key.toUpperCase();
for (var r in this.replacement) {
key = key.replace(new RegExp(r.replace(/(\?|\.)/, '\\$1'),'g'), this.replacement[r]);
}
key = key.replace(/[^A-Za-z]/g,'');
if (key.length > 0) {
this.key = key;
}
return this.key;
},
encryptMessage: function (message) {
message = message.toUpperCase();
message = message.replace(/[!\?\.]$/g,'');
for (var r in this.replacement) {
message = message.replace(new RegExp(r.replace(/(\?|\.)/, '\\$1'),'g'), this.replacement[r]);
}
message = message.replace(/[^A-Za-z]/g,'');
var encryptedMessage = this.workRotor(message);
encryptedMessage = encryptedMessage.replace(/([^\s]{4})/g, '$1 ');
return encryptedMessage;
},
decryptMessage: function (encryptedMessage) {
encryptedMessage = encryptedMessage.toUpperCase();
encryptedMessage = encryptedMessage.replace(/[^A-Za-z]/g,'');
message = this.workRotor(encryptedMessage, true);
message = message.toLowerCase();
return message;
},
workRotor: function (input, reverse) {
if (this.key.length < 1) {
return '';
}
if (!reverse) {
reverse = false;
}
var posAsciiA = 'A'.charCodeAt(0);
rotor = 0;
out = '';
for (var i=0; i < input.length; i++) {
rotorValue = this.key.charCodeAt(rotor) - posAsciiA;
charValue = input.charCodeAt(i) - posAsciiA;
if (reverse) {
charValue -= rotorValue;
}
else {
charValue += rotorValue;
}
while (charValue >= this.alphabetLength) {
charValue -= this.alphabetLength;
}
while (charValue < 0) {
charValue += this.alphabetLength;
}
out = out + String.fromCharCode(charValue + posAsciiA);
rotor = this.moveRotor(rotor);
}
return out;
},
moveRotor: function (oldPosition, by, max) {
if (!by) {
by = 1;
}
if (!max) {
max = this.key.length;
}
newPosition = oldPosition + by;
while (newPosition >= max) {
newPosition -= max;
}
while (newPosition < 0) {
newPosition += max;
}
return newPosition;
},
end : 0
}