I am in process of developing the COM object that will encrypt the passed string. It is to be called from PHP.
I am not getting how can i return the value from COM to PHP. I tried following code perhaps it is not working.
STDMETHODIMP CATLObject::EncryptURL(VARIANT* sURLString, VARIANT* sEncryptedValue)
{
URLEncryption oURLEncryption;
char sRequestString[MAX_NAME] = "abcbbefekjdss dsf dsk fkjds fk sd";
char sEncrytedRequestStrin
g[MAX_NAME] = "";
char sDecrytedRequestString[MAX_NAME] = "";
oURLEncryption.EncryptQuery(sRequestString, sEncrytedRequestString);
KeyValue oKeyValue1;
KeyValue oParameterKeyValue;
oKeyValue1.ParseKeyValueString(sEncrytedRequestString, '&', true);
string sParameter = oKeyValue1.GetValue("sp");
string sCheckSum = oKeyValue1.GetValue("chk");
oURLEncryption.DecryptQuery(sParameter, sCheckSum, (void *)&oParameterKeyValue);
string sCidAudio = oParameterKeyValue.GetValue("cid_audio");
string sEUid = oParameterKeyValue.GetValue("euid");
printf("sCidAudio = %s\n", sCidAudio.c_str());
printf("sEUid = %s\n\n", sEUid.c_str());
// Create an instance of the MEMORYSTATUSEX structure
MEMORYSTATUSEX memstatex;
// Specify the length of the structure
memstatex.dwLength = sizeof(memstatex);
// Call the GlobalMemoryStatusEx function and pass to it
// a reference to our MEMORYSTATUSEX instance
::GlobalMemoryStatusEx(&memstatex);
// Set the ulVal (unsigned long value) of the VARIANT parameter
// passed by reference to the function with the dwMemoryLoad
// value of the MEMORYSTATUEX instance which specifies the
// approximate percentage of the physical memory currently
// in use.
sURLString->ulVal = memstatex.dwMemoryLoad;
sEncryptedValue->bstrVal = L"Output from DLL!!!";
return S_OK;
}
From PHP I am trying following way to get return value
$testConnection = new COM("URLEncryption.ATLObject");
$sURLString = new VARIANT(0, VT_UI4);
$sEncryptedValue = new VARIANT(0, VT_UI4);
$testConnection->EncryptURL($sURLString,$sEncryptedValue);
Looks to me to be a silly typo:
new COM("URLEncryption.ATLObject")
compared to
STDMETHODIMP CATLObject::EncryptURL
^^^
I'd say new COM should be changed to:
$testConnection = new COM("URLEncryption.CATLObject");
Related
I'm building a PHP based webpage. I want to use REST APIs to store, read and update data in an AZURE Cosmos DB.
First challenge is to generate the authentication token with the masterkey. I used the Microsoft documentation: https://learn.microsoft.com/de-de/rest/api/cosmos-db/access-control-on-cosmosdb-resources
and a postman collection* as a reference to build the code below.
*see
https://www.youtube.com/watch?v=2ndj_-zp82Y
https://github.com/MicrosoftCSA/documentdb-postman-collection
I used the console log from postman to compare each step and figured out that there are different results** but I have no clue how to get the same results from my PHP like from Postman
**
key64 PHP:
WUtDMFF5VWZkZ1NsTFp5UmU5ZVBMbW9jV3ZSN.....==
key64 Postman:
60a0b443251f7604a52d9c917bd78f2e6a1c5af4790d3f67dc7dbd513d173418... NO == at the end
authstring PHP:
type%253Dmaster%2526ver%253D1.0%2526sig%.....
authstring POSTMAN:
type%3Dmaster%26ver%3D1.0%26sig%3.....
POSTMAN (JS)
// store our master key for documentdb
var mastKey = postman.getEnvironmentVariable("DocumentDBMasterKey");
console.log("mastKey = " + mastKey);
// store our date as RFC1123 format for the request
var today = new Date();
var UTCstring = today.toUTCString();
postman.setEnvironmentVariable("RFC1123time", UTCstring);
// Grab the request url
var url = request.url.trim();
console.log("request url = " + url);
// strip the url of the hostname up and leading slash
var strippedurl = url.replace(new RegExp('^https?://[^/]+/'),'/');
console.log ("stripped Url = " + strippedurl);
// push the parts down into an array so we can determine if the call is on a specific item
// or if it is on a resource (odd would mean a resource, even would mean an item)
var strippedparts = strippedurl.split("/");
var truestrippedcount = (strippedparts.length - 1);
console.log(truestrippedcount);
// define resourceId/Type now so we can assign based on the amount of levels
var resourceId = "";
var resType = "";
// its odd (resource request)
if (truestrippedcount % 2)
{
console.log("odd");
// assign resource type to the last part we found.
resType = strippedparts[truestrippedcount];
console.log("resType");
console.log(resType);
if (truestrippedcount > 1)
{
// now pull out the resource id by searching for the last slash and substringing to it.
var lastPart = strippedurl.lastIndexOf("/");
resourceId = strippedurl.substring(1,lastPart);
console.log(resourceId);
}
}
else // its even (item request on resource)
{
console.log("even");
// assign resource type to the part before the last we found (last is resource id)
resType = strippedparts[truestrippedcount - 1];
console.log("resType");
// finally remove the leading slash which we used to find the resource if it was
// only one level deep.
strippedurl = strippedurl.substring(1);
console.log("strippedurl");
// assign our resourceId
resourceId = strippedurl;
console.log("resourceId");
console.log(resourceId);
}
// assign our verb
var verb = request.method.toLowerCase();
// assign our RFC 1123 date
var date = UTCstring.toLowerCase();
// parse our master key out as base64 encoding
var key = CryptoJS.enc.Base64.parse(mastKey);
console.log("key = " + key);
// build up the request text for the signature so can sign it along with the key
var text = (verb || "").toLowerCase() + "\n" +
(resType || "").toLowerCase() + "\n" +
(resourceId || "") + "\n" +
(date || "").toLowerCase() + "\n" +
"" + "\n";
console.log("text = " + text);
// create the signature from build up request text
var signature = CryptoJS.HmacSHA256(text, key);
console.log("sig = " + signature);
// back to base 64 bits
var base64Bits = CryptoJS.enc.Base64.stringify(signature);
console.log("base64bits = " + base64Bits);
// format our authentication token and URI encode it.
var MasterToken = "master";
var TokenVersion = "1.0";
auth = encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + base64Bits);
console.log("auth = " + auth);
// set our auth token enviornmental variable.
postman.setEnvironmentVariable("authToken", auth);
PHP CODE
#PHP Script
function generateAuthKey($url, $method){
$key = "****************";
$date = new DateTime('');
$date = $date->format('D, d M Y H:i:s O');
$ressourcetype = "";
$strippedurl = parse_url($url, PHP_URL_PATH);
$strippedparts = explode("/", $strippedurl);
$strippedurlcount = sizeof($strippedparts)-1;
#GET RESSOURCE TYPE
if ($strippedurlcount % 2){
$resType = $strippedparts[$strippedurlcount];
if ($strippedurlcount > 1){
$ressourcetype = $strippedparts[$strippedurlcount];
}
}
else{
$ressourcetype = $strippedparts[$strippedurlcount-1];
}
$sig = nl2br(strtolower($method)."\n".strtolower($ressourcetype)."\n".$strippedurl."\n".strtolower($date)."\n".""."\n");
$sig = utf8_encode($sig);
$key64 = base64_encode($key);
echo $key64."\n";
$hmac = hash_hmac('sha256',$sig,$key64);
$token = "type=master&ver=1.0&sig=".$hmac;
return urlencode($token);
}
How can I change the PHP script to provide the same output as Postman (JS)?
I believe the issue is with the following line of code:
$key64 = base64_encode($key);
As per the REST API documentation, you should be doing a base64_decode of your key as the key is already base64 encoded.
Please try by changing your code to:
$key64 = base64_decode($key);
While this is an old question, I'll note a couple issues with the author's code:
It was not necessary to utf8_encode() -- trying to utf8 encode a string that is already valid ISO-8859-1 can produce unexpected results. Also note that this method is deprecated as of PHP 8.2.0.
The author was returning the string output of hash_hmac(), rather than binary.
Here is how you correctly generate a signature in PHP. Bear in mind that all requests to the Cosmos REST API, needs to include an x-ms-date header, which matches the same date used to generate the token. It's up to you how to want to handle that, but in my case, I chose to return the date and token as an array from the function. You could also consider making the function return the entire header array all at once.
I am using Carbon and Guzzle in this example.
private function cosmosAuth(string $method, string $resourceType, string $resourceLink)
{
$date = Carbon::now()->toRfc7231String();
// alternatively: gmdate('D, d M Y H:i:s T')
$key = base64_decode(MY_COSMOS_KEY);
$body = $method . "\n" .
$resourceType . "\n" .
$resourceLink . "\n" .
$date . "\n" .
"\n";
$hash = hash_hmac('sha256', strtolower($body), $key, true);
$signature = base64_encode($hash);
$tokenType = "master";
$tokenVersion = "1.0";
$token = urlencode("type={$tokenType}&ver={$tokenVersion}&sig={$signature}");
return [
'date' => $date,
'token' => $token
];
}
Here is an example of a request to update a document. Note if you created your collection with a partition key, you also must pass the partition key value in the x-ms-documentdb-partitionkey header. The format here is a little janky, with Microsoft expecting a string representation of an array containing the value.
$resource = "dbs/{$database}/colls/{$collection}/docs/{$documentId}";
$auth = $this->cosmosAuth("PUT", "docs", $resource);
try {
$client = new \GuzzleHttp\Client();
$client->request("PUT", "https://{$account}.documents.azure.com/{$resource}", [
'headers' => [
'authorization' => $auth['token'],
'x-ms-date' => $auth['date'],
'x-ms-documentdb-partitionkey' => '["'.$documentId.'"]',
],
'json' => $documentData
]);
}
catch (Exception $e) {
$this->log("error: {$e->getMessage()}");
}
Microsoft resources:
Constructing a hashed token
Replace a document
I have a program that encrypts passwords using a c# rsa public key which outputs a byte array.
In order for me to transport it easily and maintain data I am converting the bytes directly to a Hex string. Now this is where I am having issue. I send the post data to my script and am now unsure what to convert it to and how to decrypt it.
I am attempting to use http://phpseclib.sourceforge.net/ which I was pointed to by this post RSA decryption using private key The documentation on this is very vague and I don't know what data/type decrypt() should take.
<?php
include('Crypt/RSA.php');
if (isset($_POST['Password']))
{
$Password = $_POST['Password'];
$crypttext = pack("H*",$Password);
echo $cryptext;
$rsa = new Crypt_RSA();
$rsa->loadKey('key.priv');
$decryptedText =$rsa->decrypt($cryptext);
echo "Pass = >" . $decryptedText;
}
?>
Note that this gives no errors but $decryptedText is empty.
EDIT: Adding more info.
This is my c# encrypt method.
public static string Encrypt(string data, string keyLocation, string keyName)
{
Console.WriteLine("-------------------------BEGIN Encrypt--------------------");
// Variables
CspParameters cspParams = null;
RSACryptoServiceProvider rsaProvider = null;
string publicKeyText = "";
string result = "";
byte[] plainBytes = null;
byte[] encryptedBytes = null;
try
{
// Select target CSP
cspParams = new CspParameters();
cspParams.ProviderType = 1; // PROV_RSA_FULL
rsaProvider = new RSACryptoServiceProvider(2048, cspParams);
// Read public key from Server
WebClient client = new WebClient();
Stream stream = client.OpenRead(keyLocation + "/" + keyName);
StreamReader reader = new StreamReader(stream);
publicKeyText = reader.ReadToEnd();
//
//Console.WriteLine("Key Text : {0}",publicKeyText);
// Import public key
rsaProvider.FromXmlString(publicKeyText);
// Encrypt plain text
plainBytes = Convert.FromBase64String(data);
Console.WriteLine("inputlength : {0}",plainBytes.Length);
encryptedBytes = rsaProvider.Encrypt(plainBytes, false);
result = ByteArrayToString(encryptedBytes);
Console.WriteLine("Encrypted Hex string : {0}", result);
}
catch (Exception ex)
{
// Any errors? Show them
Console.WriteLine("Exception encrypting file! More info:");
Console.WriteLine(ex.Message);
}
rsaProvider.Dispose();
Console.WriteLine("-------------------------END Encrypt--------------------");
return result;
} // Encrypt
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length / 2;
byte[] bytes = new byte[NumberChars];
using (var sr = new StringReader(hex))
{
for (int i = 0; i < NumberChars; i++)
bytes[i] =
Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
}
return bytes;
}
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
I modified the php to this
<?php
include('Crypt/RSA.php');
if (isset($_POST['Password']))
{
$Password = $_POST['Password'];
$crypttext = pack("H*",$Password);
echo $cryptext;
$rsa = new Crypt_RSA();
$rsa->loadKey(file_get_contents('key.priv')); // Added file_get_contents() which fixed the key loading
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); // Added this which is essential thank you guys/gals
$decryptedText =$rsa->decrypt($cryptext);
echo "Pass = >" . $decryptedText; // gives unsual data. This needs to be converted from binary data to base64string I think
echo "Pass = >" . base64_encode($decryptedText); // gives no data.
echo "Pass = >" . base64_decode($decryptedText); // gives no data.
}
?>
I searched around and tried several things to convert back to text and I have tried base64_encode() and base64_decode() but I get nothing and otherwise I get gobbledey gook.
The final solution was to use imap_binary($decryptedText) to convert back.
Edit :
It has since been brought to my attention that a better way of doing this would be to replace 2 things
C#
plainBytes = Convert.FromBase64String(data);
Changed to
plainBytes = Encoding.UTF8.GetBytes(data);
and PHP
imap_binary($decryptedText)
Changed to
utf8_decode($decryptedText)
Forgive me if this has already been answered/ is extremely basic/ the question is worded incorrectly, I am very new to this and struggling.
Basically I have back end PHP which generates XML, the flash builder then inherits the data. Where I'm stuck is understanding how the flash builder can send a parameter to the PHP through an HttpService e.g
This is what it currently interprets:
http://..../file.php?action=getitems
What I would like the flash builder to send is
&class=fruit (<- the class would be dependant on what is selected from the drop down in the application)
to overall create this string
http://..../file.php?action=getitems&class=fruit
Thank you and apologies if this is nonsense. I'm using Flash Builder 4.
This is actually rather simple in Flex...
var service : HTTPService = new HTTPService();
service.url = "http://localhost/getData.php";
service.method = "POST";
var parameters:Object = new Object();
parameters["action"] = "getitems";
parameters["class"] = "fruit";
service.send(parameters);
... done!
Overall I would use the push method instead of passing a variable, lessens the chance of getting hacked from the middle.
My AS3 Code for the http call:
public function someRequest() : void
{
var service : HTTPService = new HTTPService();
service.url = "http://localhost/getData.php";
service.useProxy = false;
service.method = "POST";
service.contentType = "application/xml"; // Pass XML data.
service.request = "<ID>somevalue</ID>"; // The XML data.
service.resultFormat = "xml"; // Recieve XML data.
service.addEventListener(ResultEvent.RESULT, createFields);
service.addEventListener(FaultEvent.FAULT, handleFault);
service.send();
}
private function createFields(event : ResultEvent) : void
{
var result : String = event.result.toString();
returnData = XML(result);
}
private function handleFault(event : FaultEvent) : void
{
var faultstring : String = event.fault.faultString;
Alert.show(faultstring);
}
As you see toward the middle, there is an XML space for entering a variable. I use this approach to pass data back and forth from the PHP to the AS3.
The PHP is:
<?php
define("DATABASE_SERVER", "localhost");
define("DATABASE_USERNAME", "root");
define("DATABASE_PASSWORD", "**");
define("DATABASE_NAME", "dbName");
//connect to the database.
$mysql = mysql_connect(DATABASE_SERVER, DATABASE_USERNAME, DATABASE_PASSWORD);
mysql_select_db(DATABASE_NAME);
$Query = "SELECT * from data WHERE employeeID = '" . ($_POST['ID']) . "'";
$Result = mysql_query($Query);
$Return = "<data>";
while ($User = mysql_fetch_object($Result))
{
$Return .= "<user><userid>" . $User->userid . "</userid><username>" . $User->username . "</username><emailaddress>" . $User->emailaddress . "</emailaddress></user>";
}
$Return .= "</data>";
mysql_free_result($Result);
print ($Return)
?>
Hope that helps you on your way.
I generally handle this through [POST] instead of [GET]
In your actionscript function:
private function sendRequest():void {
var obj:Object = new Object();
obj.action="getitems";
obj.class="fruit";
myService.send(obj);
Your httpService
<s:HTTPService id='myService' url='urlToYourPHP' method='POST' result='yourResultHandler' fault='yourFaultHandler' resultFormat='XML'/>
As powelljf3 said, POST is more secure then GET though it can still be gotten to.
I have been trying to get something called simplesamlphp hooked up to a django app.
I'm almost there… although i need to duplicate, in Python, the functionality of this php script:
I have copied the contents of the $raw variable in php, to the file 64.rtf. However when i run the Python equivalent i get an error stating:
TypeError: Incorrect padding
PHP code:
function getValue($raw) {
$val = $raw;
$url = parse_url($raw, PHP_URL_QUERY);
if (!empty($url)) $val = $url;
$arr = array();
$query = parse_str($val, &$arr);
#echo('<pre>');print_r($arr);
if (array_key_exists('SAMLResponse', $arr)) return $arr['SAMLResponse'];
if (array_key_exists('SAMLRequest', $arr)) return $arr['SAMLRequest'];
if (array_key_exists('LogoutRequest', $arr)) return $arr['LogoutRequest'];
if (array_key_exists('LogoutResponse', $arr)) return $arr['LogoutResponse'];
return rawurldecode(stripslashes($val));
}
function decode($raw) {
$message = getValue($raw);
#echo 'using value: ' . $message; exit;
$base64decoded = base64_decode($message);
$gzinflated = gzinflate($base64decoded);
if ($gzinflated != FALSE) {
$base64decoded = $gzinflated;
}
$decoded = htmlspecialchars($base64decoded);
return $decoded;
}
I have only come up with this in Python so far:
string64 = open("64.rtf", "rU").read()
decodedstring = base64.b64decode(string64,)
What am I not getting? the rawurldecode(stripslashes bit?? or url_parser??
and what exactly does these do thats so essential to the decoding?
I hope you can help. thanks…
Here it is, in all of its glory.
#!/usr/bin/env python
import base64
import zlib
import cgi
import urlparse
def getValue(raw):
args = urlparse.parse_qs(urlparse.urlparse(raw).query)
keys = ['SAMLResponse', 'SAMLRequest', 'LogoutRequest', 'LogoutResponse']
for key in keys:
if key in args: return args[key][0]
def decode(raw):
message = getValue(raw)
message = message + "=" * (4 - len(message) % 4)
base64decoded = base64.b64decode(message)
try:
base64decoded = zlib.decompressobj().decompress('x\x9c' + base64decoded)
except zlib.error:
pass # may want to handle this error
return cgi.escape(base64decoded, True)
data = 'PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIElEPSJwZnhkYTAxMjkzOC03MDkxLWNjZjQtZTc2Ny0wZWQ4OGVhN2Q1YmYiIFZlcnNpb249IjIuMCIgSXNzdWVJbnN0YW50PSIyMDExLTAxLTIxVDEyOjI4OjI5WiIgRGVzdGluYXRpb249Imh0dHBzOi8vd2F5Zi5teWRvbWFpbi5kay9zaW1wbGVzYW1sL3NhbWwyLW15bG9naW4ucGhwIiBJblJlc3BvbnNlVG89Il82ZDhmNDAxZDUzYTg1NDkzMzY2N2FiNWU5NzE1NWNmMzJjYWExMjBkZDciPjxzYW1sOklzc3Vlcj5odHRwczovL3Rlc3RicmlkZ2Uud2F5Zi5kazwvc2FtbDpJc3N1ZXI'
url = "http://www.google.com?SAMLResponse=" + data
print decode(url)
The reason you were getting an error when trying to b64decode your string, is because the string is not a TRUE base64 encoding. base64 encoded data is always a length that is evenly divisible by 4. Your string is not. In order to make the string length evenly divisible by 4, '=' characters are appended to the end of the string. In your case, the length % 4 == 3. So, we need to add one '=' to the end of the string to get it to decode correctly.
I want to pass an image as a byte array from php to a .NET web serice.
The php client is as follows:
<?php
class Image{
public $ImgIn = array();
}
$file = file_get_contents('chathura.jpg');
$ImgIn = str_split($file);
foreach ($ImgIn as $key=>$val) { $ImgIn[$key] = ord($val); }
$client = new SoapClient('http://localhost:64226/Service1.asmx?wsdl');
$result = $client->PutImage(new Image());
echo $result->PutImageResult;
//print_r($ImgIn);
?>
Here is the web method in ASP.NET web service:
[WebMethod]
public string PutImage(byte[] ImgIn)
{
System.IO.MemoryStream ms =
new System.IO.MemoryStream(ImgIn);
System.Drawing.Bitmap b =
(System.Drawing.Bitmap)Image.FromStream(ms);
b.Save("imageTest", System.Drawing.Imaging.ImageFormat.Jpeg);
return "test";
}
When I run this the image content is correctly read to ImgIm array in php client. (In this instance the image had 16992 elements.) However when the array is passed to the web service method it contains only 5 elements (the first 5 elements of the image)
Can I know what is the reason for the loss of data ? How can I avoid it ?
Thanks
file_get_contents returns the file contents as string which is not useful for binary files such as images. Try this:
$handle = fopen("chathura.jpg", "r");
$contents = fread($handle, filesize("chathura.jpg"));
fclose($handle);
$client = new SoapClient('http://localhost:64226/Service1.asmx?wsdl');
$result = $client->PutImage($contents);
Guys, it seems that it is not going to be any use to try and pass data as a byte array as PHP anyway converts it to a string when sending. This conversion seems to introduce control characters to the string, making it only send a part of the byte array. I got this to work by sending a base64 encoded string and decoding inside the server.
My client side code:
<?php
class Image{
public $ImgIn = '';
}
//ini_set("memory_limit","20M");
$imageData = file_get_contents('chathura.jpg');
$encodedData = base64_encode($imageData);
$Img = new Image();
$Img->ImgIn = $encodedData;
$client = new SoapClient('http://localhost:64226/Service1.asmx?wsdl');
$result = $client->PutImage($Img);
echo($result->PutImageResult);
?>
ASP .NET web service code:
[WebMethod]
public string PutImage(String ImgIn)
{
byte[] ImgInBytes = Convert.FromBase64String(ImgIn);
System.IO.MemoryStream ms =
new System.IO.MemoryStream(ImgInBytes);
System.Drawing.Bitmap b =
(System.Drawing.Bitmap)Image.FromStream(ms);
b.Save("C:\\imageTest.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
return "success";
}