a developers guide to encryption
TRANSCRIPT
A Developer’s Guide to Encryption
Barry DorransMVP – Developer Security
(well for 9 more days anyway)[email protected]
A Developer’s Guide to Encryption
• What is cryptography?• Random Numbers• Hashing• Symmetric Encryption– Deriving keys from passwords
• Asymmetric Encryption– Manual Asymmetric Encryption– X509 Certificates
• Message Authentication Codes• Encrypting and Signing XML
What is cryptography?
• This session will not include mathematics.
• Cryptography - the study of techniques and applications that depend on the existence of difficult problems.
• Cryptanalysis - the study of how to compromise (defeat) cryptographic mechanisms.
• Cryptology - (from the Greek “kryptós lógos” meaning “hidden word”) is the discipline of cryptography and cryptanalysis combined.
Definitions
• Plaintext / Cleartext – Unencrypted Data.
• Ciphertext –Encrypted Data.
• Cipher –Encryption algorithm.
Random Numbers
• Cryptography needs random numbers.
• Random isn’t really random.
• PRNG – Pseudo Random Number Generator.
Cryptographically Secure Random Numbers
• System.Security.Cryptography.RandomNumberGenerator
public static byte[] GenerateRandomBytes(int length){ byte[] randomArray = new byte[length]; RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(randomArray); return randomArray;}
Hardware RNGs
• Based on– Radioactive decay,– Background noise,– Other entropy source.
• Specialised Hardware.• But now even Intel
Chipsets have hardware RNGs.
• (Post Office Ernie)
Hashing
• A well-defined procedure or mathematical function that converts a large, possibly variable-sized amount of data into a small datum.
• One way.• Typically used for
passwords, checksums.
Generating a hashHashAlgorithm algorithm = new SHA256Managed();byte[] hash = algorithm.ComputeHash(plaintext);
Hash Algorithms
• MD Family (MD2, MD4, MD5)• SHA Family (SHA1, SHA2, SHA3)• Whirlpool
• MD*, SHA1 are no longer considered secure• SHA2 are the most commonly used• Whirlpool is the newest ISO standard.
No implementation in the .NET framework.
Salting the hash
• Salting adds a random piece of data to the plaintext.
• Stops pre-computed lookups and rainbow tables.
• Never hash without salt.
• Salts can be stored beside the hash.
Salting a hashHashAlgorithm algorithm = new SHA256Managed();
byte[] plainTextWithSaltBytes = new byte[plainText.Length + salt.Length];
for (int i = 0; i < plainText.Length; i++){ plainTextWithSaltBytes[i] = plainText[i];}for (int i = 0; i < salt.Length; i++){ plainTextWithSaltBytes[plainText.Length + i] = salt[i];}
byte[] hash = algorithm.ComputeHash(plainTextWithSaltBytes);
Comparing byte arrayspublic static bool CompareByteArrays( byte[] array1, byte[] array2){ if (array1.Length != array2.Length) return false;
for (int i = 0; i < array1.Length; i++) { if (array1[i] != array2[i]) return false; }
return true;}
Demo Time!
Encryption Keys
• Once you lose them change the “locks”.
• Keys are like condoms -don’t reuse them.
Symmetric Encryption
• A single key is used for encryption and decryption.
• Fast, computationally cheap.
• Needs a shared key.• Repudiable.
Symmetric Keys
• Keys are cryptographically secure random data.
• Size of key depends on algorithm.
Initialization Vectors
• Symmetric algorithms tend to be block algorithms.
• The result of a block encryption feeds into the next block.
• An IV is the initial starting block.
• An IV is cryptographically secure random data
Demo Time!
Encrypting SymmetricallyRijndaelManaged rijndaelManaged = new RijndaelManaged();ICryptoTransform cryptoTransform = rijndaelManaged.CreateEncryptor(
key, IV);
MemoryStream outputStream = new MemoryStream();CryptoStream cryptoStream = new CryptoStream(
outputStream,cryptoTransform,CryptoStreamMode.Write);
cryptoStream.Write(plaintextAsBytes, 0,plaintextAsBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] ciphertextAsBytes = outputStream.ToArray();
Decrypting SymmetricallyRijndaelManaged rijndaelManaged = new RijndaelManaged();ICryptoTransform cryptoTransform = rijndaelManaged.CreateDecryptor(
key, IV);
MemoryStream outputStream = new MemoryStream();CryptoStream cryptoStream = new CryptoStream(
outputStream,cryptoTransform,CryptoStreamMode.Write);
cryptoStream.Write(plaintextAsBytes, 0,plaintextAsBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] ciphertextAsBytes = outputStream.ToArray();
Symmetric Encryption Algorithms
• DES• TripleDES• Rivest Cipher 2• Rijndael/AES
• DES/RC considered unsafe.• Rijndael is the most commonly used.
Deriving keys from passwords
• RFC2898 derives a key and IV from a password and a salt
private static void GetKeyAndIVFromPasswordAndSalt( string password, byte[] salt, SymmetricAlgorithm symmetricAlgorithm, ref byte[] key, ref byte[] iv){ Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt); key = rfc2898DeriveBytes.GetBytes( symmetricAlgorithm.KeySize / 8); iv = rfc2898DeriveBytes.GetBytes( symmetricAlgorithm.BlockSize / 8);}
Message Authentication Codes
• MACs provide data integrity.
• A checksum of the plaintext combined with a MAC key.
• MAC can be stored alongside data, key cannot.
Demo Time!
Generating a MACprivate static byte[] CalculateMAC( byte[] plainText, byte[] key){ HMACSHA256 hmac = new HMACSHA256(key); return hmac.ComputeHash(plainText);}
Asymmetric Encryption
• Two keys are used.• A public key allows
encryption.• A private key allows
decryption.• Slow, computationally
heavy.• Only for small amounts
of data.
Demo Time!
Encrypting AsymmetricallyRSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024);string publicKey = rsa.ToXmlString(false);string privateKey = rsa.ToXmlString(true);…RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.FromXmlString(publicKey);byte[] ciphertextAsBytes = rsa.Encrypt(plaintextAsBytes, true);
Encrypting AsymmetricallyRSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024);string publicKey = rsa.ToXmlString(false);string privateKey = rsa.ToXmlString(true);…RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.FromXmlString(privateKey);byte[] plaintextAsBytes = rsa.Decrypt(ciphertextAsBytes, true);
X509 Certificate Encryption
• Certificates are a container for a public and private key.
• HTTPS certificate properties show the public key.
• Windows has a secure certificate store.
• Private keys have ACLs.Allow access via Certificate MMC snap-in
Demo Time!
Making Certificates with makecertmakecert -sv devReedRootCA.pvk -r -n "CN=Development Root CA" devRootCA.cer
makecert -pe -n "CN=barryd" -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -ic devReedRootCA.cer -iv devRootCA.pvk -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 -sv barryd.pvk barryd.cer
pvk2pfx -pvk barryd.pvk -spc barryd.cer -pfx barryd.pfx
Loading a Certificatestatic X509Certificate2 LoadCertificate(string serialNumber){ X509Store certificateStore = new X509Store(StoreName.My,
StoreLocation.CurrentUser); certificateStore.Open(OpenFlags.ReadOnly); X509Certificate2Collection searchResults = certificateStore.Certificates.Find( X509FindType.FindBySerialNumber, serialNumber, false);
if (searchResults.Count != 1) { throw new ArgumentException( "Cannot find individual certificate with the serial # specified.", "serialNumber"); }
certificateStore.Close(); return searchResults[0];}
Encrypting With A CertificateX509Certificate2 certificate = LoadCertificate(this.serialNumber.Text);
RSACryptoServiceProvider encryptionProvider = (RSACryptoServiceProvider) certificate.PublicKey.Key;
byte[] cipherText = encryptionProvider.Encrypt( plaintextAsBytes, true));
Decrypting With A CertificateX509Certificate2 certificate = LoadCertificate(this.serialNumber.Text);
if (!certificate.HasPrivateKey) throw new CryptographicException( "No private key.");
RSACryptoServiceProvider encryptionProvider = (RSACryptoServiceProvider) certificate;
byte[] plaintext = encryptionProvider.Decrypt( ciphertextAsBytes, true));
Envelopes & Signing with certificates
• Signing guarantees data integrity.
• Signing with a certificate provides non-repudiation.
• CMS / PKCS #7 is the standard envelope format.
Encrypting a CMS envelopestatic byte[] EncryptForCertificate( byte[] plaintext, X509Certificate2 certificate){ ContentInfo contentInfo = new ContentInfo(plaintext); EnvelopedCms envelopedCms = new EnvelopedCms(contentInfo);
CmsRecipient recipient = new CmsRecipient(certificate); envelopedCms.Encrypt(recipient); return envelopedCms.Encode();}
Signing a CMS envelopestatic byte[] SignWithCertificate( byte[] plaintext, X509Certificate2 certificate){ ContentInfo contentInfo = new ContentInfo(plaintext); CmsSigner signer = new CmsSigner(certificate); SignedCms signedCms = new SignedCms(contentInfo); signedCms.ComputeSignature(signer); return signedCms.Encode();}
Decrypting a CMS envelopestatic byte[] DecryptEnvelopedCMS( byte[] envelopeAsBytes){ EnvelopedCms envelopedCms = new EnvelopedCms(); envelopedCms.Decode(envelopeAsBytes); envelopedCms.Decrypt(); return envelopedCms.ContentInfo.Content;}
Validating X509 Signaturesstatic bool IsSignatureValid(SignedCms signedCms){ bool result = false; try { // Call with true to check CRLs. signedCms.CheckSignature(false); foreach (SignerInfo signerInfo in signedMessage.SignerInfos) { X509Certificate2 signingCert = signerInfo.Certificate; // Validate signingCert is known. } result = true; } catch (CryptographicException) { } return result;}
Encrypting and Signing XML
• XML has standards for Encryption and Signing - XmlEnc & XmlDSig
• Can encrypt and sign multiple elements with multiple keys.
• Typically done with certificates.
• Certificate is used to protect generated symmetric key.
Demo Time!
Encrypting XMLprivate static void EncryptXml( XmlDocument document, string elementIdToEncrypt, X509Certificate2 certificate){ // Extract the element to encrypt XmlElement elementToEncrypt = document.GetElementsByTagName(elementIdToEncrypt)[0] as XmlElement; if (elementToEncrypt == null) { throw new XmlException("The specified element was not found"); } // Create an instance of the encryptedXml class, // and encrypt the data EncryptedXml encryptedXml = new EncryptedXml(); EncryptedData encryptedData = encryptedXml.Encrypt(elementToEncrypt, certificate); // Replace the original element. EncryptedXml.ReplaceElement(elementToEncrypt, encryptedData, false);}
Decrypting XMLprivate static void DecryptXml( XmlDocument document){ // Create a new EncryptedXml object // from the document EncryptedXml encryptedXml = new EncryptedXml(document); // Decrypt the document. encryptedXml.DecryptDocument();}
Signing XMLprivate static void SignXml(XmlDocument document, X509Certificate2 certificate){ SignedXml signedXml = new SignedXml(document) { SigningKey = certificate.PrivateKey }; Reference reference = new Reference { Uri = string.Empty }; XmlDsigC14NTransform transform = new XmlDsigC14NTransform(); reference.AddTransform(transform); XmlDsigEnvelopedSignatureTransform envelope = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(envelope); signedXml.AddReference(reference); KeyInfo keyInfo = new KeyInfo(); keyInfo.AddClause(new KeyInfoX509Data(certificate)); signedXml.KeyInfo = keyInfo; signedXml.ComputeSignature(); XmlElement xmlDigitalSignature = signedXml.GetXml(); document.DocumentElement.AppendChild(document.ImportNode(xmlDigitalSignature, true));}
Validating XML Signaturesprivate static bool VerifySignature(XmlDocument document){ SignedXml signedXml = new SignedXml(document);
XmlNodeList nodeList = document.GetElementsByTagName("Signature"); if (nodeList.Count <= 0) { throw new CryptographicException("No signature found."); } signedXml.LoadXml((XmlElement)nodeList[0]); return signedXml.CheckSignature();}
Extracting the signing certificateprivate static bool VerifySignature(XmlDocument document, out X509Certificate signingCertificate){ SignedXml signedXml = new SignedXml(document);
XmlNodeList nodeList = document.GetElementsByTagName("Signature"); if (nodeList.Count <= 0) throw new CryptographicException("No signature found.");
signedXml.LoadXml((XmlElement)nodeList[0]);
signingCertificate = null; foreach (KeyInfoClause keyInfoClause in signedXml.KeyInfo) { if (!(keyInfoClause is KeyInfoX509Data)) continue;
KeyInfoX509Data keyInfoX509Data = keyInfoClause as KeyInfoX509Data; if ((keyInfoX509Data.Certificates != null) && (keyInfoX509Data.Certificates.Count == 1)) signingCertificate = (X509Certificate)keyInfoX509Data.Certificates[0]; } return signedXml.CheckSignature();}
Links
• http://www.keylength.com/ - collection of recommended algorithms, key lengths and expiries.
• http://csrc.nist.gov/groups/ST/toolkit/ - US National Institute of Standards and Technology recommendations
Buy my book
Beginning ASP.NET SecurityWrox PressISBN: 978-0470743652Available now!
An ideal valentine’s gift for your loved one …