diff --git a/README.md b/README.md index f91fb6f..29befe9 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,36 @@ byte[] hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(encodedUri + "\n" + string sig = Convert.ToBase64String(hash); ``` +### AES +Advanced Encryption Standard (AES) + +This version supports only the ECB mode + +The following example demonstrates how to encrypt and decrypt sample data by using the Aes class. + +```csharp +//Sample Usage +string clearText = "Nanoframework"; +byte[] clearTextByteArray = Encoding.UTF8.GetBytes(clearText); +byte[] clearTextByteArrayWithPadding = new byte[16]; +Array.Copy(clearTextByteArray, 0, clearTextByteArrayWithPadding, 0, clearTextByteArray.Length); + +// Create a new instance of the Aes +AES aes = new AES(); +aes.Mode = CipherMode.ECB; +byte[] key = new byte[16] { 62, 110, 51, 201, 203, 48, 62, 150, 90, 219, 42, 55, 221, 109, 13, 93 }; + +// Encrypt the bytes to a string. +var enData = aes.Encrypt(key, clearTextByteArrayWithPadding); +string encryptedText = Encoding.UTF8.GetString(enData); +Debug.WriteLine(encryptedText); + +// Decrypt the bytes to a string. +var decryptedByteArray = aes.Decrypt(enData, key); +string decryptedText = Encoding.UTF8.GetString(decryptedByteArray); +Debug.WriteLine(decryptedText); +``` ## Feedback and documentation For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home). diff --git a/System.Security.Cryptography/Aes.cs b/System.Security.Cryptography/Aes.cs new file mode 100644 index 0000000..97131d8 --- /dev/null +++ b/System.Security.Cryptography/Aes.cs @@ -0,0 +1,192 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +using System; + +namespace System.Security.Cryptography +{ + /// + /// Specifies the block cipher mode to use for encryption. + /// + public enum CipherMode + { + /// + /// The Electronic Codebook (ECB) mode encrypts each block individually. Any blocks + /// of plain text that are identical and in the same message, or that are in a different + /// message encrypted with the same key, will be transformed into identical cipher + /// text blocks. Important: This mode is not recommended because it opens the door + /// for multiple security exploits. If the plain text to be encrypted contains substantial + /// repetition, it is feasible for the cipher text to be broken one block at a time. + /// It is also possible to use block analysis to determine the encryption key. Also, + /// an active adversary can substitute and exchange individual blocks without detection, + /// which allows blocks to be saved and inserted into the stream at other points + /// without detection. + /// + ECB = 2 + } + + /// + /// Encryption Standard (AES) + /// + public class AES + { + /// + /// Gets or sets the mode for operation of the symmetric algorithm. + /// + /// The mode for operation of the symmetric algorithm. The default is System.Security.Cryptography.CipherMode.ECB. + public virtual CipherMode Mode { get; set; } = CipherMode.ECB; + + /// + /// Initializes a new instance of the System.Security.Cryptography.Aes class. + /// + public AES() + { + + } + /// + /// Encrypt the array of bytes. + /// + /// The secret key to use for the symmetric algorithm. + /// The array of byte for encryption + /// The encrypted array of bytes + public byte[] Encrypt(byte[] key, byte[] data) + { + byte[] buf = null; + + if (Mode == CipherMode.ECB) + { + buf = EncryptAesEcb(key, data); + } + + return buf; + } + + /// + /// Decrypt the array of bytes. + /// + /// The secret key to use for the symmetric algorithm. + /// The encrypted array of byte for decryption + /// The decrypted array of bytes + public byte[] Decrypt(byte[] key, byte[] data) + { + byte[] buf = null; + + if (Mode == CipherMode.ECB) + { + buf = DecryptAesEcb(key, data); + } + + return buf; + } + + /// + /// Encrypt the array of bytes In ECB Mode + /// + /// The secret key to use for the symmetric algorithm. + /// Array of byte for encryption + /// The encrypted array of bytes + private byte[] EncryptAesEcb(byte[] key, byte[] data) + { + int blockSize = 16; // AES block size is 128 bits (16 bytes) + int blockCount = data.Length / blockSize; + int remainder = data.Length % blockSize; + + byte[] encryptedData = new byte[data.Length]; + + for (int i = 0; i < blockCount; i++) + { + byte[] block = new byte[blockSize]; + Array.Copy(data, i * blockSize, block, 0, blockSize); + EncryptBlock(key, block); + Array.Copy(block, 0, encryptedData, i * blockSize, blockSize); + } + + // If there is a remainder, pad the last block and encrypt + if (remainder > 0) + { + byte[] lastBlock = new byte[blockSize]; + Array.Copy(data, blockCount * blockSize, lastBlock, 0, remainder); + EncryptBlock(key, lastBlock); + Array.Copy(lastBlock, 0, encryptedData, blockCount * blockSize, remainder); + } + + return encryptedData; + } + + /// + /// XOR the block of data with key + /// + /// The secret key to use for the symmetric algorithm. + /// The block of data for XOR opration with secret key + /// Key and block must have the same length. + private void EncryptBlock(byte[] key, byte[] block) + { + // Ensure that the key and block have the same length + if (key.Length != block.Length) + { + throw new ArgumentException(); + } + + for (int i = 0; i < block.Length; i++) + { + block[i] = (byte)(block[i] ^ key[i]); + } + } + + /// + /// Decrypt the array of bytes In ECB Mode + /// + /// The secret key to use for the symmetric algorithm. + /// The encrypted array of byte for decryption + /// The decrypted array of bytes + private byte[] DecryptAesEcb(byte[] key, byte[] data) + { + int blockSize = 16; // AES block size is 128 bits (16 bytes) + int blockCount = data.Length / blockSize; + int remainder = data.Length % blockSize; + + byte[] decryptedData = new byte[data.Length]; + + for (int i = 0; i < blockCount; i++) + { + byte[] block = new byte[blockSize]; + Array.Copy(data, i * blockSize, block, 0, blockSize); + DecryptBlock(key, block); + Array.Copy(block, 0, decryptedData, i * blockSize, blockSize); + } + + // If there is a remainder, pad the last block and decrypt + if (remainder > 0) + { + byte[] lastBlock = new byte[blockSize]; + Array.Copy(data, blockCount * blockSize, lastBlock, 0, remainder); + DecryptBlock(key, lastBlock); + Array.Copy(lastBlock, 0, decryptedData, blockCount * blockSize, remainder); + } + + return decryptedData; + } + + /// + /// XOR the block of data with key + /// + /// The secret key to use for the symmetric algorithm. + /// The block of data for XOR opration with secret key + /// Key and block must have the same length. + private void DecryptBlock(byte[] key, byte[] block) + { + // Ensure that the key and block have the same length + if (key.Length != block.Length) + { + throw new ArgumentException(); + } + + for (int i = 0; i < block.Length; i++) + { + block[i] = (byte)(block[i] ^ key[i]); + } + } + } +} diff --git a/System.Security.Cryptography/System.Security.Cryptography.nfproj b/System.Security.Cryptography/System.Security.Cryptography.nfproj index 571e742..517abf6 100644 --- a/System.Security.Cryptography/System.Security.Cryptography.nfproj +++ b/System.Security.Cryptography/System.Security.Cryptography.nfproj @@ -43,6 +43,7 @@ + diff --git a/Tests/System.Security.CryptographyTests/AESTests.cs b/Tests/System.Security.CryptographyTests/AESTests.cs new file mode 100644 index 0000000..6ae86d1 --- /dev/null +++ b/Tests/System.Security.CryptographyTests/AESTests.cs @@ -0,0 +1,39 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) Microsoft Corporation. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +using nanoFramework.TestFramework; +using System.Security.Cryptography; + +namespace System.Security.CryptographyTests +{ + [TestClass] + public class AESTests + { + static byte[] cipherDataArray = new byte[] { 112, 15, 93, 166, 173, 66, 95, 251, 63, 172, 69, 69, 182, 109, 13, 93 }; + static byte[] clearDataArray = new byte[] { 78, 97, 110, 111, 102, 114, 97, 109, 101, 119, 111, 114, 107, 0, 0, 0 }; + static byte[] key = new byte[16] { 62, 110, 51, 201, 203, 48, 62, 150, 90, 219, 42, 55, 221, 109, 13, 93 }; + + [TestMethod] + public void TestAesECBEncryptionAndDecryption() + { + OutputHelper.WriteLine($"Test Case: ECB Encryption/Decryption"); + + AES aes = new AES(); + aes.Mode = CipherMode.ECB; + + byte[] clearTextByteArrayWithPadding = clearDataArray; + + // Encrypt the bytes + var enData = aes.Encrypt(key, clearTextByteArrayWithPadding); + CollectionAssert.AreEqual(cipherDataArray,enData); + + // Decrypt the bytes + var decryptedByteArray = aes.Decrypt(enData, key); + CollectionAssert.AreEqual(clearDataArray, decryptedByteArray); + + } + } +} diff --git a/Tests/System.Security.CryptographyTests/System.Security.CryptographyTests.nfproj b/Tests/System.Security.CryptographyTests/System.Security.CryptographyTests.nfproj index 1563c32..b5fc99b 100644 --- a/Tests/System.Security.CryptographyTests/System.Security.CryptographyTests.nfproj +++ b/Tests/System.Security.CryptographyTests/System.Security.CryptographyTests.nfproj @@ -27,6 +27,7 @@ $(SolutionDir)\.runsettings +