I converting a swf project to php, I'm not good with actionscript much so I need help to convert functions Hex.toArray, Hex.fromString, Base64.encodeByteArray in actionscript3 to php.
ActionScript
public function spawn(query_str:String, key:String, token:String = "") : String{
var tmp1:* = key + "&" + token;
var tmp2:* = Crypto.getHMAC("sha1");
var tmp3:* = Hex.toArray(Hex.fromString(tmp1));
var tmp4:* = Hex.toArray(Hex.fromString(query_str));
var tmp5:* = tmp2.compute(tmp3, tmp4);
return Base64.encodeByteArray(tmp5);
}
This is PHP function I converted, but results of two functions are different
function spawn($query_str, $key, $token = ''){
$tmp1 = $key . "&" . $token;
$tmp3 = pack("H*" , bin2hex($tmp1));
$tmp4 = pack("H*" , bin2hex($query_str));
$tmp5 = hash_hmac('sha1', $tmp4, $tmp3);
return base64_encode($tmp5);
}
You can use bin2hex in PHP, and pack("H*", ...) in lieu of hex2bin. The primarily used base64 functions in PHP are base64_encode and base64_decode.
Arrays are seldomly used for data representation; binary data is generally kept in strings in PHP. But if really needed $array = array_map("ord", str_split($string)); would do.
Related
I'm trying to convert a combined string into a ASCII Byte Array to pass it into a server as an http header. Been trying numerous ways like unpack, splitting strings and doing a loop to convert each. But the server I am passing the converted string still ignores it. Not so much of a support from the API I'm using so maybe anyone here can help if I'm doing anything wrong.
$billerId = '9999986379225246';
$authToken = '16dfe8d7-889b-4380-925f-9c2c6ea4d930';
$auth = $billerId . ':' . $authToken;
//this results in error
$auth_key_byte_array = unpack("H*",$auth);
//this also results in error
$auth_key_byte_array = hash_hmac("sha256", $auth, false);
//even tried a loop function
function create_byte_array($string){
$array = array();
foreach(str_split($string) as $char){
array_push($array, sprintf("%02X", ord($char)));
}
return implode('', $array);
}
$auth_key_byte_array = create_byte_array($auth);
I've got a javascript function that creates a Time Based One Time Password (TOTP).
Now I have to create that same TOTP at the server, using PHP.
I coded the same logic in PHP as in my javascript function.
For convenience, I created a javascript fiddle, and a PHP fiddle. So you can compare the codes and see the outputs.
Javascript version: (fiddle: https://jsfiddle.net/rrfk4ey9/1/)
var TOTP = function() {
var dec2hex = function(s) {
return (s < 15.5 ? "0" : "") + Math.round(s).toString(16);
};
var hex2dec = function(s) {
return parseInt(s, 16);
};
var leftpad = function(s, l, p) {
if(l + 1 >= s.length) {
s = Array(l + 1 - s.length).join(p) + s;
}
return s;
};
this.getOTP = function(secret) {
try {
var epoch = Math.round(new Date().getTime() / 1000.0);
// For testing, we take a fixed time. (same as in PHP version).
var time = "0000000002f3e3c9";//leftpad(dec2hex(Math.floor(epoch / 30)), 16, "0");
document.getElementById("key").innerHTML = secret;
document.getElementById("time").innerHTML = time;
var hmacObj = new jsSHA(time, "HEX");
var hmac = hmacObj.getHMAC(secret, "TEXT", "SHA-1", "HEX");
document.getElementById("hmac-out").innerHTML = hmac;
var offset = hex2dec(hmac.substring(hmac.length - 1));
var otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec("7fffffff")) + "";
otp = (otp).substr(otp.length - 6, 6);
} catch (error) {
alert("Error: " + error);
throw error;
}
return otp;
};
};
var totpObj = new TOTP();
document.getElementById("result").innerHTML = totpObj.getOTP("someSecret");
output {
font-family: monospace;
white-space: pre;
}
#result {
color: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsSHA/1.6.0/sha.js"></script>
<body>
<aside>This snippet uses external library <b>jsSHA</b> version <b>1.6.0</b></aside>
<hr />
<output>
<div>Key: <b id="key"></b></div>
<div>Time: <b id="time"></b></div>
<div>HMAC: <b id="hmac-out"></b></div>
<div>code: <b id="result"></b></div>
</output>
</body>
PHP version: (http://ideone.com/s0Bwqu)
<?php
function leftPad($in, $len, $str) {
return str_pad($in, $len, $str, STR_PAD_LEFT);
}
$key = "someSecret";
$epoch = time();
// For testing, we take a fixed time. (same as in JS version).
$time = "0000000002f3e3c9";//leftPad(dechex(floor($epoch / 30)), 16, "0");
echo "Key: " . $key . "\n";
echo "Time: " . $time . "\n";
$hmac = hash_hmac("sha1", $time, $key, false);
echo "HMAC: " . $hmac . "\n";
$offset = hexdec(substr($hmac, strlen($hmac) - 1));
$otp = (hexdec(substr($hmac, $offset * 2, 8)) & hexdec("7fffffff")) . "";
$otp = substr($otp, strlen($otp) - 6, 6);
echo "Code: " . $otp . "\n";
?>
This yields:
Key: someSecret
Time: 0000000002f3e3c9
HMAC: 5dcab54740bdca71e706c7e38a5c59fec3cb9c1a
Code: 094428
Note that in both versions (JS and PHP) the time and key are the same.
The HMAC differs, and so in my understanding here starts the problem.
The javascript version is the one I created first, and is proven to be working correctly.
I am pretty sure the problem is caused by the behavior of the jsSHA library.
So I put some things in perspective:
jsSHA Library takes time in HEX format. Also in PHP the time is in HEX format when put in the hash_hmac function.
secret (the key) is in TEXT format put in jsSHA. Also in PHP.
Actually, the point is getting the same result in PHP as the jsSHA library in javascript.
I'm sure I'm missing something. I have long been trying, and even Google does't know the answer.
You tell that jsSHA library that the input is a hexadecimal string here:
var hmacObj = new jsSHA(time, "HEX");
But you're not doing anything equivalent on the PHP side before/inside the hash_hmac() call. That means that jsSHA gets raw binary data, while PHP's hash_hmac() gets the literal string of "0000000002f3e3c9".
Naturally, that won't produce the same result.
Apply hex2bin() to $time before passing it to hash_hmac().
everyone!
I have some PHP code to sign some text and it works fine. I need to have equivalent of this code on actionscript 3. I need your help.
$privateKeyPath = "private.key";
$message = "hello";
$privateKey = file_get_contents($privateKeyPath);
openssl_sign($message, $signature, $privateKey);
echo base64_encode($signature);
In AS3 I using as3crypto library to make sign:
private function readPrivateKey():String {
var f:File = new File("/Users/ivan/Desktop/private.key");
var fs:FileStream = new FileStream();
fs.open(f,FileMode.READ);
var key:String = fs.readUTFBytes(fs.bytesAvailable);
fs.close();
return key;
}
private function getSign():void {
var message:String = "hello";
var privateKey:String = readPrivateKey();
var srcBA:ByteArray = new ByteArray();
var resultBA:ByteArray = new ByteArray();
var rsaKey:RSAKey;
var base64encoder:Base64Encoder = new Base64Encoder();
srcBA.writeUTFBytes(message);
rsaKey = PEM.readRSAPrivateKey(privateKey);
rsaKey.sign(srcBA, resultBA, srcBA.length);
b64encoder.encodeBytes(resultBA);
trace(b64encoder.toString());
}
I have same private key file. I expect that the output values are equals. But these values are different =(
What am I doing wrong?
UPDATE: I tried to verify my encoded base64 string using public key and verify method - everything is ok inside Actionscript.
Example:
var text:String = "hello";
var srcBA:ByteArray;
var desBA:ByteArray;
var rsaKey:RSAKey;
var encodedB64:String;
// ENCODING
srcBA = new ByteArray();
srcBA.writeUTFBytes(text);
desBA = new ByteArray();
rsaKey = PEM.readRSAPrivateKey( readPrivateKey() );
rsaKey.sign(srcBA, desBA, srcBA.length);
encodedB64 = Base64.encodeByteArray(desBA);
trace("Original: " + text);
trace("Encoded: " + encodedB64 );
// DECODING
var srcBA2:ByteArray = new ByteArray();
var desBA2:ByteArray = new ByteArray();
var rsaKey2:RSAKey = PEM.readRSAPublicKey( readPublicKey() );
srcBA2 = Base64.decodeToByteArray( encodedB64 );
rsaKey2.verify(srcBA2, desBA2, srcBA2.length);
trace("Decoded: " + desBA2.toString() );
My original text and decoded value are equals. So, I conclude that AS3 signing methods are different than PHP.
Is anyone have idea to make it equals?
Thanks.
Maybe it's late answer, but anyway...
AS3 works fine in your second code, PHP needs some tweaks, like this:
$privateKeyPath = "private.key";
$message = "hello";
$privateKey = openssl_pkey_get_private(file_get_contents($privateKeyPath));
openssl_private_encrypt($message, $signature, $privateKey);
echo base64_encode($signature);
I just checked with key genereted on this site:
http://www.selfsignedcertificate.com/ and everything works fine, I'm getting similar results in both PHP and AS3 versions.
I'm working on an RSA sign() function for generating a signed URL for private streaming. I was testing on PHP code, but I want to re-code that in Flex. Here is the part of PHP code:
function getCannedPolicy($resource, $expires, $key, $privatekeyfile){
$priv_key = file_get_contents($privatekeyfile);
$pkeyid = openssl_get_privatekey($priv_key);
$policy_str = '{"Statement":[{"Resource":"'.$resource.'","Condition":{"DateLessThan":{"AWS:EpochTime":'.$expires.'}}}]}';
$policy_str = trim( preg_replace( '/\s+/', '', $policy_str ) );
$res = openssl_sign($policy_str, $signature, $pkeyid, OPENSSL_ALGO_SHA1);
$signature_base64 = (base64_encode($signature));
$repl = array('+' => '-','=' => '_','/' => '~');
$signature_base64 = strtr($signature_base64,$repl);
$url = $resource . '?Expires='.$expires. '&Signature=' . $signature_base64 . '&Key-Pair-Id='. $key;
return $url;
}
I write the same function in Flex. Here is the code:
private function getCannedPolicy(resource:String, expires:uint, key:String, privatekey:String):String{
var unsigned:String = '{"Statement":[{"Resource":"' +resource+ '","Condition":{"DateLessThan":{"AWS:EpochTime":' +expires+ '}}}]}';
var signed:String = '';
var signature:String = '';
var regex:RegExp = /\s+/g;
unsigned = unsigned.replace(regex,'');
var src:ByteArray = new ByteArray();
src.writeUTFBytes(unsigned);
var dst:ByteArray = new ByteArray();
var hash:SHA1 = new SHA1();
src = hash.hash(src);
var rsa:RSAKey = PEM.readRSAPrivateKey(privatekey);
trace(rsa.dump());
rsa.sign(src, dst, src.length);
dst.position = 0;
signature = Base64.encodeByteArray(dst);
signature = signature.split("+").join("-");
signature = signature.split("=").join("_");
signature = signature.split("\/").join("~");
signed = resource+'?Expires=' +expires+ '&Signature=' +signature+ '&Key-Pair-Id=' +key;
return signed;
}
The outputs from the two functions (the PHP and the Flex) are the same format. But, when I'm using the signed URL from the Flex function, the stream not work.
The alternative I'm using for openssl_sign() php function is sign() function from as3crypto library. Maybe here is the problem? Maybe the encryption is different.
Unfortunately, the as3crypto's RSAKey.sign() is not the same function as php's openssl_sign(). Their outputs are different signatures. For that reason I decide to call remote php function to generated my signature. It works now!
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.