public void AuthenticatedAesCngGcmMultiRoundTripTest() { byte[] plaintext = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 }; byte[] plaintext2 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 }; byte[] expectedCiphertext = new byte[] { 0x54, 0x2d, 0x26, 0x15, 0x9c, 0xb3, 0x6e, 0x21, 0xd2, 0x58, 0xcf, 0x9c, 0x6e, 0xce, 0xfb, 0x5f, 0x8c, 0x2a, 0xb8, 0x22, 0x4d, 0x6d, 0xd0, 0x02, 0x76, 0xd2, 0xab, 0x22, 0xa2, 0xd6, 0xee, 0x5b }; byte[] expectedTag = new byte[] { 0xc1, 0x34, 0x38, 0x0b, 0xc3, 0x87, 0x7c, 0xf5, 0x2f, 0x3b, 0xa9, 0xfe, 0x3c, 0x69, 0x4b, 0x9f }; byte[] key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 }; byte[] iv = new byte[] { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; using (AuthenticatedAesCng gcm = new AuthenticatedAesCng()) { gcm.CngMode = CngChainingMode.Gcm; gcm.Key = key; gcm.IV = iv; gcm.Tag = expectedTag; // Encrypt byte[] ciphertext = null; using (MemoryStream ms = new MemoryStream()) using (IAuthenticatedCryptoTransform encryptor = gcm.CreateAuthenticatedEncryptor()) using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { // Push through two blocks and call final to get the tag. cs.Write(plaintext, 0, plaintext.Length); cs.Write(plaintext2, 0, plaintext2.Length); cs.FlushFinalBlock(); ciphertext = ms.ToArray(); // Check if the ciphertext and tag are what are expected. Assert.IsTrue(Util.CompareBytes(expectedCiphertext, ciphertext)); Assert.IsTrue(Util.CompareBytes(expectedTag, encryptor.GetTag())); } // Decrypt using (MemoryStream ms = new MemoryStream()) using (ICryptoTransform decryptor = gcm.CreateDecryptor()) using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)) { cs.Write(ciphertext, 0, ciphertext.Length / 2); cs.Write(ciphertext, ciphertext.Length / 2, ciphertext.Length / 2); cs.FlushFinalBlock(); byte[] decrypted = ms.ToArray(); // Compare the decrypted text to the initial ciphertext. byte[] fullPlaintext = new byte[plaintext.Length + plaintext2.Length]; Array.Copy(plaintext, 0, fullPlaintext, 0, plaintext.Length); Array.Copy(plaintext2, 0, fullPlaintext, plaintext.Length, plaintext2.Length); Assert.IsTrue(Util.CompareBytes(fullPlaintext, decrypted)); } } }
private static MemoryStream Encrypt(Stream source, string fileName, out string seed_encoded, out string ident) { // Randomly generate a new seed for upload byte[] seed = new byte[16]; using (RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider()) { rngCsp.GetBytes(seed); } seed_encoded = UrlBase64Encode(seed); // Derive the parameters (key, IV, ident) from the seed byte[] key, iv; DeriveParams(seed, out key, out iv, out ident); // Create a new String->String map for JSON blob, and define filename and metadata Dictionary <string, string> metadataMap = new Dictionary <string, string>(); metadataMap["mime"] = Helpers.IsTextFile(fileName) ? "text/plain" : Helpers.GetMimeType(fileName); metadataMap["name"] = fileName; // Encode the metadata with UTF-16 and a double-null-byte terminator, and append data // Unfortunately, the CCM cipher mode can't stream the encryption, and so we have to GetBytes() on the source. // We do limit the source to 50MB however byte[] data = Encoding.BigEndianUnicode.GetBytes(JsonConvert.SerializeObject(metadataMap)).Concat(new byte[] { 0, 0 }).Concat(source.GetBytes()).ToArray(); // Calculate the length of the CCM IV and copy it over long ccmIVLen = FindIVLen(data.Length); byte[] ccmIV = new byte[ccmIVLen]; Array.Copy(iv, ccmIV, ccmIVLen); // http://blogs.msdn.com/b/shawnfa/archive/2009/03/17/authenticated-symmetric-encryption-in-net.aspx using (AuthenticatedAesCng aes = new AuthenticatedAesCng()) { aes.CngMode = CngChainingMode.Ccm; aes.Key = key; aes.IV = ccmIV; aes.TagSize = MacSize; MemoryStream ms = new MemoryStream(); using (IAuthenticatedCryptoTransform encryptor = aes.CreateAuthenticatedEncryptor()) { CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write); cs.Write(data, 0, data.Length); cs.FlushFinalBlock(); byte[] tag = encryptor.GetTag(); ms.Write(tag, 0, tag.Length); return(ms); } } }
private void RunTestVector(GcmTestVector test) { // Encrypt the input byte[] ciphertext = null; using (AuthenticatedAesCng gcm = new AuthenticatedAesCng()) { gcm.CngMode = CngChainingMode.Gcm; gcm.Key = test.Key; gcm.IV = test.IVBytes; gcm.AuthenticatedData = test.AuthenticationData; using (MemoryStream ms = new MemoryStream()) using (IAuthenticatedCryptoTransform encryptor = gcm.CreateAuthenticatedEncryptor()) using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { if (test.Plaintext != null) { cs.Write(test.Plaintext, 0, test.Plaintext.Length); } cs.FlushFinalBlock(); ciphertext = ms.ToArray(); // Verify the produced tag is what we expected it to be Assert.IsTrue(Util.CompareBytes(test.Tag, encryptor.GetTag())); } } if (test.Ciphertext != null) { // Verify the ciphertext is what we expected it to be Assert.IsTrue(Util.CompareBytes(test.Ciphertext, ciphertext)); // Round trip the data using (AuthenticatedAesCng gcm = new AuthenticatedAesCng()) { gcm.CngMode = CngChainingMode.Gcm; gcm.Key = test.Key; gcm.IV = test.IVBytes; gcm.AuthenticatedData = test.AuthenticationData; gcm.Tag = test.Tag; using (MemoryStream ms = new MemoryStream()) using (CryptoStream cs = new CryptoStream(ms, gcm.CreateDecryptor(), CryptoStreamMode.Write)) { cs.Write(test.Ciphertext, 0, test.Ciphertext.Length); cs.FlushFinalBlock(); byte[] plaintext = ms.ToArray(); Assert.IsTrue(Util.CompareBytes(test.Plaintext, plaintext)); } } } }
public bool Encrypt(ref byte[] data, int length, ref byte[] tag) { if (IsInitialized) { _serverEncrypt.IV = BitConverter.GetBytes(_serverCounter).Combine(BitConverter.GetBytes(0x52565253)); using (IAuthenticatedCryptoTransform encryptor = _serverEncrypt.CreateAuthenticatedEncryptor()) { data = encryptor.TransformFinalBlock(data, 0, length); tag = encryptor.GetTag(); } } ++_serverCounter; return(true); }
// returns the encrypted string in the format [IV]-[TAG]-[DATA] public static string EncryptString(string str) { if (String.IsNullOrEmpty(str)) { throw new ArgumentNullException("encryption string invalid"); } using (AuthenticatedAesCng aes = new AuthenticatedAesCng()) { byte[] message = Encoding.UTF8.GetBytes(str); aes.Key = GetEncryptionKey(); aes.IV = GenerateIV(); // use the GCM mode, which should prevent the Padding Oracle attack // https://en.wikipedia.org/wiki/Padding_oracle_attack aes.CngMode = CngChainingMode.Gcm; aes.AuthenticatedData = GetAdditionalAuthenticationData(); using (MemoryStream memoryStream = new MemoryStream()) using (IAuthenticatedCryptoTransform encryptor = aes.CreateAuthenticatedEncryptor()) using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) { // Write through and retrieve encrypted data. cryptoStream.Write(message, 0, message.Length); cryptoStream.FlushFinalBlock(); byte[] cipherText = memoryStream.ToArray(); // Retrieve tag and create array to hold encrypted data. byte[] authenticationTag = encryptor.GetTag(); byte[] encrypted = new byte[cipherText.Length + aes.IV.Length + authenticationTag.Length]; // encrypt the data in the format [IV]-[TAG]-[DATA] aes.IV.CopyTo(encrypted, 0); authenticationTag.CopyTo(encrypted, IV_LENGTH); cipherText.CopyTo(encrypted, IV_LENGTH + TAG_LENGTH); // Store encrypted value in base 64. return(Convert.ToBase64String(encrypted)); } } }
public void AuthenticatedAesCngChainingTest() { byte[] plaintext = new byte[20 * 1024]; byte[] iv = new byte[12]; byte[] authenticatedData = new byte[1024]; using (RNGCng rng = new RNGCng()) { rng.GetBytes(plaintext); rng.GetBytes(iv); rng.GetBytes(authenticatedData); } foreach (CngChainingMode chainingMode in new CngChainingMode[] { CngChainingMode.Ccm, CngChainingMode.Gcm }) { using (AuthenticatedAesCng aes = new AuthenticatedAesCng()) { aes.AuthenticatedData = authenticatedData; aes.CngMode = chainingMode; aes.IV = iv; // Encrypt the whole block of data at once byte[] wholeCiphertext = null; byte[] wholeTag = null; using (IAuthenticatedCryptoTransform encryptor = aes.CreateAuthenticatedEncryptor()) { wholeCiphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length); wholeTag = encryptor.GetTag(); } // Encrypt it in chunks byte[] blockCiphertext = null; byte[] blockTag = null; using (MemoryStream ms = new MemoryStream()) using (IAuthenticatedCryptoTransform encryptor = aes.CreateAuthenticatedEncryptor()) using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { int chunkSize = 128; for (int offset = 0; offset < plaintext.Length; offset += chunkSize) { cs.Write(plaintext, offset, chunkSize); } cs.FlushFinalBlock(); blockCiphertext = ms.ToArray(); blockTag = encryptor.GetTag(); } // Make sure we got the same results in both cases Assert.IsTrue(Util.CompareBytes(wholeCiphertext, blockCiphertext)); Assert.IsTrue(Util.CompareBytes(wholeTag, blockTag)); aes.Tag = wholeTag; // Decrypt the whole block of data at once using (ICryptoTransform decryptor = aes.CreateDecryptor()) { byte[] wholePlaintext = decryptor.TransformFinalBlock(wholeCiphertext, 0, wholeCiphertext.Length); Assert.IsTrue(Util.CompareBytes(plaintext, wholePlaintext)); } // Decrypt the data in chunks using (MemoryStream ms = new MemoryStream()) using (ICryptoTransform decryptor = aes.CreateDecryptor()) using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)) { int chunkSize = 128; for (int offset = 0; offset < blockCiphertext.Length; offset += chunkSize) { cs.Write(blockCiphertext, offset, chunkSize); } cs.FlushFinalBlock(); byte[] blockPlaintext = ms.ToArray(); Assert.IsTrue(Util.CompareBytes(plaintext, blockPlaintext)); } } } }
/// <summary> /// Perform a round trip test given input and the expected output /// </summary> private void AuthenticatedAesCngRoundTripTest(RoundTripTestData testData) { using (AuthenticatedAesCng aes = new AuthenticatedAesCng()) { aes.CngMode = testData.ChainingMode; if (testData.Key != null) { aes.Key = testData.Key; } if (testData.IV != null) { aes.IV = testData.IV; } if (testData.AuthenticationData != null) { aes.AuthenticatedData = testData.AuthenticationData; } if (testData.ExpectedTag != null) { aes.Tag = testData.ExpectedTag; } // Encrypt byte[] ciphertext = null; byte[] tag = null; using (MemoryStream ms = new MemoryStream()) using (IAuthenticatedCryptoTransform encryptor = aes.CreateAuthenticatedEncryptor()) using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { cs.Write(testData.Plaintext, 0, testData.Plaintext.Length); cs.FlushFinalBlock(); tag = encryptor.GetTag(); ciphertext = ms.ToArray(); // Check if the ciphertext and tag are what are expected. if (testData.ExpectedCiphertext != null) { Assert.IsTrue(Util.CompareBytes(testData.ExpectedCiphertext, ciphertext)); } if (testData.ExpectedTag != null) { Assert.IsTrue(Util.CompareBytes(testData.ExpectedTag, tag)); } } if (testData.ExpectedTag == null) { aes.Tag = tag; } // Decrypt using (MemoryStream ms = new MemoryStream()) using (ICryptoTransform decryptor = aes.CreateDecryptor()) using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)) { cs.Write(ciphertext, 0, ciphertext.Length); cs.FlushFinalBlock(); // Compare the decrypted text to the initial ciphertext. byte[] decrypted = ms.ToArray(); Assert.IsTrue(Util.CompareBytes(testData.Plaintext, decrypted)); } } }
public override string ToString() { string header = JsonConvert.SerializeObject(this); string claims = JsonConvert.SerializeObject(this.claims); string signature = String.Empty; //First segment using (HMACSHA256 hmac = new HMACSHA256()) { string data = String.Format("{0}.{1}", header, claims); byte[] signatureBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); signature = signatureBytes.ToBase64String(); } byte[] masterKey = new byte[32]; byte[] initVector = new byte[12]; //Third segment using (var provider = new RNGCryptoServiceProvider()) { provider.GetBytes(masterKey); provider.GetBytes(initVector); } byte[] encryptedMasterKey = null; //Second segment using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { rsa.FromXmlString(this.AsymmetricKey); encryptedMasterKey = rsa.Encrypt(masterKey, true); // OAEP Padding } var authData = new EncryptedPayload() { Header = header, EncryptedMasterKey = encryptedMasterKey, InitializationVector = initVector }; byte[] additionalAuthenticatedData = authData.ToAdditionalAuthenticatedData(); byte[] tag = null; //Fifth segment byte[] cipherText = null; //Fourth segment using (var aes = new AuthenticatedAesCng()) { aes.CngMode = CngChainingMode.Gcm; // Galois/Counter Mode aes.Key = masterKey; aes.IV = initVector; aes.AuthenticatedData = additionalAuthenticatedData; using (MemoryStream ms = new MemoryStream()) { using (IAuthenticatedCryptoTransform encryptor = aes.CreateAuthenticatedEncryptor()) { using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { // Encrypt the claims set byte[] claimsSet = Encoding.UTF8.GetBytes(claims); cs.Write(claimsSet, 0, claimsSet.Length); cs.FlushFinalBlock(); tag = encryptor.GetTag(); cipherText = ms.ToArray(); } } } } authData.CipherText = cipherText; authData.Tag = tag; return(authData.ToString()); }
/// <summary> /// Utility to encapsulate round-tripping ciphertext /// </summary> private static bool RoundTripHelper <TEncryptionAlgorithm, TDecryptionAlgorithm>(Action <TEncryptionAlgorithm> encryptionSetup, Action <TDecryptionAlgorithm> decryptionSetup) where TEncryptionAlgorithm : AuthenticatedSymmetricAlgorithm, new() where TDecryptionAlgorithm : AuthenticatedSymmetricAlgorithm, new() { // Encryption parameters byte[] key = null; byte[] iv = null; byte[] authenticatedData = Encoding.UTF8.GetBytes("Additional authenticated data"); // Round tripping data byte[] plainText = Encoding.UTF8.GetBytes("Authenticated round trip message"); byte[] cipherText = null; byte[] tag = null; AuthenticatedSymmetricEncryptionState encryptionState = null; AuthenticatedSymmetricAlgorithm encryptionObject = null; try { // Setup the encryption algorithm encryptionObject = new TEncryptionAlgorithm(); encryptionObject.AuthenticatedData = authenticatedData; encryptionObject.IV = new byte[] { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; encryptionSetup(encryptionObject as TEncryptionAlgorithm); encryptionObject = encryptionObject.EnableLogging(); // Encrypt the data using (MemoryStream ms = new MemoryStream()) using (IAuthenticatedCryptoTransform encryptor = encryptionObject.CreateAuthenticatedEncryptor()) using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { cs.Write(plainText, 0, plainText.Length); cs.FlushFinalBlock(); cipherText = ms.ToArray(); tag = encryptor.GetTag(); } // Save the encryption parameters key = encryptionObject.Key; iv = encryptionObject.IV; authenticatedData = encryptionObject.AuthenticatedData; encryptionState = encryptionObject.GetLastEncryptionState(); } finally { if (encryptionObject != null) { (encryptionObject as IDisposable).Dispose(); } } byte[] roundTrip = null; // Now verify the data AuthenticatedSymmetricAlgorithm decryptionObject = null; try { decryptionObject = new TDecryptionAlgorithm(); decryptionObject.Key = key; decryptionObject.IV = iv; decryptionObject.AuthenticatedData = authenticatedData; decryptionObject.Tag = tag; decryptionSetup(decryptionObject as TDecryptionAlgorithm); decryptionObject = decryptionObject.EnableDecryptionVerification(encryptionState); using (MemoryStream ms = new MemoryStream()) using (CryptoStream cs = new CryptoStream(ms, decryptionObject.CreateDecryptor(), CryptoStreamMode.Write)) { cs.Write(cipherText, 0, cipherText.Length); cs.FlushFinalBlock(); roundTrip = ms.ToArray(); } } finally { if (decryptionObject != null) { (decryptionObject as IDisposable).Dispose(); } } if (roundTrip.Length != plainText.Length) { return(false); } for (int i = 0; i < roundTrip.Length; ++i) { if (roundTrip[i] != plainText[i]) { return(false); } } return(true); }
public override string ToString() { string header = JsonConvert.SerializeObject(this); string claims = JsonConvert.SerializeObject(this.claims); // Generate a 256 bit random Content Master Key and a 96 bit initialization vector byte[] masterKey = new byte[32]; byte[] initVector = new byte[12]; using (var provider = new RNGCryptoServiceProvider()) { provider.GetBytes(masterKey); provider.GetBytes(initVector); } byte[] encryptedMasterKey = null; using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { rsa.FromXmlString(this.AsymmetricKey); encryptedMasterKey = rsa.Encrypt(masterKey, true); // OAEP Padding } var authData = new EncryptedPayload() { Header = header, EncryptedMasterKey = encryptedMasterKey, InitializationVector = initVector }; byte[] additionalAuthenticatedData = authData.ToAdditionalAuthenticatedData(); byte[] tag = null; byte[] cipherText = null; using (var aes = new AuthenticatedAesCng()) { aes.CngMode = CngChainingMode.Gcm; // Galois/Counter Mode aes.Key = masterKey; aes.IV = initVector; aes.AuthenticatedData = additionalAuthenticatedData; using (MemoryStream ms = new MemoryStream()) { using (IAuthenticatedCryptoTransform encryptor = aes.CreateAuthenticatedEncryptor()) { using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { // Encrypt the claims set byte[] claimsSet = Encoding.UTF8.GetBytes(claims); cs.Write(claimsSet, 0, claimsSet.Length); cs.FlushFinalBlock(); tag = encryptor.GetTag(); cipherText = ms.ToArray(); } } } } var payload = new EncryptedPayload() { Header = header, EncryptedMasterKey = encryptedMasterKey, InitializationVector = initVector, CipherText = cipherText, Tag = tag }; string token = payload.ToString(); return(token); }