AS3 RSAKey.sign() != PHP openssl_sign() - php

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.

Related

PBKDF2-HMAC-SHA256 .NET vs PHP

I have this code from our old system in .NET, and I need to rewrite it in PHP.
try{
byte[] heslo = Encoding.UTF8.GetBytes(Pwd);
byte[] salt = Encoding.UTF8.GetBytes(String.Format("source={0}&owner={1}&usercode={2}&ts={3}", Source, Owner, UserCode, ts));
int iterations = 8;
byte[] output = null;
using (var hmac = new HMACSHA256()){
var df = new Pbkdf2(hmac, heslo, salt, iterations);
output = df.GetBytes(20);
token.Value = BitConverter.ToString(output).Replace("-", "").ToLowerInvariant();
}
}catch{
token = null;
}
return token;
}
I tried to use
openssl_pbkdf2( $password,$salt,20,8,"SHA256");
with the same values in both scripts but in php I'm getting different output, can anyone help me. Please

Different hashing results in Dart vs PHP code

I'm trying to get this working in flutter and i cant get the same outcome.
My php code prints a diffrent hash then my flutter code. Is it posible to do this in a flutter app?
i have tried to achieve this by running this flutter code. But after 5 hours of reading i gave up and created a stack overflow account.
import 'package:crypto/crypto.dart';
import 'dart:convert'; // for the utf8.encode method
import 'package:http/http.dart' as http;
void main() {
var api = 'https://app.repricer.nl';
var endpoint = '/api/v1/channels/all.json';
var method = 'GET';
var public_key = '';
var private_key = '';
var data = '';
var ms = (new DateTime.now()).millisecondsSinceEpoch;
var timestamp = ms / 1000;
var hash_string = public_key + '|' + method + '|' + endpoint + '|' + data + '|' + timestamp.toString();
var key = utf8.encode(private_key);
var bytes = utf8.encode(hash_string);
var hmacSha256 = new Hmac(sha512, key); // HMAC-SHA256
var digest = hmacSha256.convert(bytes);
print(digest);
}
This is the PHP code that i want to convert to flutter:
$api = 'https://app.repricer.nl';
$endpoint = '/api/v1/channels/all.json';
$method = 'GET';
$public_key = '';
$private_key = '';
// Generate the CURL headers to authenticate our request
$headers = generateHash($public_key, $private_key, $method, $endpoint, $data);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$api.$endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
curl_close($ch);
print_r($result);
function generateHash($public_key, $private_key, $method, $endpoint, $data)
{
$timestamp = date("U");
$hash_string = array($public_key,$method,$endpoint,$data,$timestamp);
$hash = hash_hmac('sha512',implode('|',$hash_string),$private_key);
print ($hash);
return array('X-Auth: '.$public_key, 'X-Hash: '.$hash, 'X-Date: '.$timestamp);
}
I expect the output is the same exept from the timestamp. But i ran it in the same second and it are 2 completly diffrent outcomes.
Your code is correct.
Small fix is just replacing:
ms / 1000 to (ms / 1000).toInt()
I don't see other flaw in Your code.
I've came to that answer after doing test run with constant timestamp parameter: 1572731120
PHP:
$timestamp = 1572731120; //date("U");
$hash_string = array($public_key,$method,$endpoint,$data,$timestamp);
$hash = hash_hmac('sha512',implode('|',$hash_string),$private_key);
Dart
var ms = (new DateTime.now()).millisecondsSinceEpoch;
var timestamp = 1572731120;//(ms / 1000).toInt();
var hash_string = public_key + '|' + method + '|' + endpoint + '|' + data + '|' + timestamp.toString();
var key = utf8.encode(private_key);
var bytes = utf8.encode(hash_string);
var hmacSha256 = new Hmac(sha512, key); // HMAC-SHA256
var digest = hmacSha256.convert(bytes);
which proves that results are equal:

NodeJS HMAC Hash Creation

