// AES Encryption - Matching results with other systems.
// This C# example is intended not only for Chilkat customers,
// but for anyone faced with the situation where data is
// encrypted by one software/system, but decrypted by another.
// A specific example might be a case where data is encrypted using
// PHP on a Linux computer, but needs to be decrypted using C#
// on a Windows platform.
// Note: Some developers really struggle with this problem.
// Debugging is difficult because if one parameter is mismatched
// the results are completely different. It is difficult to
// know when one is getting ‘closer’ to a solution because it’s
// an all-or-none proposition.
// Chilkat has extensive experience in solving these kinds
// of problems.
// The Chilkat encryption API is available on the Windows platform, and
// presents the identical API across many different programming languages:
// C++, ASP, C#, VB.NET, Delphi, Perl, Python, Ruby, Java, Visual Basic 6.0,
// Visual Foxpro, etc. One benefit to using Chilkat for encryption is
// that your encrypting and decrypting software can be coded identically using different
// programming languages. Compatibility is easy to achieve. In cases
// where Chilkat cannot be used on one end, the component is designed
// to make it possible to match encryption software packages produced by
// other vendors.
// Now for the example, which discusses each factor involved in AES
// encryption that must be matched against the software doing the decryption.
Chilkat.Crypt2 crypt = new Chilkat.Crypt2();
crypt.UnlockComponent("Anything for 30-day-trial");
// The algorithm must match, of course…
// AES is a synonym for Rijndael. They are both the same encryption algorithm.
crypt.CryptAlgorithm = "aes";
// The cipher modes must match. CBC stands for Cipher Block Chaining,
// whereas ECB stands for Electronic Cookbook. If you use CBC, an
// initialization vector is always used. If an encryption API does
// not mention IV’s, it is likely that an IV containing all NULL bytes is
// used. This is the case with Chilkat if no IV is explicitly
crypt.CipherMode = "cbc";
// The key length is in bits. AES can either be 128-bits,
// 192-bits, or 256-bits. Your secret key will be the exact length
// in bits as the key-length. If you are doing 128-bit encryption,
// your secret key must be 16 bytes (8 * 16 = 128 bits).
crypt.KeyLength = 128;
// Initialization Vector must match.
// IV’s are used when operating in CBC (Cipher Block Chaining) mode.
// AES is a block-cipher, meaning that input data is encrypted in
// fixed-sized blocks. The output is always a multiple of the
// block size. Different encryption algorithms use different block sizes.
// For example, Blowfish uses a 64-bit block size. AES however, uses
// a 128-bit block size. Note: The block size is not the same as the
// key size. 256-bit AES encryption still encrypts in 128-bit blocks.
// The length of the IV should equal the block size. For AES, the IV
// is 16 bytes (16 * 8 bits/byte = 128 bits).
// Chilkat provides a few ways to set the IV.
// (1) You can set it using a byte array:
byte  iv = new byte;
for (i=0; i<16; i++)
iv[i] = (byte)i;
crypt.IV = iv;
// (2) Another option is to set the IV from an encoded string:
// Padding Scheme
// The AES encryption algorithm produces output that is a multiple of
// 16 bytes. Therefore, if the input is not an exact multiple of
// 16, it is padded prior to encrypting. It is
// necessary to unpad after decrypting to return the original data.
// There are many different padding schemes. Chilkat offers several,
// including the most common method of appending bytes equal in value to
// the number of padding bytes. (For example, if 5 padding bytes are added,
// each padding byte has a value of 0×05.)
// There are two points to be made regarding padding with respect to
// matching output on different systems:
// (1) If all other parameters match except for padding, then it will be apparent
// because your output will only differ in the last block.
// (2) Be sure to test with enough data to produce more than one encrypted block.
// If you have only a single block of output, you cannot identify the
// case where all is OK except for padding.
// For this example, we’ll set the padding scheme equal to it’s default
// value, so the following line of code is not really necessary:
crypt.PaddingScheme = 0;
// Secret Key
// This is the most likely culprit for inconsistencies between
// encryptor and decryptor.
// The secret key is a byte array equal in length to the key length.
// If your KeyLength = 128 (i.e. 128-bit encryption) your SecretKey
// should be 16 bytes. Likewise, if your KeyLength is 256-bits, the
// SecretKey should be 32 bytes.
// Some components/APIs provide methods for converting an arbitrary
// password string to a SecretKey of the appropriate size.
// Chilkat Crypt, as an example, provides the GenerateSecretKey method
// which hashes a password string to a byte array of the appropriate length
// for the SecretKey. For example:
crypt.SecretKey = crypt.GenerateSecretKey("ThisIsMyPassword");
// Note: Set the KeyLength property prior to calling GenerateSecretKey
// in order to return a SecretKey byte array of the appropriate size.
// Other software APIs may provide similar methods. If used, you’ll need
// to know the exact hash algorithm used to transform a password string
// into a binary secret key. It’s the binary secret keys that must match, not
// the password strings. If possible, always set the binary secret key
// directly rather than rely on an undocumented hash algorithm. If you cannot
// reproduce the hash function elsewhere, you will not be able to match
// the encryption.
// Chilkat provides two ways to set the SecretKey directly. Because
// the property is a byte array, it can be set directly:
byte  secretKey = new byte;
for (i=0; i<16; i++)
secretKey[i] = (byte)i;
crypt.SecretKey = secretKey;
// It may also be set via an encoded string:
// To sum it up, these input parameters must match between encryptor
// and decryptor:
// (1) Algorithm
// (2) Mode (CBC, ECB)
// (3) Key Length (128-bit, 192-bit, 256-bit)
// (4) Initialization Vector
// (5) Secret Key
// (6) Padding Scheme (but only last block will differ if mismatched).
// That’s not the end of it, because your input data may be sensitive
// to byte-ordering issues or character encoding issues.
// For example, let’s say you are encrypting a string in VB6 (Unicode) to
// be decrypted in C++ (ANSI). You need to know the exact bytes
// passed to the encryptor. Are you passing Unicode (2 bytes/char) or
// ANSI (typically 1 byte/char)? A telltale sign of a mismatch in this
// case is an output size difference — on one system the encrypted output
// is roughly twice the size as the other. Or alternatively, you decrypt
// in C++ and the string "ABC" decrypts to "A" — which is because
// C++ strings are null-terminated and your decrypted output was in fact
// Unicode: #65 #00 #66 #00 #67 #00.
// Chilkat Crypt provides a Charset property to indicate the charset to
// be used when encrypting strings. (Input strings are automatically
// converted TO this charset prior to encrypting, and output strings
// are converted FROM this charset after decrypting.)
// This property has no affect when encrypting byte arrays (i.e. binary data).
crypt.Charset = "utf-8″;
// Byte ordering: Are you encrypting integer data such that one
// system is little-endian and the other is big-endian? If so,
// make sure you 4321 byte-swap on one side to account for the difference.
// Finally, encrypted data is binary. If your encrypted output is
// in the format of a printable string, it means that an extra step
// was taken to encode it.
// This is most commonly base64 or hex-encoding. If you are decrypting
// from an encoded string, decode first before passing the data
// to the decryptor.
crypt.EncodingMode = "base64″;
// Now that everything is fully-specified, the following code
// should produce identical results in every programming language
// supported by Chilkat: VB6, ASP, Perl, C++, C#, Python, Ruby, Foxpro, Delphi, etc.
string encryptedStr = crypt.EncryptStringENC("Hello World!");
// Output is "qiq+IFhcjTkEIkZyf31V/g=="
string decryptedStr = crypt.DecryptStringENC(encryptedStr);