Skip to content

Commit 96a2719

Browse files
authored
Move AES ECB implementation to native (#5)
1 parent cac04c6 commit 96a2719

File tree

8 files changed

+240
-197
lines changed

8 files changed

+240
-197
lines changed

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ This repository contains the nanoFramework System.Security.Cryptography class li
1616

1717
## System.Security.Cryptography usage
1818

19-
This library brings to .NET nanoFramework C# applications the equivalent implementations provided by Mbed TLS. The target there the code is going to be deployed has to have a firmware image built with this namespace enabled.
19+
This library brings to .NET nanoFramework C# applications the equivalent implementations provided by Mbed TLS. The target there the code is going to be deployed has to have a firmware image built with this namespace enabled.
2020

2121
### HMAC SHA256
2222

@@ -33,25 +33,30 @@ byte[] hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(encodedUri + "\n" +
3333

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

3839
Advanced Encryption Standard (AES)
3940

40-
This version supports only the ECB mode
41+
[AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) is a variant of the Rijndael block cipher with different key and block sizes. For AES, NIST selected three members of the Rijndael family, each with a block size of 128 bits, but three different key lengths: 128, 192 and 256 bits.
42+
43+
The current version has support for the ECB mode. Others will be added.
44+
The following example demonstrates how to encrypt and decrypt sample data by using the AES class.
4145

42-
The following example demonstrates how to encrypt and decrypt sample data by using the Aes class.
46+
Note that the input data has to be multiple of 16 bits, otherwise an exception will be thrown.
47+
Data shorter than that should be padded with zeros.
4348

4449
```csharp
4550
//Sample Usage
4651
string clearText = "Nanoframework";
4752
byte[] clearTextByteArray = Encoding.UTF8.GetBytes(clearText);
53+
// please note the array size: 16 bytes
4854
byte[] clearTextByteArrayWithPadding = new byte[16];
4955
Array.Copy(clearTextByteArray, 0, clearTextByteArrayWithPadding, 0, clearTextByteArray.Length);
5056

5157
// 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 };
58+
AES aes = new AES(CipherMode.ECB);
59+
aes.Key = new byte[16] { 198, 49, 248, 31, 20, 7, 226, 232, 208, 100, 15, 11, 2, 32, 213, 243 };
5560

5661
// Encrypt the bytes to a string.
5762
var enData = aes.Encrypt(key, clearTextByteArrayWithPadding);
@@ -63,6 +68,7 @@ var decryptedByteArray = aes.Decrypt(enData, key);
6368
string decryptedText = Encoding.UTF8.GetString(decryptedByteArray);
6469
Debug.WriteLine(decryptedText);
6570
```
71+
6672
## Feedback and documentation
6773

6874
For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home).

System.Security.Cryptography/Aes.cs

Lines changed: 38 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -3,190 +3,79 @@
33
// See LICENSE file in the project root for full license information.
44
//
55

6-
using System;
6+
using System.Runtime.CompilerServices;
77

88
namespace System.Security.Cryptography
99
{
1010
/// <summary>
11-
/// Specifies the block cipher mode to use for encryption.
11+
/// Provides an Advanced Encryption Standard (AES) algorithm to encrypt and decrypt data.
1212
/// </summary>
13-
public enum CipherMode
13+
public class Aes
1414
{
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-
}
15+
private CipherMode _mode;
16+
private byte[] _key;
2917

30-
/// <summary>
31-
/// Encryption Standard (AES)
32-
/// </summary>
33-
public class AES
34-
{
3518
/// <summary>
3619
/// Gets or sets the mode for operation of the symmetric algorithm.
3720
/// </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-
}
21+
/// <value>The mode for operation of the symmetric algorithm.</value>
22+
public CipherMode Mode { get => _mode; set => _mode = value; }
6523

6624
/// <summary>
67-
/// Decrypt the array of bytes.
25+
/// Gets or sets the secret key for the symmetric algorithm.
6826
/// </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-
}
27+
/// <value>The secret key for the symmetric algorithm.</value>
28+
public byte[] Key { get => _key; set => _key = value; }
8329

8430
/// <summary>
85-
/// Encrypt the array of bytes In ECB Mode
31+
/// Initializes a new instance of the <see cref="Aes"/> class.
8632
/// </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)
33+
/// <remarks>
34+
/// This implementation of the AES is specific to .NET nanoFramework.
35+
/// </remarks>
36+
public Aes(CipherMode mode)
9137
{
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;
38+
Mode = mode;
11639
}
11740

11841
/// <summary>
119-
/// XOR the block of data with key
42+
/// Encrypts data using the cipher specified in <see cref="Mode"/>.
12043
/// </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)
44+
/// <param name="data">The data to encrypt.</param>
45+
/// <returns>The encrypted ciphertext data.</returns>
46+
/// <exception cref="InvalidOperationException">If the <see cref="Key"/> hasn't been set.</exception>
47+
/// <exception cref="ArgumentException">If the data in not a multiple of the block size (16 bytes for AES).</exception>
48+
public byte[] Encrypt(byte[] data)
12549
{
126-
// Ensure that the key and block have the same length
127-
if (key.Length != block.Length)
50+
if (Mode == CipherMode.ECB)
12851
{
129-
throw new ArgumentException();
52+
return EncryptAesEcb(data);
13053
}
13154

132-
for (int i = 0; i < block.Length; i++)
133-
{
134-
block[i] = (byte)(block[i] ^ key[i]);
135-
}
55+
throw new NotSupportedException();
13656
}
13757

13858
/// <summary>
139-
/// Decrypt the array of bytes In ECB Mode
59+
/// Decrypts data using cipher specified in <see cref="Mode"/>.
14060
/// </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)
61+
/// <param name="data">The data to decrypt.</param>
62+
/// <returns>The decrypted plaintext data.</returns>
63+
/// <exception cref="InvalidOperationException">If the <see cref="Key"/> hasn't been set.</exception>
64+
/// <exception cref="ArgumentException">If the data in not a multiple of the block size (16 bytes for AES).</exception>
65+
public byte[] Decrypt(byte[] data)
14566
{
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)
67+
if (Mode == CipherMode.ECB)
16268
{
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);
69+
return DecryptAesEcb(data);
16770
}
16871

