I'm trying to set up my own OAuth provider, but now I'm stuck at signing requests. Is this the right way for signing?
function generateSignature($consumerSecret, $requestURI, $requestData, $requestMethod) {
$signature = '';
$signature .= strtoupper($requestMethod) . '&';
$signature .= urlencode($requestURI) . '&';
asort($requestData);
$query = http_build_query($requestData);
$signature .= urlencode($query);
echo oauthHMACsha1($consumerSecret, $signature);
}
function HMACsha1($key, $data) {
$blocksize = 64;
$hashfunc = 'sha1';
if (strlen($key) > $blocksize) $key = pack('H*', $hashfunc($key));
$key = str_pad($key, $blocksize, chr(0x00));
$ipad = str_repeat(chr(0x36), $blocksize);
$opad = str_repeat(chr(0x5c), $blocksize);
$hmac = pack('H*',$hashfunc(($key^$opad).pack('H*', $hashfunc(($key ^ $ipad) . $data))));
return $hmac;
}
function oauthHMACsha1($key, $data) {
return base64_encode(HMACsha1($key, $data));
}
Or can it be easier/more efficient? And why is signing important?
Have you seen hash_hmac php function?
Related
I'm trying to make a program where people can chat and I want to encrypt the messages that are being sent. I have 2 scripts for this, one is sendtext.php and another getchat.php.
So my question is how can I encrypt the text that's being sent in one file and then decrypt the messages that will be sent back which is in another file.
So far I have the encryption working but I dont know how to decrypt in the other file.
Also if you know a more secure way of doing this it would be appreciated.
sendtext.php
$username = $_POST["name"];
$text = $_POST["message"];
$key = openssl_random_pseudo_bytes(32, $cstrong);
$cipher = "aes-128-gcm";
if (in_array($cipher, openssl_get_cipher_methods()))
{
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext = openssl_encrypt($text, $cipher, $key, $options=0, $iv, $tag);
echo "Encrytped: " . $ciphertext;
//store $cipher, $iv, and $tag for decryption later
//$original_text = openssl_decrypt($ciphertext, $cipher, $key, $options=0, $iv, $tag);
//echo $original_text."\n";
}
//Add text to the table
$inserttextquery = "INSERT INTO ".$username." (username, message)
VALUES ('$username', '$ciphertext');";
mysqli_query($con, $inserttextquery) or die("#: send text failed");
getchat.php
$username = $_POST["name"];
$sql = "SELECT username, message FROM ".$username."";
$result = $con->query($sql);
if ($result->num_rows > 0)
{
// output data of each row
while($row = $result->fetch_assoc()) {
echo $row["username"] . "\t" . $row["message"] . "\t";
}
}
I wrote this encryption/decryption class awhile ago:
<?php
class Cryptography
{
private static $secret_key = 'gsdgsg423b523b5432bjbjm24vbjn2hv';
const CIPHER_16 = 'AES-128-CBC';
const CIPHER_32 = 'AES-256-CBC';
public static function encrypt($str, $cl = 32)
{
return static::encyptedDecypted('encrypt', $str, $cl);
}
public static function decrypt($str, $cl = 32)
{
return static::encyptedDecypted('decrypt', $str, $cl);
}
public static function encyptedDecypted($action, $str, $cl)
{
$cl = (int) $cl;
if ($cl === 16) {
$cipher = static::CIPHER_16;
$length = 16;
} elseif ($cl === 32) {
$cipher = static::CIPHER_32;
$length = 32;
} else {
throw new Exception('Error Processing Request', 1);
}
$iv = $iv = substr(hash('sha256', static:: $secret_key), 0, 16);
$key = hash('sha512', static::$secret_key);
if ($action == 'encrypt') {
$output = openssl_encrypt($str, $cipher, $key, 0, $iv);
$output = base64_encode($output);
$output = static::securesalts($length).$output.static::securesalts($length);
} elseif ($action == 'decrypt') {
$str = $text = substr($str, $length, -$length);
$output = openssl_decrypt(base64_decode($str), $cipher, $key, 0, $iv);
}
return $output;
}
private static function securesalts($length)
{
if (is_int($length) && $length >= 5) {
$chars = array_merge(range(0, 9), range('a', 'z'), range('A', 'Z'));
$stringlength = count($chars); //Used Count because its array now
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $chars[rand(0, $stringlength - 1)];
}
return $randomString;
} else {
return false;
}
}
}
Use it like this:
$str = "Simple String";
//for encryption
$encrypted = Cryptography::encrypt($str);
//for decryption
$decrypted = Cryptography::decrypt($encrypted);
Don't forget to change the $secret_key ;)
This is my C# code but I want same encrypted string in PHP. Can you please help me in any way.
var token ="MqsXexqpYRUNAHR_lHkPRic1g1BYhH6bFNVPagEkuaL8Mf80l_tOirhThQYIbfWYErgu4bDwl-7brVhXTWnJNQ2";
var id = "bob#company.com";
var ssokey = "7MpszrQpO95p7H";
string idAndKey = id + ssokey;
var salt = HttpServerUtility.UrlTokenDecode(token);
var pbkdf2 = new Rfc2898DeriveBytes(idAndKey, salt) {IterationCount = 1000};
var key = HttpServerUtility.UrlTokenEncode(pbkdf2.GetBytes(24));
//key = aE1k9-djZ66WbUATqdHbWyJzskMI5ABS0;
My PHP code is:
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
function base64url_decode($data) {
return base64_decode(str_pad(strtr($data, '-_', '+/'),strlen($data) % 4, '=', STR_PAD_RIGHT));
}
$token = "MqsXexqpYRUNAHR_lHkPRic1g1BYhH6bFNVPagEkuaL8Mf80l_tOirhThQYIbfWYErgu4bDwl-7brVhXTWnJNQ2";
$id = "bob#company.com";
$ssokey = "7MpszrQpO95p7H";
$idAndKey = $id.$ssokey;
$salt = base64_decode(base64url_decode($token));
$pbkdf2 = openssl_pbkdf2($idAndKey,$salt,20,1000);
$key = base64url_encode(base64_encode($pbkdf2));
//should produce key = aE1k9-djZ66WbUATqdHbWyJzskMI5ABS0
echo "key = ".$key; exit;
It should give aE1k9-djZ66WbUATqdHbWyJzskMI5ABS0 but is produced differently.
Any help is appreciated.
$idandKey = "bob#company.com" . "7MpszrQpO95p7H";
$salt = convertFromUrlTokenFormat("MqsXexqpYRUNAHR_lHkPRic1g1BYhH6bFNVPagEkuaL8Mf80l_tOirhThQYIbfWYErgu4bDwl-7brVhXTWnJNQ2");
$hash = hash_pbkdf2("sha1", $idandKey, base64_decode($salt), 1000, 24, true);
$key = convertToUrlTokenFormat(base64_encode($hash));
// key = “aE1k9-djZ66WbUATqdHbWyJzskMI5ABS0”;
function convertToUrlTokenFormat($val){
$padding = substr_count($val, '=');
$val = str_replace('=', '', $val);
$val .= $padding;
$val = str_replace('+', '-', str_replace('/', '_', $val));
return $val;
}
function convertFromUrlTokenFormat($val){
$val = str_replace('-', '+', str_replace('_', '/', $val));
$lastCharacter = substr($val, -1);
$val = substr($val, 0, -1);
switch($lastCharacter){
case 1:
$val = $val . "=";
break;
case 2:
$val = $val . "==";
break;
}
return $val;
}
What would be an equivalent for:
hash_hmac('sha256', 'data', 'key')
if I were using openssl_*?
openssl_digest does not take $key parameter.
This function uses the openssl_* extension to hash the data and the key:
Code
function openssl_hmac($algo, $data, $key, $raw_output = false)
{
$algo = strtolower($algo);
$pack = 'H' . strlen(openssl_digest('test', $algo));
$size = 64;
$opad = str_repeat(chr(0x5C), $size);
$ipad = str_repeat(chr(0x36), $size);
if (strlen($key) > $size) {
$key = str_pad(pack($pack, $algo($key)), $size, chr(0x00));
} else {
$key = str_pad($key, $size, chr(0x00));
}
for ($i = 0; $i < strlen($key) - 1; $i++) {
$opad[$i] = $opad[$i] ^ $key[$i];
$ipad[$i] = $ipad[$i] ^ $key[$i];
}
$output = openssl_digest($opad . pack($pack, openssl_digest($ipad . $data, $algo)), $algo);
return ($raw_output) ? pack($pack, $output) : $output;
}
Usage
echo openssl_hmac('sha256', 'data', 'key', false);
Result:
5031fe3d989c6d1537a013fa6e739da23463fdaec3b70137d828e36ace221bd0
The result is the same as when using the hash_hmac function:
echo hash_hmac('sha256', 'data', 'key');
Result:
5031fe3d989c6d1537a013fa6e739da23463fdaec3b70137d828e36ace221bd0
I have a big problem with hash_hmac
function
function hmac($key, $data){
$blocksize = 64;
$hashfunc = 'sha1';
if (strlen($key) > $blocksize)
$key = pack('H*', $hashfunc($key));
$key = str_pad($key, $blocksize, chr(0x00));
$ipad = str_repeat(chr(0x36), $blocksize);
$opad = str_repeat(chr(0x5c), $blocksize);
$hmac = pack('H*', $hashfunc(($key ^ $opad) . pack('H*', $hashfunc(($key ^ $ipad) . $data))));
return bin2hex($hmac);
}
example is:
<?php
echo hmac('111111', '222222');//=1558ab6c5ab2b0d1cd129b9ad11527cf33486705
but my
$jeden = 111111;
$dwa =222222;
$hashWiadomosci = hash_hmac('sha1', $jeden, $dwa);
is: 22f91d281349bb3081d3cec9f906572eec5c55b2
how i do wrong?
You have your input variables in the wrong order. If you look at the example from the comment you got this from; you can see that it is hmacsha1($key, $data) and not hmacsha1($data, $key) like you are using it and how hash_hmac($algorithm, $data, $key) works.
echo hash_hmac('sha1', '111111', '222222'); // 22f91d2813...
echo hmacsha1('111111', '222222'); // 1558ab6c5a...
echo hash_hmac('sha1', '111111', '222222'); // 22f91d2813...
echo hmacsha1('222222', '111111'); // 22f91d2813...
I've already looked through answers to other questions on the Sagepay protocol upgrade from 2.22 to 3.00, including the answer on my own previous question.
I am trying to update the encryption method from Xor to AES so the 3.00 protocol will work but have thus far got stuck on the Sagepay error 5068: the encryption method is not supported by this protocol. My company's three websites that need to be updated are based on the JShop e-commerce platform which is very outdated and no longer offers support.
I have implemented two solutions given as answers, one of which is taken from the Sagepay php documents available on their website but am still receiving this error.
I'd appreciate some input into where I am going wrong.
Have contacted Sagepay but they're not much help and have previously directed me here or to their partners page.
Protx (Sagepay) file:
<?php
function startProcessor($orderNumber) {
global $dbA,$orderArray,$jssStoreWebDirHTTP,$jssStoreWebDirHTTPS,$cartMain;
$callBack = "$jssStoreWebDirHTTPS"."gateways/response/protx.php";
$cDetails = returnCurrencyDetails($orderArray["currencyID"]);
$gatewayOptions = retrieveGatewayOptions("PROTX");
switch ($gatewayOptions["testMode"]) {
case "S":
$myAction = "https://test.sagepay.com/Simulator/VSPFormGateway.asp";
break;
case "Y":
$myAction = "https://test.sagepay.com/gateway/service/vspform-register.vsp";
break;
case "N":
$myAction = "https://live.sagepay.com/gateway/service/vspform-register.vsp";
break;
}
$myVendor = $gatewayOptions["vendor"];
$myEncryptionPassword = $gatewayOptions["encryptionPassword"];
$billingAddress = $orderArray["address1"]."\n";
if ($orderArray["address2"] != "") {
$billingAddress .= $orderArray["address2"]."\n";
}
$billingAddress .= $orderArray["town"]."\n";
$billingAddress .= $orderArray["county"]."\n";
$billingAddress .= $orderArray["country"];
$deliveryAddress = $orderArray["deliveryAddress1"]."\n";
if ($orderArray["deliveryAddress2"] != "") {
$deliveryAddress .= $orderArray["deliveryAddress2"]."\n";
}
$deliveryAddress .= $orderArray["deliveryTown"]."\n";
$deliveryAddress .= $orderArray["deliveryCounty"]."\n";
$deliveryAddress .= $orderArray["deliveryCountry"];
$crypt = "VendorTxCode=$orderNumber";
$crypt .= "&Amount=".number_format($orderArray["orderTotal"],$cDetails["decimals"],'.','');
$crypt .= "&Currency=".#$cDetails["code"];
$crypt .= "&Description=".$gatewayOptions["description"];
$crypt .= "&SuccessURL=$callBack?xOid=$orderNumber&xRn=".$orderArray["randID"];
$crypt .= "&FailureURL=$callBack?xOid=$orderNumber&xRn=".$orderArray["randID"];
$crypt .= "&BillingSurname=".$orderArray["surname"];
$crypt .= "&BillingFirstnames=".$orderArray["forename"];
$crypt .= "&BillingAddress1=".$orderArray["address1"];
$crypt .= "&BillingCity=".$orderArray["town"];
$crypt .= "&BillingPostCode=".preg_replace("/[^\s\-a-zA-Z0-9]/", "", $orderArray["postcode"]);
$crypt .= "&BillingCountry=".$orderArray["country"];
$crypt .= "&DeliverySurname=".$orderArray["surname"];
$crypt .= "&DeliveryFirstnames=".$orderArray["forename"];
if ($orderArray["deliveryPostcode"] != "") {
$crypt .= "&DeliveryAddress1=".$orderArray["deliveryAddress1"];
$crypt .= "&DeliveryCity=".$orderArray["deliveryTown"];
$crypt .= "&DeliveryPostCode=".preg_replace("/[^\s\-a-zA-Z0-9]/", "", $orderArray["deliveryPostcode"]);
$crypt .= "&DeliveryCountry=".$orderArray["deliveryCountry"]; }
else {
$crypt .= "&DeliveryAddress1=".$orderArray["address1"];
$crypt .= "&DeliveryCity=".$orderArray["town"];
$crypt .= "&DeliveryPostCode=".preg_replace("/[^\s\-a-zA-Z0-9]/", "", $orderArray["postcode"]);
$crypt .= "&DeliveryCountry=".$orderArray["country"]; }
$crypt .= "&BillingPhone=".preg_replace("/[^\sa-zA-Z0-9]/", "", $orderArray["telephone"]);
if ($gatewayOptions["sendEmail"] == 1) {
$crypt .= "&CustomerEmail=".$orderArray["email"]; }
$crypt .= "&VendorEmail=".$gatewayOptions["vendorEmail"];
$crypt .= "&ApplyAVSCV2=".$gatewayOptions["cvvCheck"];
$crypt .= "&Apply3dSecure=".$gatewayOptions["3DSecure"];
$crypt = base64_encode(encryptAes($crypt, $myEncryptionPassword));
$tpl = createTSysObject(templatesCreatePath($cartMain["templateSet"]),"gatewaytransfer.html",$requiredVars,0);
$gArray["method"] = "POST";
$gArray["action"] = $myAction;
$gArray["fields"][] = array("name"=>"VPSProtocol","value"=>"3.00");
$gArray["fields"][] = array("name"=>"Vendor","value"=>$myVendor);
$gArray["fields"][] = array("name"=>"TxType","value"=>$gatewayOptions["txType"]);
$gArray["fields"][] = array("name"=>"Crypt","value"=>$crypt);
$mArray = $gArray;
$gArray["process"] = "document.automaticForm.submit();";
$tpl->addVariable("shop",templateVarsShopRetrieve());
$tpl->addVariable("labels",templateVarsLabelsRetrieve());
$tpl->addVariable("automaticForm",$gArray);
$tpl->addVariable("manualForm",$mArray);
$tpl->showPage();
}
function addPKCS5Padding($input)
{
$blockSize = 16;
$padd = "";
$length = $blockSize - (strlen($input) % $blockSize);
for ($i = 1; $i <= $length; $i++)
{
$padd .= chr($length);
}
return $input . $padd;
}
function removePKCS5Padding($input)
{
$blockSize = 16;
$padChar = ord($input[strlen($input) - 1]);
$unpadded = substr($input, 0, (-1) * $padChar);
return $unpadded;
}
function encryptAes($string, $key)
{
$string = addPKCS5Padding($string);
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $key);
return strtoupper(bin2hex($crypt));
}
function decryptAes($strIn, $myEncryptionPassword)
{
#Sagepay specific - remove the '#'
$strIn = substr($strIn,1);
$strInitVector = $myEncryptionPassword;
$strIn = pack('H*', $hex);
$string = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $myEncryptionPassword, $strIn, MCRYPT_MODE_CBC,$strInitVector);
return removePKCS5Padding($string);
}
?>
Response file:
<?php
define("IN_JSHOP", TRUE);
include("../../static/config.php");
include("../../routines/dbAccess_".$databaseType.".php");
include("../../routines/tSys.php");
include("../../routines/general.php");
include("../../routines/stockControl.php");
include("../../routines/emailOutput.php");
require_once 'SagepayUtil.php';
dbConnect($dbA);
$orderID = makeSafe(getFORM("xOid"));
$newOrderID = $orderID;
$randID = makeSafe(getFORM("xRn"));
$crypt = makeSafe(getFORM("crypt"));
$gatewayOptions = retrieveGatewayOptions("PROTX");
$orderID = makeInteger($orderID) - retrieveOption("orderNumberOffset");
$result = $dbA->query("select * from $tableOrdersHeaders where orderID=$orderID and randID='$randID'");
if ($dbA->count($result) == 0 || $crypt=="") {
doRedirect_JavaScript($jssStoreWebDirHTTP."index.php");
exit;
}
$orderArray = $dbA->fetch($result);
$ccResult = $dbA->query("select * from $tablePaymentOptions where paymentID=".$orderArray["paymentID"]);
$poRecord = $dbA->fetch($ccResult);
$paidStatus = $poRecord["statusID"];
$crypt = str_replace(" ","+",$crypt);
//$crypt = protx_simpleXor(base64_decode($crypt),$gatewayOptions["encryptionPassword"]);
$crypt = decryptAes(base64_decode($crypt), $gatewayOptions["encryptionPassword"]);
$nameValues = explode("&",$crypt);
$resultCode = "";
for ($f = 0; $f < count($nameValues); $f++) {
$thisCode = explode("=",$nameValues[$f]);
$resultCode[$thisCode[0]] = $thisCode[1];
}
if ($resultCode["VendorTxCode"] != $newOrderID) {
doRedirect_JavaScript($jssStoreWebDirHTTP."index.php");
exit;
}
$authResponse = "&Status Result=".$resultCode["Status"]."&AVS/CV2 Check=".#$resultCode["AVSCV2"]."&Address Result=".#$resultCode["AddressResult"]."&Postcode Result=".#$resultCode["PostCodeResult"]."&CV2 Result=".#$resultCode["CV2Result"]."&3d Secure Status=".#$resultCode["3DSecureStatus"];
$randID = $orderArray["randID"];
if ($orderArray["status"] != $paidStatus) {
$dt=date("YmdHis",createOffsetTime());
switch ($resultCode["Status"]) {
case "OK":
case "AUTHENTICATED":
case "REGISTERED":
$authResponse="Gateway=Sage Pay&Authorisation Code=".$resultCode["TxAuthNo"]."&Sage Pay Transaction ID=".$resultCode["VPSTxId"]."&Status=Payment Confirmed".$authResponse;
$dbA->query("update $tableOrdersHeaders set status=$paidStatus, authInfo=\"$authResponse\", paymentDate=\"$dt\" where orderID=$orderID");
$orderArray["status"] = $paidStatus;
//ok, this is where we should do the stock control then.
include("process/paidProcessList.php");
doRedirect_JavaScript($jssStoreWebDirHTTPS."process.php?xOid=$newOrderID&xRn=$randID");
break;
case "REJECTED":
$authResponse="Gateway=Sage Pay&Status=Payment Rejected Due To Rules".$authResponse;
$dbA->query("update $tableOrdersHeaders set status=3, authInfo=\"$authResponse\", paymentDate=\"$dt\" where orderID=$orderID");
include("process/failProcessList.php");
doRedirect_JavaScript($jssStoreWebDirHTTPS."process.php?xOid=$newOrderID&xRn=$randID");
break;
default:
if ($orderArray["status"] == 1) {
$authResponse="Gateway=Sage Pay&Status=Payment Failed".$authResponse;
$dbA->query("update $tableOrdersHeaders set status=3, authInfo=\"$authResponse\", paymentDate=\"$dt\" where orderID=$orderID");
include("process/failProcessList.php");
}
doRedirect_JavaScript($jssStoreWebDirHTTPS."process.php?xOid=$newOrderID&xRn=$randID");
break;
}
} else {
doRedirect_JavaScript($jssStoreWebDirHTTPS."process.php?xOid=$newOrderID&xRn=$randID");
}
function addPKCS5Padding($input)
{
$blockSize = 16;
$padd = "";
$length = $blockSize - (strlen($input) % $blockSize);
for ($i = 1; $i <= $length; $i++)
{
$padd .= chr($length);
}
return $input . $padd;
}
function removePKCS5Padding($input)
{
$blockSize = 16;
$padChar = ord($input[strlen($input) - 1]);
$unpadded = substr($input, 0, (-1) * $padChar);
return $unpadded;
}
function encryptAes($string, $key)
{
$string = addPKCS5Padding($string);
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $key);
return strtoupper(bin2hex($crypt));
}
function decryptAes($strIn, $myEncryptionPassword)
{
#Sagepay specific - remove the '#'
$strIn = substr($strIn,1);
$strInitVector = $myEncryptionPassword;
$strIn = pack('H*', $hex);
$string = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $myEncryptionPassword, $strIn, MCRYPT_MODE_CBC,$strInitVector);
return removePKCS5Padding($string);
}
?>
Make sure you back up the files first, then change this line:
$crypt =base64_encode(encryptAes($crypt, $myEncryptionPassword));
to
$crypt = "#".encryptAes($crypt, $myEncryptionPassword);
And:
$crypt = decryptAes(base64_decode($crypt), $gatewayOptions["encryptionPassword"]);
To:
$crypt = decryptAes($crypt, $gatewayOptions["encryptionPassword"]);
Having looked at the decrypt bit, the removal of the '#' is already there. I'm not a PHP guy, so this may not be perfect!
Give it a go without the base64 encryption, and make sure you add '#' to the beginning of the crypt when encoding (and remove it from the crypt when decrypting the transaction result).