Caesar cipher reloaded

This semester I’m studying “eBusiness Security” at the university and I needed to create encryption technique similar to Caesar cipher. I needed to use the Bulgarian alphabet which is cyrillic and it has 30 letters. Here’s how it looks like:

alphabet

Probably you’ve noticed that the letters are more than 30. That’s because I actually used the Caesar algorithm but in my case the current letter is using the position of the letter next to it instead of its own position. After that I’m taking the position with right shift of 3.

Here’s example how the algorithm works:

table

The last letter is using the position of the first letter because it has no neighbor. This rule applies reversed for the first letter when we are decrypting a word.

Drawing this implementation with a pencil in hand was not so hard as I thought but when I stepped into writing the algorithm in PHP it turned out to be pain in the ass. PHP is not supporting most of the features that I need to use with cyrillic stings (e.g. check if cyrillic letter is upper case or lower case) so I just hard coded the alphabet instead of dynamically generate it.

Here’s my PHP implementation of the algorithm:


<?php
/**
* This file contains PHP classes that can be used to crypt/decrypt strings.
* The encryption/decryption method is based on the Caesar cihper.
*
* (C) 2013 Anton Georgiev (http://github.com/angeorg/). All rights reserved.
* This work is licensed under a Creative Commons Attribution 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/
*/
interface MarcActions
{
public function crypt($string);
public function decrypt($string);
}
/**
* Mark PHP Cipher
*
* @version 1.0
* @copyright Anton Georgiev (https://github.com/angeorg/)
* @author Anton Georgiev
*
*/
class Marc implements MarcActions
{
// Set the encryption step performed by the cipher
protected $step = 3;
/**
* Constructor
*
* @return void
*/
public function __construct(Alphabet $alphabet)
{
$this->alphabet = $alphabet;
}
/**
* Crypt string
*
* @param string $string String to be crypted
* @return string
*/
public function crypt($string)
{
$encrypted = '';
$cyrillic_symbols = preg_replace('/[^\p{Cyrillic}]/u', '', trim($string));
$string = self::convert_to_cyrillic($cyrillic_symbols);
$alpha_upper = array_map('self::upper', $this->alphabet->letters);
for ($i = 0; $i < mb_strlen($string); $i++)
{
$next_letter = isset($string[$i+1]) ? $string[$i+1] : $string[0];
$next_letter_utf8 = self::convert_to_utf8($next_letter);
$next_letter_position = array_search(self::upper($next_letter_utf8),
$alpha_upper) + $this->step;
$encrypted .= $this->alphabet->letters[$next_letter_position];
}
return $encrypted;
}
/**
* Decrypt string
*
* @param string $string String to be decrypted
* @return string
*/
public function decrypt($string)
{
$decrypted = '';
$string = self::convert_to_cyrillic($string);
for ($i = 0; $i < mb_strlen($string); $i++)
{
$next_letter = isset($string[$i-1])
? $string[$i-1] : $string[strlen($string)-1];
$next_letter_utf8 = self::convert_to_utf8($next_letter);
$next_letter_position = array_search($next_letter_utf8,
$this->alphabet->letters) – $this->step;
$decrypted .= $this->alphabet->letters[$next_letter_position];
}
return $decrypted;
}
/**
* Make string uppercase
*
* @param string $string String to be processed
* @return string
*/
protected function upper($string)
{
return mb_convert_case($string, MB_CASE_UPPER, 'UTF-8');
}
/**
* Convert string to CP1251 encoding
*
* @param string $string UTF8 string
* @return string
*/
protected function convert_to_cyrillic($string)
{
return iconv('UTF-8', 'CP1251', $string);
}
/**
* Convert string to UTF-8 encoding
*
* @param string $string CP1251 string
* @return string
*/
protected function convert_to_utf8($string)
{
return iconv('CP1251', 'UTF-8', $string);
}
}
/**
* Mark Decorator
*
*/
class UpperMarc extends Marc
{
/**
* Decrypt string
*
* @param string $string String to be decrypted
* @return string
*/
public function decrypt($string)
{
$decrypted = parent::decrypt($string);
return self::upper($decrypted);
}
}
/**
* Alphabet used for encryption/decryption
*
*/
class Alphabet
{
// Use the Bulgarian alphabet by default
public $letters = array(
'А', 'Б', 'В', 'г', 'д', 'е', 'Ж', 'з', 'И', 'Й', 'К', 'л', 'М', 'Н', 'о',
'П', 'Р', 'с', 'Т', 'У', 'Ф', 'Х', 'Ц', 'ч', 'Ш', 'щ', 'Ъ', 'ь', 'Ю', 'Я',
'а', 'б', 'в',
);
/**
* Preview the alphabet using CLI
*
* @return void
*/
public function debug()
{
$keys = array();
$letter = array();
foreach($this->letters as $key => $value)
{
$letter_length = strlen($value);
$difference = $letter_length-1 – strlen($key);
$letter[] = ($difference)
? str_pad($value, $letter_length + abs($difference)) : $value;
$keys[] = $key;
}
echo implode('|', $letter) . PHP_EOL . implode('|', $keys) . PHP_EOL;
}
}

view raw

gistfile1.php

hosted with ❤ by GitHub

Here’s example usage of the algorithm:

$string = 'ТЕКСТ';

$alphabet = new Alphabet();
$alphabet->debug();

$crypto = new UpperMarc($alphabet);
$crypted = $crypto->crypt($string);

echo $crypted . PHP_EOL;

$decrypted = $crypto->decrypt($crypted);

echo $decrypted . PHP_EOL;

Leave a comment