February 4, 2008 7:25 PM
Ted Patrick had posted about the distinction between loader.load()
and
loader.loadBytes()
where he also mentions that the latter can be used
to load an obfuscated / encrypted SWF. I've implemented exactly that
in an AIR application using AS3 Crypto Framework to handle the
encryption / decryption just to figure out how easy it would be to do
it and what it's security implications might be. There's also a
companion Flex application that uses loadBytes()
but only uses a
simple substitution cipher to hide the actual SWF data.
The concept is pretty straightforward: Your SWF is encrypted or
obfuscated so that someone else cannot just grab the SWF and decompile
it. Your application loads the SWF in it's memory, performs some
computation on it's contents to get back the actual SWF1 and then load
it using loader.loadBytes()
.
However, the whole thing will crumble if the key to decrypting the SWF is embedded in your un-encrypted SWF (which anybody can decompile).
Flex Example for loadBytes
This is a lightweight example highlighting the capability of
loadBytes()
. If you hit any of the "Get" buttons, it performs a
URLLoader
request to get a SWF. Each byte of the SWF has been
incremented by 13 (ROT13) to fool SWF decompilers. Only the "Get SWF
and Decrypt" button will reverse the substitution cipher to get the
proper SWF data. This SWF is then injected into the current
application and it's content becomes visible below the
buttons.
View Flex loadBytes Example (View Source Enabled)
Hitting the first button will throw an error because the SWF data is not proper. The second button should load the SWF content below the buttons.
Note: Simple substitution cipher techniques such as ROT 13 can be easily broken.
AIR Version using AS3 Crypto Framework
The following AIR application uses the AS3 Crypto Framework to perform
AES 256 bit encryption and decryption. The password string supplied
during encryption is the key for decryption. Without the correct
password string, the output SWF will never match the actual SWF. The
application also has a "Load SWF" button that injects an SWF using
loadBytes()
. This injected SWF will be running with full privileges
and access to all AIR APIs (i.e, it is in the AIR application security
context).
AIREncryptSWF for AIR Beta 3 (View Source Enabled) - Download
Note: When you hit encrypt or decrypt in the AIR application, the UI may not update2 for some time. Please wait patiently till the application becomes responsive again.
Ideally, you could also do a MD5 or SHA-1 hash on the contents of the
actual SWF and compare this hash with the hash obtained after
decrypting the SWF. Only if the hashes match should you call
loadBytes()
.
The existence of loadBytes()
gives us an option to introduce a level
of difficulty for some random dude while trying to grab your SWF and
view it's code. However, the security of the system depends upon even
the smallest aspect of it's implementation and like in all client-side
technologies, complete security may be impossible to achieve. Ideally,
such techniques should be thought of only as a precautionary measure
and not as a complete fool proof solution.
[1] We're assuming it's not very easy to get the contents of the
decrypted SWF from flash player's memory.
[2] Sadly, distribution of calls to the crypto framework is not
supported via callLater()
or by listening to an enter frame event.