Currently writing my own AMF TcpSocketServer. Everything works good so far i can send and recieve objects and i use some serialization/deserialization code. Now i started working on the encryption code and i am not so familiar with this stuff.
- I work with bytes , is DES-CBC a good way to encrypt this stuff? Or are there other more performant/secure ways to send my data? Note that performance is a must :).
- When i call: ReadAmf3Object with the decrypter specified i get an: InvalidOperationException thrown by my ReadAmf3Object function when i read out the first byte the Amf3TypeCode isn't specified ( they range from 0 to 16 i believe (Bool, String, Int, DateTime, etc) ). I got Typecodes varying from 97 to 254? Anyone knows whats going wrong? I think it has something to do with the encryption part. Since the deserializer works fine w/o the encryption. I am using the right padding/mode/key?
I used: http://code.google.com/p/as3crypto/ as as3 encryption/decryption library. And i wrote an Async tcp server with some abuse of开发者_Python百科 the threadpool ;)
Anyway here some code:
C# crypter initalization code
System.Security.Cryptography.DESCryptoServiceProvider crypter = new DESCryptoServiceProvider();
crypter.Padding = PaddingMode.Zeros;
crypter.Mode = CipherMode.CBC;
crypter.Key = Encoding.ASCII.GetBytes("TESTTEST");
AS3
private static var _KEY:ByteArray = Hex.toArray(Hex.fromString("TESTTEST"));
private static var _TYPE:String = "des-cbc";
public static function encrypt(array:ByteArray):ByteArray
{
var pad:IPad = new NullPad;
var mode:ICipher = Crypto.getCipher(_TYPE, _KEY, pad);
pad.setBlockSize(mode.getBlockSize());
mode.encrypt(array);
return array;
}
public static function decrypt(array:ByteArray):ByteArray
{
var pad:IPad = new NullPad;
var mode:ICipher = Crypto.getCipher(_TYPE, _KEY, pad);
pad.setBlockSize(mode.getBlockSize());
mode.decrypt(array);
return array;
}
C# read/unserialize/decrypt code
public override object Read(int length)
{
object d;
using (MemoryStream stream = new MemoryStream())
{
stream.Write(this._readBuffer, 0, length);
stream.Position = 0;
if (this.Decrypter != null)
{
using (CryptoStream c = new CryptoStream(stream, this.Decrypter, CryptoStreamMode.Read))
using (AmfReader reader = new AmfReader(c))
{
d = reader.ReadAmf3Object();
}
}
else
{
using (AmfReader reader = new AmfReader(stream))
{
d = reader.ReadAmf3Object();
}
}
}
return d;
}
Define "secure."
DES is more secure than plain text, but due to it's 56-bit keysize, it's not usually used anymore. If you're protecting data against your family, or the casual ease dropper this might be okay.
If people are using DES these days, it's Triple DES which essentially runs DES, three times, on each datablock.
Now a days the symmetric encryption algorithm (which DES is) of choice is AES, which is like the spiritual successor to DES.
AES with a sufficiently large key of 256 (really 512 or higher now a days) is cryptographically secure for most applications.
The few caveats of AES are:
- It's still restricted to US Export controls
- The NSA can decrypt your information if they want to (yes this is tin hat thinking)
Regarding your error, first try switching to AES, and see if you still get a problem.
Regarding AES:
Key selection is important, as well as key protection.
Key Selection
If you want to "password" protect your data, using AES, then you need to convert your password into an AES key. This is a common pitfall for many amateur computer security developers. Adobe essentially destroyed all the protection of AES in their PDF's by using an MD5 hash of the users password as the key. Needless to say, you're smarter than all of Adobe's engineers combined, so you won't make that mistake.
The proper way to generate a key from a password is using RFC2898 aka PBKD2 (password based key derivation function). .NET handily has a method that does this: Rfc2898DeriveBytes(). Essentially what this does is cryptographically securely hashes your password, with a supplied salt (more on this in a bit), a number of times, supplied by the user. This provides several layers to protect against brute force attacks against your password (assuming your key is large enough to prevent brute force attacks against it!)
Each iteration of PBKD2 takes a minuscule amount of time to run. The more interation you run (i think the recommend number is > 1000), the more computer time it takes. This time is still less than a human would recognize, but in computer time it's like a century. Thus without knowing the exact iteration count, it makes it a very lengthy process to brute force attack a password.
Salt. Rather than taking a direct hash of your password, a salt adds extra information to your input password, creating a unique hash. This prevents rainbow table attacks, assuming you keep your salt value protected.
Key Storage
The other side to cryptography is key storage. If you are password protecting your data, then you need to securely store the password. The easiest way is to use the OS's built in security. On Windows thats using DPAPI in the registry, and Unix, filepermissions.
AES as a Session Key
If you are looking to securely transmit data across a nonsecure channel (or even adding your own extra security ontop of SSL), you may want to looking at using AES as a session encryption.
Essentially this is two scheme encryption system that works as follows:
You generate a public/private key pair using your favorite assymetric encryption (RSA!) for your server. Each trusted client is given the public key. During a session, the client generates a new random AES key of 256 bit or higher. This AES Session key is encrypted using the public RSA key. This encrypted data containing the AES session key is sent to the server. The server decrypts the data using it's private RSA key, and keeps the AES Session key. During the rest of the session, all data is encrypted with the session AES key. At the end of the session, the AES key is discarded.
While this does require more handshaking, this gives you the added protection of limiting exposure. Since the AES key is only good for a session, if it's discovered, the damage is only limited to a single session.
DES is a block cipher, so in general it makes working with bytes more tedious. AS3 is a stream cipher used primarily with GSM phone systems, because it's a stream cipher it'll work nicely with bytes.
Personally, I would use RC4 if you really need to use a stream cipher; it's very quick. There's a good implementation here http://dotnet-snippets.com/dns/rc4-encryption-SID577.aspx
There are some very important caveats you should be aware of when using stream ciphers:
1) NEVER re-use an encryption key with a stream cipher.
2) Because you're encrypting one byte at a time, it's hard to determine if the data has been tampered with, so you'll need add a digital signature or HMAC to the stream.
精彩评论