A little over a month ago, somebody posted this question to the Flexcoders mailing list asking about encrypting SWF’s to prevent them from being “captured” by applications or individuals. The solution is fairly simple, “encrypt the SWF!” But how would the Flash player handle that you might ask? Let’s find out.
Here’s the quick summary of how everything is going to work:
- Encrypt the real SWF using a standalone application, or integrate encryption into a web service.
- Create a wrapper SWF that loads the encrypted SWF from the server using the same symmetric key and initialization vector.
- Upload the SWF’s to your server as usual.
- Sit relaxed knowing nobody can intercept your SWFs.
As can be seen in the above steps, the wrapper SWF is loaded by the Flash Player, so it doesn’t have to do anything special and everything is basically transparent to the user.
Now let’s go into a bit more background on encryption and how this will work.
Most modern encryption is based on one of two different algorithms, symmetric key algorithms or asymmetric key algorithms.
In symmetric key algorithms, both the sender and the receiver use the same key. In other words, the same key is used to encrypt the message as is used to decrypt the message. Thus, if anybody can figure out what that shared key is, and obtains a copy of the encrypted data, they can then decrypt that data.
Asymmetric key algorithms use a public key and a private key. Both the sender and the receiver usually have different public and private keys. Let’s say that John and Tom decide they want to send encrypted messages back and forth. John then creates a public and a private key and gives his public key to Tom. Similarly, Tom creates a different public key and private key and gives his public key to John. To send an encrypted message to Tom, John only needs to use John’s public key to encrypt his message, after which it can be sent to John. Then John, using his private key (which only he has a copy of), can decrypt the message to see what John had to say about how great a conference they put on.
As it turns out, symmetric keys are better for transmitting a lot of information, so that’s the approach that I’ll take. Specifically, I’ll use the Advanced Encryption Standard (AES) algorithm which is a combination block/stream cipher. I’ll use it to operate on a stream of bits (the SWF we will be encrypting and decrypting), but internally it’s operates on one block at a time, thus requiring a padding algorithm.
Since AES operates on blocks of streaming data, there has to be at least one blocks worth of data to operate on, thus, at the end of the SWF we usually will not have exactly the right number of bits, so we will pad the real bits with a few extra bits using a known padding algorithm. This also means our SWF might end up a few bytes larger.
Encrypt Your SWF
The first thing you’ll need is a “real” SWF that we can encrypt. The one that I’ll use for this example has a red background with the text “Hello Encrypted SWF World!” on it as can be seen below, or you can try it out here:
Now that we have a real application, we need to encrypt it. To try this out yourself, you’ll need this Java Program to encrypt your SWF. You simply give it a few arguments on the command line as follows:
# compile the .java file (only necessary the first time javac AesEncrypter.java # NOTE: The following should be on one command line, the backslashes escape # the newline allowing it to be on multiple lines. java AesEncrypter 01020304050708090a0b0c0d0e0f0001 \ 01020304050708090a0b0c0d0e0f0001 \ SampleSwf.swf \ SampleSwf.eswf
And the output will look something like the following:
key:01020304050708090a0b0c0d0e0f0001 Bytes:32 iv:01020304050708090a0b0c0d0e0f0001 Bytes:32 Cipher mode: AES/CBC/PKCS5Padding Name:SampleSwf.eswf and size: 152480
Other tools besides my Java program can be used for the AES encryption, as long as the encryption and padding algorithms match up, it doesn’t matter which program does the encryption. I have a C# program that could easily be adapted to do the same thing. (The AES algorithm is actually the Rijndael algorithm with a few restrictions applied, so it’s more popular than some people think.)
On the ActionScript side, I must note that the EncSwfLoader requires the awesome as3crypto libraries. Without such a good encryption library for Flex/Actionscript, this wouldn’t be possible! I just grabbed the swc of the as3crypto site and everything worked exactly as expected.
Create a Wrapper SWF
Now that are SWF has been encrypted, we need a wrapper that will load the encrypted SWF, decrypt it, and display it. Let’s take a look at some code. First, we want to be able to load a encrypted SWF just as if it were a regular SWF, so I’ll subclass SWFLoader. It’s usage follows:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:comp="com.sophware.controls.*" layout="vertical" > <comp:EncSwfLoader source="http://blogs.soph-ware.com/posted-content/files/sampleswf/SampleSwf.eswf" hexKey="01020304050708090a0b0c0d0e0f0001" hexIv="01020304050708090a0b0c0d0e0f0001" /> </mx:Application>
Now that’s pretty simple. I just generated a not-quite random 32 bytes and placed them (in hex form) in the
hexIv properties of the
EncSwfLoader. As long as nobody finds out what the key is, they won’t be able to break the encryption. The
hexIv is the initialization vector, also in hex form. Although this need not be kept secret, at might as well be.
Upload the SWF
For this example, I assume you know how to do that. My examples are here:
Sit back and relax!
Now how safe is the encryption being used above? The default encryption type is AES using a CBC mode. AES is certified for government Top Secret data. In other words, it’s pretty safe. The only danger is that someone downloads the wrapper SWF, decompiles it, discovers the encryption key, intercepts the encrypted SWF being downloaded, and then uses some other program to decrypt the SWF, assuming of course that they grabbed the initialization vector at the same time they were looking at the SWF. Oh, and a couple of other little details, they would have to know it’s using CBC mode and discover the padding algorithm. So, in other words, it’s pretty safe. Yes, it’s still possible for somebody to figure out what was sent, but they would really want to know and it would be non-trivial and require extra tools. Even though I know how… I don’t think I would ever bother!
The end result, will look like a normal SWF application. Here’s a screenshot, or take a look at the real application here:
So what are the downsides of this?
- You have to encrypt your SWF
- It takes some processing time to decrypt the SWF
- The encrypted SWF will usually be larger by up to 31 bytes
- Nobody can “borrow” your SWF and thereby help make you famous!
A few of you might be thinking, but that’s not good enough — I absolutely can’t have anybody intercept or decrypt my SWF, what do I do? The short answer is — it’s possible. The long answer is — perhaps I’ll discuss it in some other blog post :).
For interested parties, here are some relevant links on Wikipedia. Also note that I’ve been a little lax about terminology, so please forgive me if that’s bothered you:
NOTE: Following text added Apr 18, 2008 after comments #1 through #3 were posted:
Purpose and Preventative Target
Cédric Tabin and others have asked about the purpose of this. To the question, “Isn’t this completely a waste of time?”, I answer “It depends!”
When Ritesh Yadav posted his original question, I saw the main issue as being that anybody with some reasonable computer or HTML experience could easily figure out how to save the SWF to disk, allowing them to use that SWF in an environment where it wasn’t originally intended. Perhaps that environment is one where no adds are served, and therefore, the author is unable to make money based on the work that they did.
If the purpose is to prevent somebody from saving the SWF to disk, this works great and does exactly what it’s supposed to do. As such, it is not a waste of time.
If, however, the purpose is to prevent somebody determined from getting the code to your SWF, which is basically impossible, then this might be a waste of time and will only slow the a capable hacker down requiring an extra two or three steps. Any determined and capable hacker can decompile or otherwise reverse engineer just about anything, which includes this process.
One way in which a hacker might break this procedure follows:
- Decompile the wrapper SWF
- Retrieve the shared private key and the initialization vector
- Intercept the real SWF as it is downloaded
- Use the exact same encryption algorithm and its parameters to decrypt the SWF
- Decrypt the real SWF
In private correspondence with Cédric Tabin, he pointed out another possible point of attack:
- Debug the wrapper SWF, breakpointing at the location where the decryption has been done.
- Grab the stream of bytes that are being sent to the SWFLoader
- Write the bytes to disk or otherwise inspect the real SWF
I’m not exactly sure how the latter may work, never having tried to debug a release SWF, but I could certainly do such a thing with C or C++, so it’s definitely a feasable approach. Furthermore, the actual Flex/SWF debugger could by bypassed by using a C/C++ debugger with the Flash Player directly.
This approach is not intended to make it impossible for somebody to get to the real SWF, only to make it “impossible” for an average or better than average computer user (e.g. not a hacker) to grab the SWF. This approach is also not intended to be complete. By adding TLS and/or random key and iv generation to the mix, which would require a service on the server side, it can be made much more difficult for a hacker to get at the real SWF.
I hope this clarifies. Thanks for your comments and feedback.