I am trying to follow part of a tutorial for an API written in PHP. They show the following example:
$public = 'JkAFq7M47kLN0xVD';
$private = 'E6X9FyZvMFeJbqtq.IwjlTuR.MKDoicB';
$url = 'https://pterodactyl.local/api/admin/users';
$body = '';
$hmac = hash_hmac('sha256', $url . $body, $private, true);
return $public . '.' . base64_encode($hmac);
// Should return the string below:
//
// JkAFq7M47kLN0xVD.wgIxj+V8RHgIetcQg2lRM0PRSH/y5M21cPz9zVhfFaQ=
But my method doesn't return the proper value. Instead it returns the following:
JkAFq7M47kLN0xVD./RKZS3U2FKfEt7/tEks4vWwyS+89lL+k8aEGO8NJWuo=
Here is my code:
hmac = crypto.createHmac('sha256', private_key);
hmac.write(url+body);
hmac.end();
hash = hmac.read().toString('base64');
console.log(hash);
EDIT: I think the example they provided was invalid because as everyone is saying my code is almost identical and the PHP code outputs a different value then it said it should in the documentation.
ok so, i used this tool writephponline to run this php code:
$public = 'JkAFq7M47kLN0xVD';
$private = 'E6X9FyZvMFeJbqtq.IwjlTuR.MKDoicB';
$url = 'https://pterodactyl.local/api/admin/users';
$body = '';
$hmac = hash_hmac('sha256', $url . $body, $private, true);
echo $public . '.' . base64_encode($hmac);
and returns:
JkAFq7M47kLN0xVD./RKZS3U2FKfEt7/tEks4vWwyS+89lL+k8aEGO8NJWuo=
So i used that as a parameter, then i made a little nodejs script:
var crypto = require('crypto');
var public = 'JkAFq7M47kLN0xVD';
var private = 'E6X9FyZvMFeJbqtq.IwjlTuR.MKDoicB';
var url = 'https://pterodactyl.local/api/admin/users';
var body = '';
var hmac = crypto.createHmac('sha256', private).update(url+body).digest('base64');
console.log(public + '.' + hmac);
and returns:
JkAFq7M47kLN0xVD./RKZS3U2FKfEt7/tEks4vWwyS+89lL+k8aEGO8NJWuo=
Hope it helps.
I am prefer use crypto-js library of crypto standards. This library is keep maintaining.
const crypto = require('crypto-js')
const public = 'JkAFq7M47kLN0xVD'
const private = 'E6X9FyZvMFeJbqtq.IwjlTuR.MKDoicB'
const url = 'https://pterodactyl.local/api/admin/users'
const body = ''
const hmac = crypto.HmacSHA256(url + body, private).toString(crypto.enc.Base64)
console.log(public + '.' + hmac)
// Print value:
// JkAFq7M47kLN0xVD./RKZS3U2FKfEt7/tEks4vWwyS+89lL+k8aEGO8NJWuo=

PHP's $HTTP_RAW_POST_DATA in ASP

I'm updating a classic asp page with a flash app and I need to reproduce the PHP's $HTTP_RAW_POST_DATA function under vbscript (OR C# .NET since it's on IIS7 also). This is what I have so far but does not work. The browser just tells me that it can not display the image because of errors or corruption. Thanx in advance.
AS3 Code
vid_out = new Video();
vid_out.x = 0;
vid_out.y = 0;
vid_out.width = cam.width;
vid_out.height = cam.height;
vid_out.attachCamera(cam);
addChild(vid_out);
var bitmapData:BitmapData = new BitmapData(640, 480);
bitmapData.draw(vid_out);
var encoder:JPGEncoder = new JPGEncoder();
var byteArray:ByteArray = encoder.encode(bitmapData);
var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var jpgURLRequest:URLRequest = new URLRequest("/capture.asp?i=blah.jpg");
jpgURLRequest.requestHeaders.push(header);
jpgURLRequest.method = URLRequestMethod.POST;
jpgURLRequest.data = byteArray;
navigateToURL(jpgURLRequest, "_blank");
non-working vbscript code
Function RSBinaryToString(xBinary)
Dim Binary
If vartype(xBinary)=8 Then Binary = MultiByteToBinary(xBinary) Else Binary = xBinary
Dim RS, LBinary
Const adLongVarChar = 201
Set RS = CreateObject("ADODB.Recordset")
LBinary = LenB(Binary)
If LBinary>0 Then
RS.Fields.Append "mBinary", adLongVarChar, LBinary
RS.Open
RS.AddNew
RS("mBinary").AppendChunk Binary
RS.Update
RSBinaryToString = RS("mBinary")
Else
RSBinaryToString = ""
End If
End Function
photoname = trim(request.querystring("i"))
Dim ByteCount, BinRead
ByteCount = Request.TotalBytes
If ByteCount > 0 Then
BinRead = Request.BinaryRead(ByteCount)
Response.ContentType = "image/jpeg"
Response.AddHeader "Content-Disposition", "inline; filename=" & photoname
Response.BinaryWrite(RSBinaryToString(BinRead))
Response.End()
End If
'working vbscript code
I'm just using the actual folder path located on the server. You can user servermappath also.
photoname = trim(request.querystring("i"))
folder = "C:\some_folder\"
tofolder = folder & photoname
Dim BinaryData, ByteCount
ByteCount = Request.TotalBytes
BinaryData = Request.BinaryRead(ByteCount)
Set objADO = Server.CreateObject("ADODB.Stream")
objADO.Type = 1
objADO.Open
objADO.Write BinaryData
objADO.SaveToFile tofolder, 2
Set objADO = Nothing
See Request Object reference
Specifically, you will be interested in Request.TotalBytes property to get request body size and Request.BinaryRead method to read the request body.
Quote from MSDN:
VBScript
<%
Dim vntPostedData, lngCount
lngCount = Request.TotalBytes
vntPostedData = Request.BinaryRead(lngCount)
%>

RSA sign function problem

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!

Categories