From ae91589e599e051f2c909000a2b3ed7a501b02d0 Mon Sep 17 00:00:00 2001 From: Jasper Olbrich Date: Sat, 27 Jun 2015 16:13:18 +0200 Subject: [PATCH 1/3] Add CFB mode. Includes test vectors, result is PASS. --- blowfish.php | 28 ++++++++++++++++++++++------ tests/test.php | 10 +++++++--- tests/vectors_cfb.txt | 3 +++ 3 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 tests/vectors_cfb.txt diff --git a/blowfish.php b/blowfish.php index 6e0949b..37c45e4 100644 --- a/blowfish.php +++ b/blowfish.php @@ -14,6 +14,7 @@ class Blowfish { # Mode constants const BLOWFISH_MODE_EBC = 10; const BLOWFISH_MODE_CBC = 11; + const BLOWFISH_MODE_CFB = 12; # Padding mode constants const BLOWFISH_PADDING_NONE = 20; @@ -58,11 +59,19 @@ function encrypt($plaintext, $key, $mode=Blowfish::BLOWFISH_MODE_CBC, $padding=B if ($mode == Blowfish::BLOWFISH_MODE_CBC) { $chain = ($i == 0) ? $fish->IV : substr($ciphertext, $i - $block, $block); list(, $xL, $xR) = unpack('N2', substr($paded, $i, $block) ^ $chain); - } else { + $fish->_encipher($xL, $xR); + list(, $a, $b) = unpack('N2', pack('N2', $xL, $xR)); + $ciphertext .= pack('N2', $xL, $xR); + } else if ($mode ==Blowfish::BLOWFISH_MODE_CFB) { + $chain = ($i == 0) ? $fish->IV : substr($ciphertext, $i - $block, $block); + list(, $xL, $xR) = unpack('N2', $chain); + $fish->_encipher($xL, $xR); + $ciphertext .= substr($paded, $i, $block) ^ pack('N2', $xL, $xR); + }else { list(, $xL, $xR) = unpack('N2', substr($paded, $i, $block)); + $fish->_encipher($xL, $xR); + $ciphertext .= pack('N2', $xL, $xR); } - $fish->_encipher($xL, $xR); - $ciphertext .= pack('N2', $xL, $xR); } unset($fish); return $ciphertext; @@ -92,12 +101,19 @@ function decrypt($ciphertext, $key, $mode=Blowfish::BLOWFISH_MODE_CBC, $padding= # encrypt in 1 byte intervals for ($i=0; $i < $len; $i+=$block) { - list(, $xL, $xR) = unpack('N2', substr($ciphertext, $i, $block)); - $fish->_decipher($xL, $xR); if ($mode == Blowfish::BLOWFISH_MODE_CBC) { + list(, $xL, $xR) = unpack('N2', substr($ciphertext, $i, $block)); + $fish->_decipher($xL, $xR); $chain = ($i == 0) ? $fish->IV : substr($ciphertext, $i - $block, $block); $plaintext .= (pack('N2', $xL, $xR) ^ $chain); + } elseif ($mode == Blowfish::BLOWFISH_MODE_CFB) { + $chain = ($i == 0) ? $fish->IV : substr($ciphertext, $i - $block, $block); + list(, $xL, $xR) = unpack('N2', $chain); + $fish->_encipher($xL, $xR); // ENcipher! + $plaintext .= (substr($ciphertext, $i, $block) ^ pack('N2', $xL, $xR)); } else { + list(, $xL, $xR) = unpack('N2', substr($ciphertext, $i, $block)); + $fish->_decipher($xL, $xR); $plaintext .= pack('N2', $xL, $xR); } } @@ -484,4 +500,4 @@ class DefaultKey { ); } -?> \ No newline at end of file +?> diff --git a/tests/test.php b/tests/test.php index 0398a2f..8879b9a 100644 --- a/tests/test.php +++ b/tests/test.php @@ -9,6 +9,10 @@ $mode = Blowfish::BLOWFISH_MODE_CBC; $vectors = file(dirname(__FILE__) . '/vectors_cbc.txt'); break; + case 'cfb': + $mode = Blowfish::BLOWFISH_MODE_CFB; + $vectors = file(dirname(__FILE__) . '/vectors_cfb.txt'); + break; case 'key': $mode = Blowfish::BLOWFISH_MODE_EBC; $vectors = file(dirname(__FILE__) . '/vectors_key.txt'); @@ -20,7 +24,7 @@ } echo '
';
-if ($mode == Blowfish::BLOWFISH_MODE_CBC) {
+if ($mode == Blowfish::BLOWFISH_MODE_CBC || $mode == Blowfish::BLOWFISH_MODE_CFB) {
   echo sprintf('%-20s%-50s%-50s%-10s%s', 'Key/IV', 'Plain/Cipher In', 'Plain/Cipher Out', 'Result', PHP_EOL);
   echo sprintf('%-20s%-50s%-50s%-10s%s', '------', '---------------', '----------------', '------', PHP_EOL);  
 } else {
@@ -30,7 +34,7 @@
 foreach ($vectors as $v) {
   $v = trim($v);
   if ($v AND ($v[0] != '#')) {
-    if ($mode == Blowfish::BLOWFISH_MODE_CBC) {
+    if ($mode == Blowfish::BLOWFISH_MODE_CBC || $mode == Blowfish::BLOWFISH_MODE_CFB) {
       list($key, $plaintext, $expected_ciphertext, $iv) = preg_split('/\s+/', $v);
     } else {
       list($key, $plaintext, $expected_ciphertext) = preg_split('/\s+/', $v);
@@ -40,7 +44,7 @@
     $key = trim($key);
     $key = pack('H' . strlen($key), $key);
     
-    if ($mode == Blowfish::BLOWFISH_MODE_CBC) {
+    if ($mode == Blowfish::BLOWFISH_MODE_CBC || $mode == Blowfish::BLOWFISH_MODE_CFB) {
       $iv = trim($iv);
       $iv = pack('H' . strlen($iv), $iv);
     }
diff --git a/tests/vectors_cfb.txt b/tests/vectors_cfb.txt
new file mode 100644
index 0000000..7117e4a
--- /dev/null
+++ b/tests/vectors_cfb.txt
@@ -0,0 +1,3 @@
+# CFB Test Vectors - in Hex
+# Key                             Plain Text                                                  Cipher Text                                                       IV  
+0123456789ABCDEFF0E1D2C3B4A59687  37363534333231204E6F77206973207468652074696D6520666F722000  E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3        FEDCBA9876543210

From 47b8caefb08991022ecac9247bfdba59a929ee8d Mon Sep 17 00:00:00 2001
From: Jasper Olbrich 
Date: Sat, 27 Jun 2015 16:15:14 +0200
Subject: [PATCH 2/3] Update readme.textile

---
 readme.textile | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/readme.textile b/readme.textile
index 9c03d81..802cbc7 100644
--- a/readme.textile
+++ b/readme.textile
@@ -1,6 +1,6 @@
 h1. PHP_Blowfish
 
-PHP class which provides CBC and ECB Blowfish encryption without any external libraries. Tested using Eric Young's test vectors.
+PHP class which provides CBC, CFB and ECB Blowfish encryption without any external libraries. Tested using Eric Young's test vectors.
 
 h2. Dependencies
 
@@ -13,6 +13,7 @@ See the included example.php in the tests folder.
 h2. The MIT License
 
 Copyright (c) 2009 Matt Harris (http://themattharris.com)
+Copyright (c) 2015 Jasper Olbrich (the CFB part)
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -30,4 +31,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
\ No newline at end of file
+THE SOFTWARE.

From e76e0776070b8cdc7c482b3f1d3933b070fe0ea0 Mon Sep 17 00:00:00 2001
From: Jasper Olbrich 
Date: Sat, 27 Jun 2015 16:27:59 +0200
Subject: [PATCH 3/3] Add IV check, update phpdoc.

---
 blowfish.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/blowfish.php b/blowfish.php
index 37c45e4..d485872 100644
--- a/blowfish.php
+++ b/blowfish.php
@@ -37,7 +37,7 @@ function Blowfish($key, $mode, $padding, $iv=NULL) {
    *
    * @param string $plaintext the string to encrypt
    * @param string $key the encryption key
-   * @param int $mode one of BLOWFISH_MODE_CBC, BLOWFISH_MODE_EBC. BLOWFISH_MODE_CBC is recommened
+   * @param int $mode one of BLOWFISH_MODE_[CBC, CFB, EBC]. BLOWFISH_MODE_CBC is recommened
    * @param int $padding one of BLOWFISH_PADDING_NONE, BLOWFISH_PADDING_RFC, BLOWFISH_PADDING_ZERO. BLOWFISH_PADDING_RFC is recommened
    * @param int $iv the initialisation vector. Required when using CBC mode.
    * @return string Returns the encrypted string. It is recommended you base64encode this for storage.
@@ -89,7 +89,7 @@ function encrypt($plaintext, $key, $mode=Blowfish::BLOWFISH_MODE_CBC, $padding=B
    * @author Matt Harris
    **/
   function decrypt($ciphertext, $key, $mode=Blowfish::BLOWFISH_MODE_CBC, $padding=Blowfish::BLOWFISH_PADDING_RFC, $iv=NULL) {
-    if ( $mode == Blowfish::BLOWFISH_MODE_CBC and empty($iv) ) {
+    if ( ($mode == Blowfish::BLOWFISH_MODE_CBC || $mode == Blowfish::BLOWFISH_MODE_CFB) and empty($iv) ) {
       throw new Exception('CBC Mode requires an IV key');
       return;
     }