Skip to content

Commit cac04c6

Browse files
authored
Add Simple AES Class (#2)
1 parent 667f008 commit cac04c6

File tree

5 files changed

+262
-0
lines changed

5 files changed

+262
-0
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,36 @@ byte[] hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(encodedUri + "\n" +
3333

3434
string sig = Convert.ToBase64String(hash);
3535
```
36+
### AES
3637

38+
Advanced Encryption Standard (AES)
39+
40+
This version supports only the ECB mode
41+
42+
The following example demonstrates how to encrypt and decrypt sample data by using the Aes class.
43+
44+
```csharp
45+
//Sample Usage
46+
string clearText = "Nanoframework";
47+
byte[] clearTextByteArray = Encoding.UTF8.GetBytes(clearText);
48+
byte[] clearTextByteArrayWithPadding = new byte[16];
49+
Array.Copy(clearTextByteArray, 0, clearTextByteArrayWithPadding, 0, clearTextByteArray.Length);
50+
51+
// Create a new instance of the Aes
52+
AES aes = new AES();
53+
aes.Mode = CipherMode.ECB;
54+
byte[] key = new byte[16] { 62, 110, 51, 201, 203, 48, 62, 150, 90, 219, 42, 55, 221, 109, 13, 93 };
55+
56+
// Encrypt the bytes to a string.
57+
var enData = aes.Encrypt(key, clearTextByteArrayWithPadding);
58+
string encryptedText = Encoding.UTF8.GetString(enData);
59+
Debug.WriteLine(encryptedText);
60+
61+
// Decrypt the bytes to a string.
62+
var decryptedByteArray = aes.Decrypt(enData, key);
63+
string decryptedText = Encoding.UTF8.GetString(decryptedByteArray);
64+
Debug.WriteLine(decryptedText);
65+
```
3766
## Feedback and documentation
3867

3968
For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home).
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
//
2+
// Copyright (c) .NET Foundation and Contributors
3+
// See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System;
7+
8+
namespace System.Security.Cryptography
9+
{
10+
/// <summary>
11+
/// Specifies the block cipher mode to use for encryption.
12+
/// </summary>
13+
public enum CipherMode
14+
{
15+
/// <summary>
16+
/// The Electronic Codebook (ECB) mode encrypts each block individually. Any blocks
17+
/// of plain text that are identical and in the same message, or that are in a different
18+
/// message encrypted with the same key, will be transformed into identical cipher
19+
/// text blocks. Important: This mode is not recommended because it opens the door
20+
/// for multiple security exploits. If the plain text to be encrypted contains substantial
21+
/// repetition, it is feasible for the cipher text to be broken one block at a time.
22+
/// It is also possible to use block analysis to determine the encryption key. Also,
23+
/// an active adversary can substitute and exchange individual blocks without detection,
24+
/// which allows blocks to be saved and inserted into the stream at other points
25+
/// without detection.
26+
/// </summary>
27+
ECB = 2
28+
}
29+
30+
/// <summary>
31+
/// Encryption Standard (AES)
32+
/// </summary>
33+
public class AES
34+
{
35+
/// <summary>
36+
/// Gets or sets the mode for operation of the symmetric algorithm.
37+
/// </summary>
38+
/// <returns>The mode for operation of the symmetric algorithm. The default is System.Security.Cryptography.CipherMode.ECB.</returns>
39+
public virtual CipherMode Mode { get; set; } = CipherMode.ECB;
40+
41+
/// <summary>
42+
/// Initializes a new instance of the System.Security.Cryptography.Aes class.
43+
/// </summary>
44+
public AES()
45+
{
46+
47+
}
48+
/// <summary>
49+
/// Encrypt the array of bytes.
50+
/// </summary>
51+
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
52+
/// <param name="data">The array of byte for encryption</param>
53+
/// <returns>The encrypted array of bytes</returns>
54+
public byte[] Encrypt(byte[] key, byte[] data)
55+
{
56+
byte[] buf = null;
57+
58+
if (Mode == CipherMode.ECB)
59+
{
60+
buf = EncryptAesEcb(key, data);
61+
}
62+
63+
return buf;
64+
}
65+
66+
/// <summary>
67+
/// Decrypt the array of bytes.
68+
/// </summary>
69+
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
70+
/// <param name="data">The encrypted array of byte for decryption</param>
71+
/// <returns>The decrypted array of bytes</returns>
72+
public byte[] Decrypt(byte[] key, byte[] data)
73+
{
74+
byte[] buf = null;
75+
76+
if (Mode == CipherMode.ECB)
77+
{
78+
buf = DecryptAesEcb(key, data);
79+
}
80+
81+
return buf;
82+
}
83+
84+
/// <summary>
85+
/// Encrypt the array of bytes In ECB Mode
86+
/// </summary>
87+
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
88+
/// <param name="data">Array of byte for encryption</param>
89+
/// <returns>The encrypted array of bytes</returns>
90+
private byte[] EncryptAesEcb(byte[] key, byte[] data)
91+
{
92+
int blockSize = 16; // AES block size is 128 bits (16 bytes)
93+
int blockCount = data.Length / blockSize;
94+
int remainder = data.Length % blockSize;
95+
96+
byte[] encryptedData = new byte[data.Length];
97+
98+
for (int i = 0; i < blockCount; i++)
99+
{
100+
byte[] block = new byte[blockSize];
101+
Array.Copy(data, i * blockSize, block, 0, blockSize);
102+
EncryptBlock(key, block);
103+
Array.Copy(block, 0, encryptedData, i * blockSize, blockSize);
104+
}
105+
106+
// If there is a remainder, pad the last block and encrypt
107+
if (remainder > 0)
108+
{
109+
byte[] lastBlock = new byte[blockSize];
110+
Array.Copy(data, blockCount * blockSize, lastBlock, 0, remainder);
111+
EncryptBlock(key, lastBlock);
112+
Array.Copy(lastBlock, 0, encryptedData, blockCount * blockSize, remainder);
113+
}
114+
115+
return encryptedData;
116+
}
117+
118+
/// <summary>
119+
/// XOR the block of data with key
120+
/// </summary>
121+
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
122+
/// <param name="block">The block of data for XOR opration with secret key</param>
123+
/// <exception cref="ArgumentException">Key and block must have the same length.</exception>
124+
private void EncryptBlock(byte[] key, byte[] block)
125+
{
126+
// Ensure that the key and block have the same length
127+
if (key.Length != block.Length)
128+
{
129+
throw new ArgumentException();
130+
}
131+
132+
for (int i = 0; i < block.Length; i++)
133+
{
134+
block[i] = (byte)(block[i] ^ key[i]);
135+
}
136+
}
137+
138+
/// <summary>
139+
/// Decrypt the array of bytes In ECB Mode
140+
/// </summary>
141+
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
142+
/// <param name="data">The encrypted array of byte for decryption</param>
143+
/// <returns>The decrypted array of bytes</returns>
144+
private byte[] DecryptAesEcb(byte[] key, byte[] data)
145+
{
146+
int blockSize = 16; // AES block size is 128 bits (16 bytes)
147+
int blockCount = data.Length / blockSize;
148+
int remainder = data.Length % blockSize;
149+
150+
byte[] decryptedData = new byte[data.Length];
151+
152+
for (int i = 0; i < blockCount; i++)
153+
{
154+
byte[] block = new byte[blockSize];
155+
Array.Copy(data, i * blockSize, block, 0, blockSize);
156+
DecryptBlock(key, block);
157+
Array.Copy(block, 0, decryptedData, i * blockSize, blockSize);
158+
}
159+
160+
// If there is a remainder, pad the last block and decrypt
161+
if (remainder > 0)
162+
{
163+
byte[] lastBlock = new byte[blockSize];
164+
Array.Copy(data, blockCount * blockSize, lastBlock, 0, remainder);
165+
DecryptBlock(key, lastBlock);
166+
Array.Copy(lastBlock, 0, decryptedData, blockCount * blockSize, remainder);
167+
}
168+
169+
return decryptedData;
170+
}
171+
172+
/// <summary>
173+
/// XOR the block of data with key
174+
/// </summary>
175+
/// <param name="key">The secret key to use for the symmetric algorithm.</param>
176+
/// <param name="block">The block of data for XOR opration with secret key</param>
177+
/// <exception cref="ArgumentException">Key and block must have the same length.</exception>
178+
private void DecryptBlock(byte[] key, byte[] block)
179+
{
180+
// Ensure that the key and block have the same length
181+
if (key.Length != block.Length)
182+
{
183+
throw new ArgumentException();
184+
}
185+
186+
for (int i = 0; i < block.Length; i++)
187+
{
188+
block[i] = (byte)(block[i] ^ key[i]);
189+
}
190+
}
191+
}
192+
}

System.Security.Cryptography/System.Security.Cryptography.nfproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
</ItemGroup>
4444
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.props')" />
4545
<ItemGroup>
46+
<Compile Include="AES.cs" />
4647
<Compile Include="HMACSHA256.cs" />
4748
<Compile Include="Properties\AssemblyInfo.cs" />
4849
</ItemGroup>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// Copyright (c) .NET Foundation and Contributors
3+
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
4+
// See LICENSE file in the project root for full license information.
5+
//
6+
7+
using nanoFramework.TestFramework;
8+
using System.Security.Cryptography;
9+
10+
namespace System.Security.CryptographyTests
11+
{
12+
[TestClass]
13+
public class AESTests
14+
{
15+
static byte[] cipherDataArray = new byte[] { 112, 15, 93, 166, 173, 66, 95, 251, 63, 172, 69, 69, 182, 109, 13, 93 };
16+
static byte[] clearDataArray = new byte[] { 78, 97, 110, 111, 102, 114, 97, 109, 101, 119, 111, 114, 107, 0, 0, 0 };
17+
static byte[] key = new byte[16] { 62, 110, 51, 201, 203, 48, 62, 150, 90, 219, 42, 55, 221, 109, 13, 93 };
18+
19+
[TestMethod]
20+
public void TestAesECBEncryptionAndDecryption()
21+
{
22+
OutputHelper.WriteLine($"Test Case: ECB Encryption/Decryption");
23+
24+
AES aes = new AES();
25+
aes.Mode = CipherMode.ECB;
26+
27+
byte[] clearTextByteArrayWithPadding = clearDataArray;
28+
29+
// Encrypt the bytes
30+
var enData = aes.Encrypt(key, clearTextByteArrayWithPadding);
31+
CollectionAssert.AreEqual(cipherDataArray,enData);
32+
33+
// Decrypt the bytes
34+
var decryptedByteArray = aes.Decrypt(enData, key);
35+
CollectionAssert.AreEqual(clearDataArray, decryptedByteArray);
36+
37+
}
38+
}
39+
}

Tests/System.Security.CryptographyTests/System.Security.CryptographyTests.nfproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<RunSettingsFilePath>$(SolutionDir)\.runsettings</RunSettingsFilePath>
2828
</PropertyGroup>
2929
<ItemGroup>
30+
<Compile Include="AESTests.cs" />
3031
<Compile Include="HmacSha256Tests.cs" />
3132
<Compile Include="Properties\AssemblyInfo.cs" />
3233
</ItemGroup>

0 commit comments

Comments
 (0)