520 likes | 780 Views
A Developer’s Guide to Encryption. Barry Dorrans MVP – Developer Security (well for 9 more days anyway) barryd@idunno.org. A Developer’s Guide to Encryption. What is cryptography? Random Numbers Hashing Symmetric Encryption Deriving keys from passwords Asymmetric Encryption
E N D
A Developer’s Guide to Encryption Barry Dorrans MVP – Developer Security (well for 9 more days anyway)barryd@idunno.org
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ósló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(intlength) { byte[] randomArray = new byte[length]; RNGCryptoServiceProviderrng = 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 hash HashAlgorithmalgorithm = 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 hash HashAlgorithmalgorithm = 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 arrays public 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; }
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
Encrypting Symmetrically RijndaelManagedrijndaelManaged = new RijndaelManaged(); ICryptoTransformcryptoTransform = rijndaelManaged.CreateEncryptor( key, IV); MemoryStreamoutputStream = new MemoryStream(); CryptoStreamcryptoStream = new CryptoStream( outputStream, cryptoTransform, CryptoStreamMode.Write); cryptoStream.Write(plaintextAsBytes, 0,plaintextAsBytes.Length); cryptoStream.FlushFinalBlock(); byte[] ciphertextAsBytes = outputStream.ToArray();
Decrypting Symmetrically RijndaelManagedrijndaelManaged = new RijndaelManaged(); ICryptoTransformcryptoTransform = rijndaelManaged.CreateDecryptor( key, IV); MemoryStreamoutputStream = new MemoryStream(); CryptoStreamcryptoStream = 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, SymmetricAlgorithmsymmetricAlgorithm, 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.
Generating a MAC private 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.
Encrypting Asymmetrically RSACryptoServiceProviderrsa = new RSACryptoServiceProvider(1024); string publicKey =rsa.ToXmlString(false); string privateKey=rsa.ToXmlString(true); … RSACryptoServiceProviderrsa= new RSACryptoServiceProvider(); rsa.FromXmlString(publicKey); byte[] ciphertextAsBytes = rsa.Encrypt(plaintextAsBytes, true);
Encrypting Asymmetrically RSACryptoServiceProviderrsa = new RSACryptoServiceProvider(1024); string publicKey =rsa.ToXmlString(false); string privateKey=rsa.ToXmlString(true); … RSACryptoServiceProviderrsa= 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
Making Certificates with makecert makecert -svdevReedRootCA.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 -svbarryd.pvk barryd.cer pvk2pfx -pvkbarryd.pvk-spcbarryd.cer -pfxbarryd.pfx
Loading a Certificate static 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 Certificate X509Certificate2 certificate = LoadCertificate(this.serialNumber.Text); RSACryptoServiceProviderencryptionProvider = (RSACryptoServiceProvider)certificate.PublicKey.Key; byte[] cipherText= encryptionProvider.Encrypt(plaintextAsBytes, true));
Decrypting With A Certificate X509Certificate2 certificate = LoadCertificate(this.serialNumber.Text); if (!certificate.HasPrivateKey) throw new CryptographicException( "No private key."); RSACryptoServiceProviderencryptionProvider = (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 envelope static byte[] EncryptForCertificate( byte[] plaintext, X509Certificate2 certificate) { ContentInfocontentInfo = new ContentInfo(plaintext); EnvelopedCmsenvelopedCms = new EnvelopedCms(contentInfo); CmsRecipientrecipient = new CmsRecipient(certificate); envelopedCms.Encrypt(recipient); return envelopedCms.Encode(); }
Signing a CMS envelope static byte[] SignWithCertificate( byte[] plaintext, X509Certificate2 certificate) { ContentInfocontentInfo = new ContentInfo(plaintext); CmsSigner signer = new CmsSigner(certificate); SignedCmssignedCms = new SignedCms(contentInfo); signedCms.ComputeSignature(signer); return signedCms.Encode(); }
Decrypting a CMS envelope static byte[] DecryptEnvelopedCMS( byte[] envelopeAsBytes) { EnvelopedCmsenvelopedCms = new EnvelopedCms(); envelopedCms.Decode(envelopeAsBytes); envelopedCms.Decrypt(); return envelopedCms.ContentInfo.Content; }
Validating X509 Signatures static bool IsSignatureValid(SignedCmssignedCms) { bool result = false; try { // Call with true to check CRLs. signedCms.CheckSignature(false); foreach (SignerInfosignerInfo 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.
Encrypting XML private static void EncryptXml( XmlDocument document, string elementIdToEncrypt, X509Certificate2 certificate) { // Extract the element to encrypt XmlElementelementToEncrypt = 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 EncryptedXmlencryptedXml = new EncryptedXml(); EncryptedDataencryptedData = encryptedXml.Encrypt(elementToEncrypt, certificate); // Replace the original element. EncryptedXml.ReplaceElement(elementToEncrypt, encryptedData, false); }
Decrypting XML private static void DecryptXml(XmlDocumentdocument) { // Create a new EncryptedXml object // from the document EncryptedXmlencryptedXml = new EncryptedXml(document); // Decrypt the document. encryptedXml.DecryptDocument(); }
Signing XML private static void SignXml(XmlDocument document, X509Certificate2 certificate) { SignedXmlsignedXml = new SignedXml(document) {SigningKey= certificate.PrivateKey}; Reference reference = new Reference { Uri = string.Empty}; XmlDsigC14NTransform transform = new XmlDsigC14NTransform(); reference.AddTransform(transform); XmlDsigEnvelopedSignatureTransformenvelope = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(envelope); signedXml.AddReference(reference); KeyInfokeyInfo = new KeyInfo(); keyInfo.AddClause(new KeyInfoX509Data(certificate)); signedXml.KeyInfo = keyInfo; signedXml.ComputeSignature(); XmlElementxmlDigitalSignature = signedXml.GetXml(); document.DocumentElement.AppendChild(document.ImportNode(xmlDigitalSignature, true)); }
Validating XML Signatures private static bool VerifySignature(XmlDocument document) { SignedXmlsignedXml = new SignedXml(document); XmlNodeListnodeList = document.GetElementsByTagName("Signature"); if (nodeList.Count <= 0) { throw new CryptographicException("No signature found."); } signedXml.LoadXml((XmlElement)nodeList[0]); return signedXml.CheckSignature(); }
Extracting the signing certificate private static bool VerifySignature(XmlDocument document, out X509Certificate signingCertificate) { SignedXmlsignedXml = new SignedXml(document); XmlNodeListnodeList = document.GetElementsByTagName("Signature"); if (nodeList.Count <= 0) throw new CryptographicException("No signature found."); signedXml.LoadXml((XmlElement)nodeList[0]); signingCertificate = null; foreach(KeyInfoClausekeyInfoClause 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 Security Wrox Press ISBN: 978-0470743652 Available now! An ideal valentine’s gift for your loved one …