Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
192 changes: 192 additions & 0 deletions System.Security.Cryptography/Aes.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Specifies the block cipher mode to use for encryption.
/// </summary>
public enum CipherMode
{
/// <summary>
/// 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.
/// </summary>
ECB = 2
}

/// <summary>
/// Encryption Standard (AES)
/// </summary>
public class AES
{
/// <summary>
/// Gets or sets the mode for operation of the symmetric algorithm.
/// </summary>
/// <returns>The mode for operation of the symmetric algorithm. The default is System.Security.Cryptography.CipherMode.ECB.</returns>
public virtual CipherMode Mode { get; set; } = CipherMode.ECB;

/// <summary>
/// Initializes a new instance of the System.Security.Cryptography.Aes class.
/// </summary>
public AES()
{

}
/// <summary>
/// Encrypt the array of bytes.
/// </summary>
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
/// <param name="data">The array of byte for encryption</param>
/// <returns>The encrypted array of bytes</returns>
public byte[] Encrypt(byte[] key, byte[] data)
{
byte[] buf = null;

if (Mode == CipherMode.ECB)
{
buf = EncryptAesEcb(key, data);
}

return buf;
}

/// <summary>
/// Decrypt the array of bytes.
/// </summary>
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
/// <param name="data">The encrypted array of byte for decryption</param>
/// <returns>The decrypted array of bytes</returns>
public byte[] Decrypt(byte[] key, byte[] data)
{
byte[] buf = null;

if (Mode == CipherMode.ECB)
{
buf = DecryptAesEcb(key, data);
}

return buf;
}

/// <summary>
/// Encrypt the array of bytes In ECB Mode
/// </summary>
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
/// <param name="data">Array of byte for encryption</param>
/// <returns>The encrypted array of bytes</returns>
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;
}

/// <summary>
/// XOR the block of data with key
/// </summary>
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
/// <param name="block">The block of data for XOR opration with secret key</param>
/// <exception cref="ArgumentException">Key and block must have the same length.</exception>
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]);
}
}

/// <summary>
/// Decrypt the array of bytes In ECB Mode
/// </summary>
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
/// <param name="data">The encrypted array of byte for decryption</param>
/// <returns>The decrypted array of bytes</returns>
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;
}

/// <summary>
/// XOR the block of data with key
/// </summary>
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
/// <param name="block">The block of data for XOR opration with secret key</param>
/// <exception cref="ArgumentException">Key and block must have the same length.</exception>
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]);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
</ItemGroup>
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.props')" />
<ItemGroup>
<Compile Include="AES.cs" />
<Compile Include="HMACSHA256.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
Expand Down
39 changes: 39 additions & 0 deletions Tests/System.Security.CryptographyTests/AESTests.cs
Original file line number Diff line number Diff line change
@@ -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);

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<RunSettingsFilePath>$(SolutionDir)\.runsettings</RunSettingsFilePath>
</PropertyGroup>
<ItemGroup>
<Compile Include="AESTests.cs" />
<Compile Include="HmacSha256Tests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
Expand Down