Security- Encryption and Signing
Hashing, signing and encryption- which algorithm is what?
Type | Algorithms |
---|---|
Hashes | MD5 (128bit) or SHA (160bit+, so stronger) You use a ComputeHash method NB: System.Object.GetHashCode isn't strong |
Signing | DSA (SignData or SignHash) Message Authentication Code (MAC) is a sort of hash for messages (like signing, but the hash has a symmetric key). HMACSHA has the biggest key (160bits) |
Encryption: Symmetric (shared key) |
3DES, Rijndael (=AES, better) |
Encryption: Assymmetric (public/private keys) |
RSA |
Strong Names and the GAC
- Create private/public keys:
sn -k Keys.snk
More secure- use a Crypto provider (CSP):sn -i Keys.snk cspName
- Sign assembly: one of
- AssemblyInfo.cs (in VStudio):
[assembly: AssemblyKeyFile(@"..\path\keys.snk")]
CSP: AssemblyKeyName - Assembly linker:
al /keyfile:keys.snk
- Or in csc compiler
- AssemblyInfo.cs (in VStudio):
- Delay signing:
- Extract public key (for delay signing):
sn -p Keys.snk PublicKey.snk
(from CSP- sn -pc ) - Either:
- AssemblyInfo.cs (in VStudio):
[assembly: AssemblyDelaySign(true)]
(use public key) - Assembly linker:
al /delaysign+
(warning: delay- and default is to fully sign)
- AssemblyInfo.cs (in VStudio):
- Turn off verification:
sn -Vr myLib.dll
- Deployment- sign private key:
sn -R myLib.dll PrivateKey.snk
- Deployment- turn on verification:
sn -Vu myLib.dll
- Extract public key (for delay signing):
Ensure code can only be called by your assemblies: use CAS StrongNameIdentityPermission with the public key (read it using sn -tp Keys.snk). (You can also create a custom code group with membership condition)
Encrypting Data
Generate a key from password
string password = "Secret";
byte[] salt = Encoding.ASCII.GetBytes("The salt");
//better- use Rfc2898DeriveBytes
var deriver = new PasswordDeriveBytes(password, salt, "SHA1", 3);
//use the length required by the algorithm
//(alg.KeySize/8 for the key, alg.BlockSize/8 for the IV)
byte[] key = deriver.GetBytes(16);
Don't use the password for the IV (the IV doesn't have to be secret).
Note symmetric algorithms generate a Key as soon as they are created.
Symmetric
Use triple DES or (XP or higher) Rijndael (AES- managed).
public void EncryptFile(string unencryptedFileName, string encryptedFileName)
{
//Encrypt (decrypt) a file
// Step 1: Create the Stream objects
FileStream unencryptedFile = new FileStream(unencryptedFileName,
FileMode.Open, FileAccess.Read);
FileStream encryptedFile = new FileStream(encryptedFileName,
FileMode.OpenOrCreate, FileAccess.Write);
// Step 2: Create the SymmetricAlgorithm object
SymmetricAlgorithm myAlg = new RijndaelManaged();
// Step 3: Specify the algorithm's key, the initialization vector, or both
// if decrypting - read in key, IV
myAlg.GenerateKey(); //optional
// Step 4: Create the ICryptoTransform object
// for decryption- myAlg.CreateDecryptor();
ICryptoTransform encryptor = myAlg.CreateEncryptor();
// Step 5: Create the CryptoStream object
// for decryption- CryptoStreamMode.Read
CryptoStream encryptStream = new CryptoStream(encryptedFile,
encryptor, CryptoStreamMode.Write);
// Step 6: Write the contents to the CryptoStream
// Read the unencrypted file into fileData
byte[] fileData = new byte[unencryptedFile.Length];
unencryptedFile.Read(fileData, 0, (int)unencryptedFile.Length);
encryptStream.Write(fileData, 0, (int)unencryptedFile.Length);
}
Asymmetric (and signing)
AsymmetricAlgorithm base has 2 implementations- RSACryptoServiceProvider + DSACryptoServiceProvider
For messages (one-off key, not saved)
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
//automatically generates strongest key-export public key
//parameters = the key in a byte-array structure
RSAParameters key = rsa.ExportParameters(false); //true = private key as well..
string xml = rsa.ToXmlString(false);
To save private key, create a CspParameters object with a KeyContainerName and pass that into the RSACsp constructor, and set r.PersistKeyInCsp=true.
Encyrpt + Decrypt methods take/return bytes arrays (convert a string using System.Text.Encoding.Unicode.GetBytes and back with .GetString).
These AsymmetricAlgorithm classes can also be used for digitally signing (SignData/ VerifyData)
Hashes
For storing passwords, checking file changes etc
//MD5 or various SHA versions- pass in a key for a keyed version
var hasher = new MD5CryptoServiceProvider();
hasher.ComputeHash(bytes);
byte[] hash= hasher.Hash;
string sHash = Convert.ToBase64String(hash);