Skip to content

Instantly share code, notes, and snippets.

@http403
Last active March 22, 2016 13:04
Show Gist options
  • Save http403/39857700831591775b1c to your computer and use it in GitHub Desktop.
Save http403/39857700831591775b1c to your computer and use it in GitHub Desktop.
AES Encryption with Custom Block Cipher Mode
AES Encryption with Custom Block Cipher Mode.
THIS BLOCK CIPHER MODE MAY HAVE POTENTIAL VULNERABILITY, DO NOT USE IN PRODUCTION PRODUCT. I code it ONLY FOR FUN AND TESTING PURPOSE.
<?php
interface Base62Interface {
public static function encode($data);
public static function decode($data);
}
Class Base62 implements Base62Interface {
/**
* @param $data
* @return string
*/
public static function encode($data) {
$outstring = '';
$l = strlen($data);
for ($i = 0; $i < $l; $i += 8) {
$chunk = substr($data, $i, 8);
$outlen = ceil((strlen($chunk) * 8)/6); //8bit/char in, 6bits/char out, round up
$x = bin2hex($chunk); //gmp won't convert from binary, so go via hex
$w = gmp_strval(gmp_init(ltrim($x, '0'), 16), 62); //gmp doesn't like leading 0s
$pad = str_pad($w, $outlen, '0', STR_PAD_LEFT);
$outstring .= $pad;
}
return $outstring;
}
/**
* @param $data
* @return string
*/
public static function decode($data) {
$outstring = '';
$l = strlen($data);
for ($i = 0; $i < $l; $i += 11) {
$chunk = substr($data, $i, 11);
$outlen = floor((strlen($chunk) * 6)/8); //6bit/char in, 8bits/char out, round down
$y = gmp_strval(gmp_init(ltrim($chunk, '0'), 62), 16); //gmp doesn't like leading 0s
$pad = str_pad($y, $outlen * 2, '0', STR_PAD_LEFT); //double output length as as we're going via hex (4bits/char)
$outstring .= pack('H*', $pad); //same as hex2bin
}
return $outstring;
}
}
?>
<?php
interface CryptFunctionsInterface {
public static function signText($plaintext, $key);
public static function genSubKey($key, $salt);
}
class CryptFunctions implements CryptFunctionsInterface {
protected static function ivAdd($big_num_str, $to_add) {
$big_num = str_split(strrev($big_num_str));
for ($i = 0; $i < count($big_num); $i++) {
$tmp = ord($big_num[$i]) + $to_add;
$big_num[$i] = $tmp % 256;
$to_add = floor( $tmp / 256 );
}
while($to_add) {
$big_num[$i++] = $to_add % 256;
$to_add = floor( $to_add / 256 );
}
for ($i = 0; $i < count($big_num); $i++) {
$big_num[$i] = chr($big_num[$i]);
}
return strrev(implode('', $big_num) );
}
/**
* @return string
*/
public static function genSafeRandomBytes($len) {
$cstrong = false;
while (!$cstrong) {
$bytes = openssl_random_pseudo_bytes($len, $cstrong);
}
return $bytes;
}
/**
* @param $iv
* @return bool|string
*/
public static function genSubKey($key, $salt) {
return openssl_pbkdf2($key, $salt, 32, 50000, "SHA256");
}
/**
* @param $plaintext
* @param $key
* @return string
*/
public static function signText($plaintext, $key) {
return hash_hmac("sha512", $plaintext, $key, true);
}
}
?>
<?php
require "framework.CryptFunctions.class.php";
require "framework.Base62.class.php";
interface AESCustomInterface {
const CIPHER = "aes-256-ecb";
public static function encrypt($key, $data);
public static function decrypt($key, $data);
}
class AESCustom extends CryptFunctions implements AESCustomInterface {
public static function encrypt($key, $data) {
$iv = parent::genSafeRandomBytes(16);
$nonce = parent::genSafeRandomBytes(16);
echo "First Block XOR\n";
$firstBlock = self::strxor_direct($nonce, $iv);
$salt = parent::genSafeRandomBytes(16);
$hmac = parent::signText($data, $key);
$subkey = parent::genSubKey($key, $salt);
$data = self::pkcs7pad($data);
echo "HEX Data w/ Pad: " . bin2hex($data) . "\n";
$tmp_r = base64_decode(openssl_encrypt($firstBlock, self::CIPHER, $subkey, OPENSSL_ZERO_PADDING));
$result = '';
for ($i = 0; $i < ceil(strlen($data) / 16); $i++) {
$tmp_n = parent::ivAdd($nonce, $i+1);
echo "TMP Nonce XOR\n";
$tmp_n = self::strxor_direct($tmp_n, $tmp_r);
$tmp_x = base64_decode(openssl_encrypt($tmp_n, self::CIPHER, $subkey, OPENSSL_ZERO_PADDING));
$tmp_d = substr($data, 16 * $i, 16);
echo "TMP Result XOR\n";
echo "TMP X: " . bin2hex($tmp_x) . "\n";
echo "TMP D: " . bin2hex($tmp_d) . "\n";
$result .= $tmp_r = self::strxor_direct($tmp_x, $tmp_d);
}
echo "HEX Chiphertext: " . bin2hex($result) . "\n";
return base64_encode($iv.$nonce.$salt.$hmac.$result);
//return bin2hex($result);
}
public static function decrypt($key, $data) {
$data = base64_decode($data);
$iv = substr($data, 0, 16);
$nonce = substr($data, 16, 16);
$salt = substr($data, 32, 16);
$hmac = substr($data, 48, strlen(parent::signText(null, null)));
$data = substr($data, 48 + strlen(parent::signText(null, null)));
$data = str_split($data, 16);
$subkey = parent::genSubKey($key, $salt);
$firstBlock = self::strxor_direct($nonce, $iv);
$tmp_r = base64_decode(openssl_encrypt($firstBlock, self::CIPHER, $subkey, OPENSSL_ZERO_PADDING));
$result = '';
for ($i = 0; $i < count($data); $i++) {
$tmp_n = parent::ivAdd($nonce, $i+1);
$tmp_n = self::strxor_direct($tmp_n, $tmp_r);
$tmp_x = base64_decode(openssl_encrypt($tmp_n, self::CIPHER, $subkey, OPENSSL_ZERO_PADDING));
$result .= $tmp_r = self::strxor_direct($tmp_x, $data[$i]);
}
//return self::pkcs7unpad($result);
return ($result);
}
private static function strxor_direct($dataA, $dataB) {
if (strlen($dataA) != strlen($dataB)) {
$e_msg = "Length Not Match";
throw new Exception($e_msg);
}
return $dataA ^ $dataB;
}
private static function pkcs7pad($message) {
$blocksize = 16;
$padsize = $blocksize - (strlen($message) % $blocksize);
return $message . str_repeat(chr($padsize), $padsize);
}
private static function pkcs7unpad($message) {
$length = strlen($message);
$blocksize = 16;
if($length % $blocksize != 0)
throw new Exception("Block Size Error");
$padsize = ord($message[$length - 1]);
if($padsize === 0)
throw new Exception("Zero Padding Found");
$padding = substr($message, -$padsize);
if($padsize > $blocksize || substr_count($padding, chr($padsize)) != $padsize)
throw new Exception("Padding Corrupted");
return substr($message, 0, $length - $padsize);
}
}
try {
$pass = "GOOGLE";
echo $ciphertext = AESCustom::encrypt($pass, "aaaaaaaaaaaaaaaa") . "\n";
echo bin2hex(AESCustom::decrypt($pass, $ciphertext));
} catch (Exception $e) {
echo "ERROR: " . $e->getMessage() . " at line " . $e->getLine();
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment