Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AES/CBC/PKCS#5 Encryption Algorithm In PHP

Im attempting to integrate the SagePay payment gateway into a website using the 'Form Integration' method.

Basically the form integration method works by inserting a FORM in a webpage and POSTing information to SagePay's servers whenever the Submit button for the FORM is selected. Before the information can be sent to SagePay's servers it must be encrypted using the AES/CBC/PKCS#5 algorithm, before being Base 64 encoded.

I have a basic knowledge of encryption but I have no experience of using it in PHP. Can anyone please help me formulate the AES/CBC/PKCS#5 algorithm in PHP please?

Here's my efforts so far:

$CRYPT = "Text Goes Here";

$blocksize = 16;//Does 16 Refer To 16 Bytes Or 16 Bits? 16 Bytes = 128 Bits.
$cryptLength = strlen($CRYPT);
$cryptLengthModuloBlocksize = $cryptLength % $blocksize;
$pad = $blocksize - $cryptLengthModuloBlocksize;
$padString = str_repeat(chr($pad), $pad);
$CRYPT = $CRYPT . $padString;

$encryptionPassword = 'password';
$Encrypted_CRYPT = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $encryptionPassword, $CRYPT, MCRYPT_MODE_CBC);

$Base64_Encrypted_CRYPT = base64_encode($Encrypted_CRYPT);

echo    "<form action = 'https://test.sagepay.com/gateway/service/vspform-register.vsp' method = 'POST'>

            <input type = 'hidden' name = 'VPSProtocol' value = '3.00' />//
            <input type = 'hidden' name = 'TxType' value = 'PAYMENT' />
            <input type = 'hidden' name = 'Vendor' value = 'vendorName' />
            <input type = 'hidden' name = 'Crypt' value = '" . $Base64_Encrypted_CRYPT . "' />
            <input type= 'submit' value = 'Submit'>

        </form>";

Any help is much appreciated.

like image 633
slickboy Avatar asked Feb 20 '26 09:02

slickboy


2 Answers

Here is a working implementation of AES/CBC/PKCS#5 working with Sagepay's form integration You will need mcrypt installed. sp_encryption is a define for the encryption key.

/**
* @param string $data - the key=value pairs separated with & 
* @return string
*/
protected function encode_data($data) {
    $strIn = $this->pkcs5_pad($data);
    $strCrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, sp_encryption, $strIn, MCRYPT_MODE_CBC, sp_encryption);
    return "@" . bin2hex($strCrypt);
}

/**
* @param string $data - crypt response from Sagepay
* @return string
*/
protected function decode_data($data) {
    if (substr($data, 0, 1) == "@") {
        $strIn = hex2bin(substr($data, 1));
        return $this->pkcs5_unpad(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, sp_encryption, $strIn, MCRYPT_MODE_CBC, sp_encryption));
    }
    return '';
}

protected function pkcs5_pad($text) {
$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $pad = $size - (strlen($text) % $size);
    return $text . str_repeat(chr($pad), $pad);
}

protected function pkcs5_unpad($text) {
    $pad = ord($text{strlen($text) - 1});
    if ($pad > strlen($text)) return false;
    if (strspn($text, $text{strlen($text) - 1}, strlen($text) - $pad) != $pad) {
        return false;
    }
    return substr($text, 0, -1 * $pad);
}

On a side note make sure the VPSProtocol you use is '3.00' not 3, and not 3.0 as these won't work!

Hoep this helps and sagepay get some official PHP docs out soon.

like image 156
evo_rob Avatar answered Feb 22 '26 22:02

evo_rob


Yes, that's fine. (As soon as we have a PHP kit for v3.00 we'll display it on our website).

Hope the below helps you to.

Example:

AES encryption with Base64 encoding AES encryption, CBC blocking with PKCS5 padding then HEX encoding

//** Wrapper function do encrypt an encode based on strEncryptionType setting **
function encryptAndEncode($strIn) {

global $strEncryptionType
      ,$strEncryptionPassword;

{
    //** AES encryption, CBC blocking with PKCS5 padding then HEX encoding **

    //** use initialization vector (IV) set from $strEncryptionPassword
    $strIV = $strEncryptionPassword;

    //** add PKCS5 padding to the text to be encypted
    $strIn = addPKCS5Padding($strIn);

    //** perform encryption with PHP's MCRYPT module
    $strCrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $strEncryptionPassword, $strIn, MCRYPT_MODE_CBC, $strIV);

    //** perform hex encoding and return
    return "@" . bin2hex($strCrypt);
}
}


//** Wrapper function do decode then decrypt based on header of the encrypted field **
function decodeAndDecrypt($strIn) {

global $strEncryptionPassword;

if (substr($strIn,0,1)=="@") 
{
    //** HEX decoding then AES decryption, CBC blocking with PKCS5 padding  **

    //** use initialization vector (IV) set from $strEncryptionPassword
    $strIV = $strEncryptionPassword;

    //** remove the first char which is @ to flag this is AES encrypted
    $strIn = substr($strIn,1); 

    //** HEX decoding
    $strIn = pack('H*', $strIn);

    //** perform decryption with PHP's MCRYPT module
    return removePKCS5Padding(
        mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $strEncryptionPassword, $strIn, MCRYPT_MODE_CBC, $strIV));
} 

}
like image 20
Sage Pay Support Avatar answered Feb 22 '26 21:02

Sage Pay Support