Multipass login to assistly.com with as3crypto - actionscript-3

I'm trying to automatically login my users into assistly.com with their multipass login as described here: http://dev.assistly.com/docs/portal/multipass
I have tried to convert their code examples ( https://github.com/assistly/multipass-examples) to Actionscript using as3crypto, obviously without success.
Here's what I have:
package
{
import com.adobe.crypto.SHA1;
import com.adobe.serialization.json.JSON;
import com.hurlant.crypto.*
import com.hurlant.util.Base64;
import flash.utils.ByteArray;
public class AssistlySingleSignOn
{
protected static var API_SITE_KEY:String = "YOUR SITE KEY"
protected static var MULTIPASS_KEY:String = "YOUR MULTIPASS API KEY"
public function AssistlySingleSignOn()
{
}
public static function generateMultipass(uid:String, username:String, email:String):String
{
var o:Object = {};
o.uid = uid;
o.expires = "2012-12-29T10:25:28-08:00";
o.customer_email = email;
o.customer_name = username;
var salted:String = API_SITE_KEY + MULTIPASS_KEY;
var hash:String = SHA1.hash(salted);
var saltedHash:String = hash.substr(0, 16);
var iv:String = "OpenSSL for Ruby";
var ivByteArray:ByteArray = new ByteArray();
ivByteArray.writeUTFBytes(iv);
var key:ByteArray = new ByteArray();
key.writeUTFBytes(saltedHash);
key.position = 0;
var json:String = JSON.encode(o);
var jsonByteArray:ByteArray = new ByteArray();
jsonByteArray.writeUTFBytes(json);
var padding:IPad = new PKCS5(16);
ivByteArray.position = 0;
key.position = 0;
var cyphered:CBCMode = Crypto.getCipher("aes-128-cbc", key, padding) as CBCMode;
jsonByteArray.position = 0;
cyphered.IV = ivByteArray;
cyphered.encrypt(jsonByteArray);
jsonByteArray.position = 0;
var base64:String = Base64.encode(jsonByteArray.readUTFBytes(jsonByteArray.length));
/*Convert to a URL safe string by performing the following
Remove any newlines
Remove trailing equal (=) characters
Change any plus (+) characters to dashes (-)
Change any slashes (/) characters to underscores (_)*/
base64 = base64.replace(/\n/g, "");
base64 = base64.replace(/=/g, "");
base64 = base64.replace(/+/g, "-");
base64 = base64.replace(/\//g, "_");
return base64;
}
}
}
I'm assuming that I'm doing something wrong with the IV stuff or the padding, because I don't quite understand it ;-)

You might want to use a different crypto class, or modify the as3crypto one. I know there are inconsistencies in the SHA1 function vs. the PHP sha1 function. See this:
sha1 hash from as3crypto differs from the one made with PHP
This could be making your values invalid. My recommendation would be to trace out all your data as it's being calculated and run it against the same things in PHP or another of the examples in github. See where the data diverges. I'm betting it's going to be issues relating to AS3Crypto.

Related

Firebase "MD5" & BloddyCrytpo's dont match

I'm trying to do a check to see if the user has a local file. If the user does, I get bloodycrypto to make a md5 out of it. Then I compare the two values. One from the firebase file's metadata and the other from the byte array of the file digested. They never match. Does Firebase do something different when trying to generate the md5 of a file I upload?
private function handleMetaSuccess(e:StorageReferenceEvent):void
{
trace("Meta succes for reference:" + this.name);
storageMetaData = e.metadata;
trace("reading file.");
fileBA = new ByteArray();
var fs:FileStream = new FileStream();
fs.open(Definitions.CACHE_DIRECTORY.resolvePath(name + ".jpg"), FileMode.READ)
fs.readBytes(fileBA);
fs.close();
var byteHash:String = MD5.hashBytes(fileBA)
trace("Local hash = " + byteHash); //93b885adfe0da089cdf634904fd59f71
trace("Network hash = " + storageMetaData.md5Hash); //bo7XPotC+T5wmAcpagnXBw==
if (byteHash != storageMetaData.md5Hash)
{
trace("Not equal. Getting file."); //Always happens
getFile();
}
else
{
loadFile();
}
}
Upon closer inspetion (thanks to Organis) firebase doesn't return a proper MD5. What is it? In my storage consol I don't see an md5 property, so is this autogenerated? The files were uploaded through my rest API based off phantom's guide.
Update: Following Organis' comment about the way Firebase handle's MD5s
var byteHash:ByteArray = new ByteArray();
byteHash.writeUTFBytes(MD5.hashBytes(fileBA));
var byteHashWithLength:ByteArray = new ByteArray();
byteHashWithLength.writeUTF(MD5.hashBytes(fileBA));
trace("Bytehash with length = " + Base64.encode(byteHashWithLength)); //ACAyMTMzYTdmYjczYTEzZDQ3ZDkzMTEyY2I1OWQyYTBmMg==
trace("Plain = " + Base64.encode(byteHash)); //OTNiODg1YWRmZTBkYTA4OWNkZjYzNDkwNGZkNTlmNzE=
trace("Storage md5 = " + storageMetaData.md5Hash); //UsoNl5sL1+aLiAhTOTBXyQ==
Trying to take the md5 I get and turn it into base64 results in consistent mismatching results. Is there an argument I am missing or applying incorrectly when I try to decode everything?
...So I would do something like
var storageHash:String = Base64.decode(storageMetaData.md5Hash).toString();
to follow your example right?
Try this code below to get your storageMetaData.md5Hash correctly decoded from Base64 :
Let me know result of trace("storage hash : " + storageHash); to check if you're getting an (expected) sequence of 32 hex values.
private function handleMetaSuccess(e:StorageReferenceEvent):void
{
trace("Meta succes for reference:" + this.name);
storageMetaData = e.metadata;
trace("reading file.");
fileBA = new ByteArray();
var fs:FileStream = new FileStream();
fs.open(Definitions.CACHE_DIRECTORY.resolvePath(name + ".jpg"), FileMode.READ)
fs.readBytes(fileBA);
fs.close();
var byteHash:String = MD5.hashBytes(fileBA); //Local hash
var ba_storageHash:ByteArray = new ByteArray();
ba_storageHash = Base64.decode(storageMetaData.md5Hash); //update ByteArray
var storageHash:String = bytesToHexString(ba_storageHash); //Hex values of bytes shown as String
trace("Network hash : " + storageMetaData.md5Hash); //bo7XPotC+T5wmAcpagnXBw==
trace("Local hash : " + byteHash); //93b885adfe0da089cdf634904fd59f71
trace("storage hash : " + storageHash); //what is result??
if (byteHash != storageHash)
{
trace("Not equal. Getting file."); //Always happens
getFile();
}
else
{
loadFile();
}
}
// # Byte values (Hex) shown as (returned) String type
private function bytesToHexString(input:ByteArray) : String
{
var strOut:String = ""; var strRead:String = "";
input.position = 0;
var intBASize:uint = input.length;
for (var i:int = 0; i < intBASize; i++)
{
strRead = input.readUnsignedByte().toString(16);
if(strRead.length < 2) { strRead = "0" + strRead; } //# do padding
strOut += strRead ;
}
return strOut.toLowerCase(); //strOut.toUpperCase();
}

How to use AES-CBC 128-bit encryption in AS3?

I would like to encrypt a string in AS3 with AES-CBC 128-bit. How to do it?
Use AS3Crypto https://code.google.com/p/as3crypto/, here is the snippet:
//notice that decrKey and decrIV length must be 16 chars long! ex: 1234567890123456
private function encrypt(input:String,decrKey:String,decrIV:String):String
{
var inputBA:ByteArray=Hex.toArray(Hex.fromString(input));
var key:ByteArray = Hex.toArray(Hex.fromString(decrKey));
var pad:IPad = new NullPad();
var aes:ICipher = Crypto.getCipher("aes-cbc", key, pad);
var ivmode:IVMode = aes as IVMode;
ivmode.IV = Hex.toArray(Hex.fromString(decrIV));
aes.encrypt(inputBA);
return Base64.encodeByteArray( inputBA); //if not use Base64 encode, data would be just byteArray
}
Notice: this code is fully compatible ex: with PHP (or C#), here is decryption for it in PHP
//notice that $key and $iv length must be 16 chars long! ex: 1234567890123456
function decrypt($data,$key,$iv)
{
$decr= mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($data), MCRYPT_MODE_CBC, $iv);
return $decr;
}

Reverse engineering - Flash app

I have that code:
private function handleFlashVarsXmlLoaded(event:Event) : void
{
var secondsplit:String = null;
var item:Array = null;
var string:* = XML(String(event.target.data));
var notsplited:* = string.vars_CDATA; //what is .vars_CDATA?
var splitted:* = notsplitted.split("&");
var datacontainer:Object = {};
var index:Number = 0;
item = secondsplit.split("=");
datacontainer[item[0]] = item[1];
this.parseFlashVars(datacontainer); // go next
return;
}
That function is loaded when URLLoader is loaded.
I think that this function parse a XML file to string(fe. param1=arg1&param2=arg2), then split it by "&" and then by "=" and add data to datacontainer by
datacontainer["param1"] = "arg1"
But how should the XML file look like and what is string.vars_CDATA
I think, vars_CDATA is just a name of XML field, becourse variable named "string" is contains whole XML. So var "notsplited" contains a String-typed data of this field (I think so, becourse of the line "var splitted:* = notsplitted.split("&");", which splits String to Array).

Other ways of counting number of keywords in a complex string

I am reading a file which contains approx 1200 words in the following format:
words:a:/zenb:/fixx:/wew:/sina:/benb:/sixx:/hew:/bin
I need to find how many keywords are there in that text file, by keyword i mean:
zen fix we sin ben six he bin
Right now I am trying to do it with RegExp like this:
var s:String = "words:b:sa:/zenb:/fixx:/wew:/sina:/benb:/sixx:/hew:/bin";
var pattern:RegExp = /:/+/g;
var results:Array = s.match(pattern);
trace(results.length);
Its producing an error, since I am a beginner I really don't understand how this RegExp work , are there any alternate methods to get the same results?
Thanks
Your var pattern:RegExp = /:/+/g; has a syntax error, you skipped a backslash \ change this to :
var pattern:RegExp = /:\/+/g;
and it should work, Alternatively with this format you can use the String split method to get the total word count. Try this:
var s:String = "words:b:sa:/zenb:/fixx:/wew:/sina:/benb:/sixx:/hew:/bin";
var wordCount:Number = s.split(":/").length -1;
trace( wordCount );
Hope that works.
package
{
import flash.display.Sprite;
public class CountWordsExample extends Sprite
{
public function CountWordsExample()
{
super();
// 8 7 0
trace(countWords(
"words:b:sa:/zenb:/fixx:/wew:/sina:/benb:/sixx:/hew:/bin",
":/"),
countWords(
"words:b:sa:/:/fixx:/wew:/sina:/benb:/sixx:/hew:/bin",
":/"),
countWords(
"words:b:sa::zenb::fixx::wew::sina::benb::sixx::hew::bin",
":/"));
}
public static function countWords(words:String, delimiter:String,
countBlanks:Boolean = false):uint
{
var result:uint;
var wordPointer:int = -1;
var delimiterPointer:int;
var delimiterLength:uint = delimiter.length;
if (words.length >= delimiterLength)
{
do
{
delimiterPointer = wordPointer;
wordPointer = words.indexOf(
delimiter, wordPointer + delimiterLength);
if (countBlanks ||
// we moved by more characters, then the length of
// delimiter
wordPointer - delimiterLength > delimiterPointer)
result++;
}
while (wordPointer > -1)
}
return result;
}
}
}
Here's an example of how to count words without ever creating additional arrays or sub-strings of the original string. It also verifies that the words counted have at least one character length.

AS3 load variables from a txt file which has && formatting

I'm trying to load a txt file of variables into my AS3 project. The problem I have though seems to be down to the fact that the txt file (which is pre formatted and cannot be changed) is formatted using double amphersands... e.g.
&name=mark&
&address=here&
&tel=12345&
I'm using the following code to load the txt file
myLoader.addEventListener(Event.COMPLETE, onLoaded, false, 0, true);
myLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
urlRqSend = new URLRequest(addressToTxt.txt);
public function onLoaded(e:Event):void {
trace(myLoader.data);
}
Using URLLoaderDataFormat.VARIABLES generates the following error:
Error: Error #2101: The String passed to URLVariables.decode() must be a URL-encoded query string containing name/value pairs.
If I use URLLoaderDataFormat.TEXT I can load the data successfully but I'm not able (or don't know how to) access the variables.
Would anyone have any ideas or work arounds to this please.
Thanks,
Mark
I had that kind of problem some time ago.
I suggest you to load first as a text, remove those line breaks, the extra amphersands and parse manually:
var textVariables:String;
var objectVariables:Object = new Object();
...
myLoader.addEventListener(Event.COMPLETE, onLoaded, false, 0, true);
myLoader.dataFormat = URLLoaderDataFormat.TEXT;
urlRqSend = new URLRequest(addressToTxt.txt);
public function onLoaded(e:Event):void {
textVariables = myLoader.data;
textVariables = textVariables.split("\n").join("").split("\r").join(""); // removing line breaks
textVariables = textVariables.split("&&").join("&"); // removing extra amphersands
var params:Array = textVariables.split('&');
for(var i:int=0, index=-1; i < params.length; i++)
{
var keyValuePair:String = params[i];
if((index = keyValuePair.indexOf("=")) > 0)
{
var key:String = keyValuePair.substring(0,index);
var value:String = keyValuePair.substring(index+1);
objectVariables[key] = value;
trace("[", key ,"] = ", value);
}
}
}
I wrote that code directly here, I don't have any AS3 editor here, so, maybe you'll find errors.
If you have data in String and it has a structure just like you wrote, you can do a workaround:
dataInString = dataInString.split("\n").join("").split("\r").join(""); // removing EOL
dataInString = dataInString.slice(0,-1); // removing last "&"
dataInString = dataInString.slice(0,1); // removing first "&"
var array:Array = dataInString.split("&&");
var myVariables:Object = new Object();
for each(var item:String in array) {
var pair:Array = item.split("=");
myVariables[pair[0]] = pair[1];
}
That should make you an object with proper variables.