1 //
2 // Copyright (c) 2010-2021 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Security.Cryptography;
9 
10 namespace Antmicro.Renode.Utilities.Crypto
11 {
12     public class AesProvider : IDisposable
13     {
GetCbcMacProvider(byte[] key)14         public static AesProvider GetCbcMacProvider(byte[] key)
15         {
16             // CBC-MAC is just CBC with empty IV (all zeros)
17             return new AesProvider(CipherMode.CBC, PaddingMode.Zeros, key, new byte[AesBlockSizeInBytes]);
18         }
19 
GetEcbProvider(byte[] key)20         public static AesProvider GetEcbProvider(byte[] key)
21         {
22             // ECB does not use IV at all
23             return new AesProvider(CipherMode.ECB, PaddingMode.Zeros, key);
24         }
25 
GetCbcProvider(byte[] key, byte[] iv)26         public static AesProvider GetCbcProvider(byte[] key, byte[] iv)
27         {
28             return new AesProvider(CipherMode.CBC, PaddingMode.None, key, iv);
29         }
30 
AesProvider(CipherMode mode, PaddingMode padding, byte[] key, byte[] iv = null)31         public AesProvider(CipherMode mode, PaddingMode padding, byte[] key, byte[] iv = null)
32         {
33             aesEngine = Aes.Create();
34             aesEngine.Mode = mode;
35             aesEngine.Padding = padding;
36             lastBlock = Block.OfSize(AesBlockSizeInBytes);
37 
38             this.key = key;
39             this.iv = iv;
40         }
41 
Dispose()42         public void Dispose()
43         {
44             if(encryptor != null)
45             {
46                 encryptor.Dispose();
47             }
48             if(decryptor != null)
49             {
50                 decryptor.Dispose();
51             }
52             aesEngine.Dispose();
53         }
54 
EncryptBlockInSitu(Block b)55         public void EncryptBlockInSitu(Block b)
56         {
57             EncryptBlock(b, b);
58         }
59 
EncryptBlock(Block b, Block result)60         public void EncryptBlock(Block b, Block result)
61         {
62             if(encryptor == null)
63             {
64                 encryptor = aesEngine.CreateEncryptor(key, iv);
65             }
66 
67             encryptor.TransformBlock(b.Buffer, 0, b.Buffer.Length, result.Buffer, 0);
68             lastBlock.CopyFrom(result);
69         }
70 
DecryptBlockInSitu(Block b)71         public void DecryptBlockInSitu(Block b)
72         {
73             DecryptBlock(b, b);
74         }
75 
DecryptBlock(Block b, Block result)76         public void DecryptBlock(Block b, Block result)
77         {
78             if(decryptor == null)
79             {
80                 decryptor = aesEngine.CreateDecryptor(key, iv);
81             }
82 
83             decryptor.TransformBlock(b.Buffer, 0, b.Buffer.Length, result.Buffer, 0);
84             lastBlock.CopyFrom(result);
85         }
86 
87         public Block LastBlock { get { return lastBlock; } }
88 
89         private ICryptoTransform encryptor;
90         private ICryptoTransform decryptor;
91 
92         private readonly Block lastBlock;
93         private readonly Aes aesEngine;
94         private readonly byte[] key;
95         private readonly byte[] iv;
96 
97         private const int AesBlockSizeInBytes = 16;
98     }
99 
100     public class Block
101     {
WithCopiedBytes(byte[] bytes)102         public static Block WithCopiedBytes(byte[] bytes)
103         {
104             var result = new Block(bytes.Length);
105             result.UpdateBytes(bytes);
106             return result;
107         }
108 
UsingBytes(byte[] bytes)109         public static Block UsingBytes(byte[] bytes)
110         {
111             return new Block(bytes);
112         }
113 
OfSize(int size)114         public static Block OfSize(int size)
115         {
116             return new Block(size);
117         }
118 
UpdateByte(byte b)119         public void UpdateByte(byte b)
120         {
121             buffer[Index++] = b;
122         }
123 
XorWith(Block b)124         public Block XorWith(Block b)
125         {
126             for(int i = 0; i < Math.Min(buffer.Length, b.buffer.Length); i++)
127             {
128                 buffer[i] = (byte)(buffer[i] ^ b.buffer[i]);
129             }
130 
131             return this;
132         }
133 
UpdateBytes(byte[] bytes, int offset = 0, int length = -1)134         public void UpdateBytes(byte[] bytes, int offset = 0, int length = -1)
135         {
136             if(length == -1)
137             {
138                 length = bytes.Length - offset;
139             }
140 
141             Array.Copy(bytes, offset, buffer, Index, length);
142             Index += length;
143         }
144 
PadSpaceLeft(byte value)145         public void PadSpaceLeft(byte value)
146         {
147             for(int i = Index; i < buffer.Length; i++)
148             {
149                 buffer[i] = value;
150             }
151             Index = buffer.Length;
152         }
153 
CopyTo(byte[] buffer)154         public void CopyTo(byte[] buffer)
155         {
156             this.buffer.CopyTo(buffer, 0);
157         }
158 
CopyFrom(Block b)159         public void CopyFrom(Block b)
160         {
161             b.buffer.CopyTo(buffer, 0);
162             Index = b.Index;
163         }
164 
165         public int SpaceLeft { get { return buffer.Length - Index; } }
166         public byte[] Buffer { get { return buffer; } }
167         public int Index { get; set; }
168 
Block(byte[] buffer)169         private Block(byte[] buffer)
170         {
171             this.buffer = buffer;
172         }
173 
Block(int size)174         private Block(int size)
175         {
176             buffer = new byte[size];
177         }
178 
179         protected readonly byte[] buffer;
180     }
181 }
182