169-
return decryptedData;
72+
throw new NotSupportedException();
17073
}
17174

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-
}
75+
[MethodImpl(MethodImplOptions.InternalCall)]
76+
private extern byte[] EncryptAesEcb(byte[] data);
18577

186-
for (int i = 0; i < block.Length; i++)
187-
{
188-
block[i] = (byte)(block[i] ^ key[i]);
189-
}
190-
}
78+
[MethodImpl(MethodImplOptions.InternalCall)]
79+
private extern byte[] DecryptAesEcb(byte[] data);
19180
}
19281
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//
2+
// Copyright (c) .NET Foundation and Contributors
3+
// See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace System.Security.Cryptography
7+
{
8+
/// <summary>
9+
/// Specifies the block cipher mode to use for encryption.
10+
/// </summary>
11+
public enum CipherMode
12+
{
13+
/// <summary>
14+
/// No cipher mode set.
15+
/// </summary>
16+
None = 0,
17+
18+
/// <summary>
19+
/// The Electronic Codebook (ECB) mode encrypts each block individually. Any blocks
20+
/// of plain text that are identical and in the same message, or that are in a different
21+
/// message encrypted with the same key, will be transformed into identical cipher
22+
/// text blocks. **Important:** This mode is not recommended because it opens the door
23+
/// for multiple security exploits. If the plain text to be encrypted contains substantial
24+
/// repetition, it is feasible for the cipher text to be broken one block at a time.
25+
/// It is also possible to use block analysis to determine the encryption key. Also,
26+
/// an active adversary can substitute and exchange individual blocks without detection,
27+
/// which allows blocks to be saved and inserted into the stream at other points
28+
/// without detection.
29+
/// </summary>
30+
ECB = 2
31+
}
32+
}

System.Security.Cryptography/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@
1616

1717
////////////////////////////////////////////////////////////////
1818
// update this whenever the native assembly signature changes //
19-
[assembly: AssemblyNativeVersion("100.0.0.1")]
19+
[assembly: AssemblyNativeVersion("100.0.0.2")]
2020
////////////////////////////////////////////////////////////////

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
</ItemGroup>
4444
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.props')" />
4545
<ItemGroup>
46-
<Compile Include="AES.cs" />
46+
<Compile Include="CipherMode.cs" />
47+
<Compile Include="Aes.cs" />
4748
<Compile Include="HMACSHA256.cs" />
4849
<Compile Include="Properties\AssemblyInfo.cs" />
4950
</ItemGroup>

Tests/System.Security.CryptographyTests/AESTests.cs

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)