I'm very new to Erlang, and I am converting some of my PHP stuff, and I can't figure this one out. Here is the function in PHP:
public function raw_send($string1, $string2 = NULL, $type = SERVERDATA_EXECCOMMAND) {
$data = pack('VV', $this->get_request_id(), $type) . $string1 . chr(0) . $string2 . chr(0); // build data
$packet = pack('V', strlen($data)) . $data;
fwrite($this->fp, $packet, strlen($packet));
}
This is my attempt:
raw_send(Sock, String1, String2, Type) ->
RequestId = random:uniform(10),
PacketData = list_to_binary([<<RequestId, Type>>, String1, 0, String2, 0]),
DataLength = byte_size(PacketData),
Packet = list_to_binary([<<DataLength>>, PacketData]),
ok = gen_tcp:send(Sock, Packet).
I've tried using crc32 to compare things, pack("VV", 1, 3) in php should = <<1/unsigned-little, 3/unsigned-little>>, no?
Also, specs of what I'm trying to do: http://developer.valvesoftware.com/wiki/Source_RCON_Protocol
Halp!
Thanks
Got it, wasn't using 32 bit integers! (Thanks to ndim # freenode)
raw_send(Sock, String1, String2, Type) ->
RequestId = random:uniform(10),
String1Bin = list_to_binary(String1),
String2Bin = list_to_binary(String2),
PacketData = <<RequestId:32/little, Type:32/little, String1Bin/binary, 0, String2Bin/binary, 0>>,
DataLength = byte_size(PacketData),
Packet = <<DataLength:32/little, PacketData/binary>>,
ok = gen_tcp:send(Sock, Packet).
Hope that helps someone!
Related
Given the following inputs:
CLIENT RANDOM : 61fc160e0a6e96db43aebcca55da7fbccb97cc04d59fcc105490b4396a915ab9
SERVER RANDOM : f0ecb127db6e353a2985894c123532a8d092fafcf7cdce3a444f574e47524401
PREMASTER KEY : 0303ec4418e91f0abf9a012f524b61c0312008641ebce76d68b2417447e3d9a970d02fd65a20e5e3e98413dbd13b6536
First I use these input to calculate the following key buffers:
CLIENT MAC: 500c7c6e6101cb1693b4cee7db6fb0bc2725deca
SERVER MAC: 41e260280fe213bd5f2c0412c69389cac2e39e4f
CLIENT KEY: c17226212f6195c1515602a0c0864ec90e73e7bcd05ad90b196fd5a5cb2445f2
SERVER KEY: 6b07166b634a7e58e623b969eb0c024a1e866bc2719c054e1a05849b87ccf79b
CLIENT IV: dac71f7b3639cf4d4ec86ee51b9530f6
SERVER IV: c1212631365432c8d5a4c93f6f999a8e
I calculate these values using helper functions I found online:
function p_hash($algo, $secret, $seed, $size) {
$output = "";
$a = $seed;
while (strlen($output) < $size) {
$a = hash_hmac($algo, $a, $secret, true);
$output .= hash_hmac($algo, $a . $seed, $secret, true);
}
return substr($output, 0, $size);
}
function prf_tls12($secret, $label, $seed, $size) {
return p_hash("sha256", $secret, $label . $seed, $size);
}
function generate_master($pre_master_secret, $client_random, $server_random) {
return prf_tls12($pre_master_secret, 'master secret', $client_random . $server_random, 48);
}
$client_random = hex2bin('61fc160e0a6e96db43aebcca55da7fbccb97cc04d59fcc105490b4396a915ab9');
$server_random = hex2bin('f0ecb127db6e353a2985894c123532a8d092fafcf7cdce3a444f574e47524401');
$pre_master_secret = hex2bin('0303ec4418e91f0abf9a012f524b61c0312008641ebce76d68b2417447e3d9a970d02fd65a20e5e3e98413dbd13b6536');
$master_secret = generate_master($pre_master_secret, $client_random, $server_random);
$key_buffer = prf_tls12($master_secret, 'key expansion', $server_random . $client_random, 136);
$client_mac = substr($key_buffer, 0, 20);
$server_mac = substr($key_buffer, 20, 20);
$client_key = substr($key_buffer, 40, 32);
$server_key = substr($key_buffer, 72, 32);
$client_iv = substr($key_buffer, 104, 16);
$server_iv = substr($key_buffer, 120, 16);
Here I have an AES_256_CBC encrypted message sent from the CLIENT ---> SERVER in Hex format
$EncryptedMessage = 'f32da333a3416888d55c583c9796f8fc498895e386616a62aa364a41cd2bfc203c1f296b4afd9c4a9674c993bf0db558de0c0cb2b3dc4b083af3824e0b9a3327';
I run the following code using the PHPSECLIB v3.0 plugin:
$cipher = new AES('cbc');
$cipher->setIV($client_iv);
$cipher->setKey($client_key);
$cipher->disablePadding();
$DecryptedMessage = bin2hex($cipher->decrypt(hex2bin($EncryptedMessage)));
print($DecryptedMessage);
I get the following output in Hex:
f889ff0ce7cc744c2182363e7117ae74e34ccb0510099e7c11133c369f98468de9f20fa6e7207c8121484a9663929d1af4bffb5410da37029aa26b9298411e3b
Basically, I have no idea whether I'm doing this right or not. I dont seem to see anything in my decrypted message. Also, unless I specifically use the $cipher->disablePadding(); I will get a PHP Fatal Error saying that PHP Fatal error: Uncaught phpseclib3\Exception\BadDecryptionException: The ciphertext has an invalid padding length (81) compared to the block size (16)
Note: This is supposed to be an "Encrypted Handshake Message" sent as the first message from a client to server after the Key Exchange using TLS 1.2. I am unable to determine if my decryption is correct, since I cant find much on the structure of value anywhere. Any help is appreciated, thanks!
I am writing a PHP code for AMAZON WEB SERVICES. This is my code.
<?php
function amazonEncode($text) {
$encodedText = "";
$j = strlen($text);
for ($i = 0; $i < $j; $i++) {
$c = substr($text, $i, 1);
if (!preg_match("/[A-Za-z0-9-_.~]/", $c)) {
$encodedText .= sprintf("%%%02X", ord($c));
} else {
$encodedText .= $c;
}
}
return $encodedText;
}
function amazonSign($url, $secretAccessKey) {
// 0. Append Timestamp parameter
$url .= "&Timestamp=" . gmdate("Y-m-dTH:i:sZ");
// 1a. Sort the UTF-8 query string components by parameter name
$urlParts = parse_url($url);
parse_str($urlParts["query"], $queryVars);
ksort($queryVars);
// 1b. URL encode the parameter name and values
$encodedVars = array();
foreach ($queryVars as $key => $value) {
$encodedVars[amazonEncode($key)] = amazonEncode($value);
}
// 1c. 1d. Reconstruct encoded query
$encodedQueryVars = array();
foreach ($encodedVars as $key => $value) {
$encodedQueryVars[] = $key . "=" . $value;
}
$encodedQuery = implode("&", $encodedQueryVars);
// 2. Create the string to sign
$stringToSign = "GET";
$stringToSign .= "n" . strtolower($urlParts["host"]);
$stringToSign .= "n" . $urlParts["path"];
$stringToSign .= "n" . $encodedQuery;
// 3. Calculate an RFC 2104-compliant HMAC with the string you just created,
// your Secret Access Key as the key, and SHA256 as the hash algorithm.
if (function_exists("hash_hmac")) {
$hmac = hash_hmac("sha256", $stringToSign, $secretAccessKey, TRUE);
} elseif (function_exists("mhash")) {
$hmac = mhash(MHASH_SHA256, $stringToSign, $secretAccessKey);
} else {
die("No hash function available!");
}
// 4. Convert the resulting value to base64
$hmacBase64 = base64_encode($hmac);
// 5. Use the resulting value as the value of the Signature request parameter
// (URL encoded as per step 1b)
$url .= "&Signature=" . amazonEncode($hmacBase64);
echo $url;
}
$url = 'http://webservices.amazon.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId=something&AssociateTag=something&Operation=ItemSearch&Keywords=Mustang&SearchIndex=Blended&Condition=Collectible&Timestamp=2016-08-08T12%3A00%3A00Z&Version=2013-08-01';
$SECRET_KEY = 'my_secret_key';
$url = amazonSign($url, $SECRET_KEY);
?>
This code returns me a URL. I use that URL inside my browser so that I can get my search results but using that URL gives me this error.
SignatureDoesNotMatchThe request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
I am using these as AWSAccessKeyId and SECRET_KEY.
It's probably $stringToSign .= "n" should be $stringToSign .= "\n" but this might not be the only problem. If you use the official PHP SDK from Amazon instead of relying on custom scripts you'll have less issues.
The error you are seeing is usually a mistyped Access Key or Secret Access Key.
or the issue may be non-UTF-8 encoded string. Once i UTF-8 encoded it, the error will disappeared.
or if you sending a metadata with an empty value,than it will not work.
or if you not providing the Content-Length parameter than also such kind of issue can happen.
In my android app, it downloads a huge huge string from php. I want to compress it to save bandwidth. I found this page http://php.net/manual/en/function.gzcompress.php which allows me to compress it in php. But once I have it in android, how can I get back the original string?
Thanks
In my case I needed to decompress a string in PHP which was compressed in Android and visa versa and these strings were transported by RabbitMQ.
Here is how I solved it:
In Android:
public static byte[] compress(String string) throws IOException {
// string = "Lorem ipsum shizzle ma nizle";
byte[] data = string.getBytes("UTF-8");
ByteArrayOutputStream os = new ByteArrayOutputStream( data.length );
GZIPOutputStream gos = new GZIPOutputStream(os);
gos.write( data );
gos.close();
os.close();
return os.toByteArray();
}
public static String decompress(byte[] compressed) throws IOException {
final int BUFFER_SIZE = compressed.length;
ByteArrayInputStream is = new ByteArrayInputStream(compressed);
GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
StringBuilder string = new StringBuilder();
byte[] data = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = gis.read(data)) != -1) {
string.append(new String(data, 0, bytesRead));
}
gis.close();
is.close();
return string.toString();
}
RabbitMQ Calls from Android:
.
.
// Publish
chan.basicPublish(EXCHANGE, routing_key, MessageProperties.PERSISTENT_BASIC, compress(message.payload));
.
.
// Subscribe
String message = decompress(body);
.
.
.
From the RabbitMQ management plugin I retrieved the Base64 encoded version of the string in Latin, and ran it against this test app in PHP to see which decompression methodology works.
<?php
$data = "Lorem ipsum shizzle ma nizle";
// try all the compression algorithms and out the results in Hex format
echo "\n\n\n";
for($i=-1;$i<=9;$i++)
echo chunk_split(strtoupper(bin2hex(gzcompress($data,$i))),2," ") . PHP_EOL ;
echo "\n\n";
for($i=-1;$i<=9;$i++)
echo chunk_split(strtoupper(bin2hex(gzdeflate($data,$i))),2," ") . PHP_EOL ;
echo "\n\n";
for($i=-1;$i<=9;$i++)
echo chunk_split(strtoupper(bin2hex(gzencode($data,$i,FORCE_GZIP))),2," ") . PHP_EOL;
echo "\n\n";
for($i=-1;$i<=9;$i++)
echo chunk_split(strtoupper(bin2hex(gzencode($data,$i,FORCE_DEFLATE))),2," ") . PHP_EOL;
echo "\n\n";
// add the Base64 encoded text from the RabbitMQ plugin
$data = "H4sIAAAAAAAAAPPJL0rNVcgsKC7NVSjOyKyqyklVyE1UyMsEMgCX3v4lHAAAAA==";
$data = base64_decode($data);
// output the binary version of the compressed string in Hex format
echo chunk_split(strtoupper(bin2hex($data)),2," ") . PHP_EOL ;
// match the HEX string to the samples from above as there may be an offset that you need to deal with
// finally see which of the decompression methods work
echo gzuncompress($data)."\n";
echo gzinflate($data)."\n";
echo gzdecode($data)."\n";
// Double check that you have the correct one
$data = "Lorem ipsum shizzle ma nizle";
echo chunk_split(strtoupper(bin2hex(gzencode($data,9,FORCE_GZIP))),2," ") . PHP_EOL;
$data = gzencode($data,9,FORCE_GZIP);
echo gzdecode($data)."\n";
Thanks
Looks like it is just using gzip compression. If that's the case, take a look at:
http://developer.android.com/reference/java/util/zip/GZIPInputStream.html
If that isn't exactly the compression algorithm being used, there are a few more built in algorithms you can use as needed:
http://developer.android.com/reference/java/util/zip/package-summary.html
I have looked at most samples of code based on this issue on stack overflow but I still cant get the request to work. I keep getting this error:
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
Here is my code:
$access_key = "ACCESS_KEY";
$associateTag = "AOSSOCIATE_TAG";
$secretkey = "SECRET_KEY";
$keywords = "harry%20potter";
$timestamp = gmdate("Y-m-d\TH:i:s\Z");
$operation = "AWSECommerceService";
function createSignature($operation,$timestamp,$secretkey){
$the_string=$operation.$timestamp;
return base64_encode(hash_hmac("sha256",$the_string,$secretkey,true));
}
$signature = createSignature ($operation,$timestamp,$secretkey);
$APIcall =
"http://ecs.amazonaws.com/onca/xml?".
"AWSAccessKeyId=$access_key&".
"AssociateTag=$associateTag&".
"BrowseNode=1000&".
"ItemPage=1&".
"Keywords=$keywords&".
"Operation=ItemSearch&".
"ResponseGroup=Medium&".
"SearchIndex=Books&".
"Service=AWSECommerceService&".
"Timestamp=$timestamp&".
"Version=2011-08-01&".
"Signature=$signature";
$response = simplexml_load_file($APIcall);
Can anyone help?
I had this issue long time and it worked for me with this code :
require_once 'Crypt/HMAC.php';
require_once 'HTTP/Request.php';
$keyId = "adasdasd";
$secretKey = "asdasdasdasdasd+";
function hex2b64($str) {
$raw = '';
for ($i=0; $i < strlen($str); $i+=2) {
$raw .= chr(hexdec(substr($str, $i, 2)));
}
return base64_encode($raw);
}
function constructSig($str) {
global $secretKey;
$str = utf8_encode($str);
$secretKey = utf8_encode($secretKey);
$hasher =& new Crypt_HMAC($secretKey, "sha1");
$signature = hex2b64($hasher->hash($str));
return ($signature);
}
$expire = time()+1000;
$resource = "/demo/files/clouds.jpg";
$date = gmdate("D, d M Y G:i:s T");
$mime = "image/jpeg";
$stringToSign = "PUT\n";
$stringToSign .= "\n";
$stringToSign .= "$mime\n";
$stringToSign .= "$date\n";
$stringToSign .= $resource;
$req =& new HTTP_Request("http://nameofmine.s3.amazonaws.com/files/clouds.jpg");
$req->setMethod("PUT");
$req->addHeader("Date",$date);
$req->addHeader("Authorization", "AWS " . $keyId . ":" . constructSig($stringToSign));
$req->addHeader("Content-Type",$mime);
$req->setBody(file_get_contents($file_path));
$req->sendRequest();
$responseCode = $req->getResponseCode();
$responseString = $req->getResponseBody();
echo $responseCode;
As you see you have to use Crypto, HTTP pear plugins
The function seems ok (it is the same as the one used in amazon AWS SDK) so make sure that there is no whitespace in front or after the copied key.
When I typed in my credentials by hand, I got the same error a couple of times.
Then I tried Console for Windows so I could copy/paste my credentials. This removed the error message. Either I sucked at typing, or sucked at reading.
Long story short: Don't type by hand, copy and past credentials to avoid typos.
EDIT:
My problem was when trying to add my credentials via EB CLIx3.
So Chrome 14 has implemented hybi10 version of websockets. I have a in house program that our company uses via chrome that uses websockets which is broken with this change.
Has anyone been successful framing the data using a php server? I am able to get the new handshake to work but I can't seem to figure out the framing. There is a python example here https://github.com/kanaka/websockify/blob/master/websocket.py#L233 but I am having a difficult time converting this to php, anyone have a suggestion?
I should mention that the function in question on the python example is decode_hybi().
i just completed a class wich makes the PHP-Websocket-Server of Nico Kaiser (https://github.com/nicokaiser/php-websocket) capable of handling hybi-10 frames and handshake. You can download the new class here: http://lemmingzshadow.net/386/php-websocket-serverclient-nach-draft-hybi-10/ (Connection.php)
This code assumes no errors or malformed frames and is based on this answer - How to (de)construct data frames in WebSockets hybi 08+?.
This code is very basic and is far from a complete solution. It works for my purposes (which are pretty basic). Hopefully it is of use to others.
function handle_data($data){
$bytes = $data;
$data_length = "";
$mask = "";
$coded_data = "" ;
$decoded_data = "";
$data_length = $bytes[1] & 127;
if($data_length === 126){
$mask = substr($bytes, 4, 8);
$coded_data = substr($bytes, 8);
}else if($data_length === 127){
$mask = substr($bytes, 10, 14);
$coded_data = substr($bytes, 14);
}else{
$mask = substr($bytes, 2, 6);
$coded_data = substr($bytes, 6);
}
for($i=0;$i<strlen($coded_data);$i++){
$decoded_data .= $coded_data[$i] ^ $mask[$i%4];
}
$this->log("Server Received->".$decoded_data);
return true;
}
Here is the code to send data back. Again this is pretty basic, it assumes you are sending a single text frame. No continuation frames etc. No error checking either. Hopefully others find it useful.
public function send($data)
{
$frame = Array();
$encoded = "";
$frame[0] = 0x81;
$data_length = strlen($data);
if($data_length <= 125){
$frame[1] = $data_length;
}else{
$frame[1] = 126;
$frame[2] = $data_length >> 8;
$frame[3] = $data_length & 0xFF;
}
for($i=0;$i<sizeof($frame);$i++){
$encoded .= chr($frame[$i]);
}
$encoded .= $data;
write_to_socket($this->socket, $encoded);
return true;
}