1 //
2 // Copyright (c) 2010-2025 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 //
7 using Antmicro.Renode.Debugging;
8 using Antmicro.Renode.Logging;
9 using Antmicro.Renode.Peripherals.Bus;
10 using Antmicro.Renode.Utilities;
11 using System;
12 using System.IO;
13 using System.Security.Cryptography;
14 using System.Linq;
15 
16 namespace Antmicro.Renode.Peripherals.Miscellaneous.Crypto
17 {
18     public class AESServiceProvider
19     {
AESServiceProvider(InternalMemoryManager manager, IBusController bus)20         public AESServiceProvider(InternalMemoryManager manager, IBusController bus)
21         {
22             this.manager = manager;
23             this.bus = bus;
24 
25             segment = new byte[SegmentSize];
26         }
27 
PerformAESOperation()28         public void PerformAESOperation()
29         {
30             manager.TryReadDoubleWord((long)AESRegisters.SegmentCount, out var segmentCount);
31             manager.TryReadDoubleWord((long)AESRegisters.IterationCount, out var iterationCount);
32 
33             var keyByteCount = 0;
34             switch(iterationCount)
35             {
36                 case (uint)IterationCount.AES128:
37                     keyByteCount = KeyLengthByteCountAES128;
38                     break;
39                 case (uint)IterationCount.AES192:
40                 case (uint)IterationCount.AES256:
41                     keyByteCount = KeyLengthByteCountAES256;
42                     break;
43                 default:
44                     Logger.Log(LogLevel.Error, "Encountered unsupported number of iterations, falling back to default key size for AES128.");
45                     keyByteCount = KeyLengthByteCountAES128;
46                     break;
47             }
48 
49             manager.TryReadBytes((long)AESRegisters.Key, keyByteCount, out var keyBytes);
50             manager.TryReadBytes((long)AESRegisters.InitVector, InitializationVectorByteCount, out var ivBytes);
51             manager.TryReadBytes((long)AESRegisters.InputData, (SegmentSize * (int)segmentCount), out var inputBytes);
52 
53             manager.TryReadDoubleWord((long)AESRegisters.Config, out var config);
54             var operation = BitHelper.IsBitSet(config, 0)
55                     ? Operation.Decryption
56                     : Operation.Encryption;
57 
58             var result = GetResultBytesCBC(keyBytes, ivBytes, inputBytes, operation);
59             manager.TryWriteBytes((long)AESRegisters.Cipher, result);
60         }
61 
PerformAESOperationDMA()62         public void PerformAESOperationDMA()
63         {
64             manager.TryReadDoubleWord((long)AESRegisters.SegmentCount, out var segmentCount);
65             manager.TryReadBytes((long)AESRegisters.Key, KeyLengthByteCountAES256, out var keyBytes);
66             manager.TryReadBytes((long)AESRegisters.InitVectorDMA, InitializationVectorByteCount, out var ivBytes);
67             manager.TryReadDoubleWord((long)AESRegisters.InputDataAddrDMA, out var inputDataAddr);
68             manager.TryReadDoubleWord((long)AESRegisters.ResultDataAddrDMA, out var resultDataAddr);
69             manager.TryReadDoubleWord((long)AESRegisters.ConfigDMA, out var config);
70             var operation = BitHelper.IsBitSet(config, 0)
71                     ? Operation.Decryption
72                     : Operation.Encryption;
73             var mode = BitHelper.IsBitSet(config, 3)
74                     ? Mode.CTR
75                     : Mode.CBC;
76             var inputBytes = bus.ReadBytes(inputDataAddr, SegmentSize);
77             switch(mode)
78             {
79                 case Mode.CTR:
80                     bus.WriteBytes(GetResultBytesCTR(keyBytes, ivBytes, inputBytes, operation), resultDataAddr);
81                     break;
82                 default:
83                     bus.WriteBytes(GetResultBytesCBC(keyBytes, ivBytes, inputBytes, operation), resultDataAddr);
84                     break;
85             }
86         }
87 
Reset()88         public void Reset()
89         {
90             manager.ResetMemories();
91             segment = new byte[SegmentSize];
92         }
93 
GetResultBytesCTR(byte[] keyBytes, byte[] ivBytes, byte[] inputBytes, Operation operation)94         private byte[] GetResultBytesCTR(byte[] keyBytes, byte[] ivBytes, byte[] inputBytes, Operation operation)
95         {
96             DebugHelper.Assert(keyBytes.Length >= SegmentSize, "Length of key bytes should at least ${SegmentSize}");
97             DebugHelper.Assert(inputBytes.Length >= SegmentSize, "Length of input bytes should at least ${SegmentSize}");
98             DebugHelper.Assert(inputBytes.Length % SegmentSize == 0, "Length of input bytes should be a multiple of ${SegmentSize}");
99             var segment = ProcessSegment(keyBytes.Take(SegmentSize).ToArray(), ivBytes, new byte[SegmentSize], operation);
100             for(var i = 0; i < segment.Length; ++i)
101             {
102                 segment[i] ^= inputBytes[i];
103             }
104             return segment;
105         }
106 
GetResultBytesCBC(byte[] keyBytes, byte[] ivBytes, byte[] inputBytes, Operation operation)107         private byte[] GetResultBytesCBC(byte[] keyBytes, byte[] ivBytes, byte[] inputBytes, Operation operation)
108         {
109             var inputSegment = new byte[SegmentSize];
110             var result = new byte[SegmentSize];
111 
112             DebugHelper.Assert(inputBytes.Length % SegmentSize == 0, "Length of input bytes should be a multiple of ${SegmentSize}");
113             var segmentCount = inputBytes.Length / SegmentSize;
114             for(var i = 0; i < segmentCount; ++i)
115             {
116                 Array.Copy(inputBytes, (i * SegmentSize), inputSegment, 0, SegmentSize);
117                 for(var j = 0; j < SegmentSize; ++j)
118                 {
119                     inputSegment[j] ^= segment[j];
120                 }
121 
122                 segment = ProcessSegment(keyBytes, ivBytes, inputSegment, operation);
123             }
124             Array.Copy(segment, 0, result, 0, SegmentSize);
125 
126             if(segmentCount == 1)
127             {
128                 segment = new byte[SegmentSize];
129             }
130             return result;
131         }
132 
ProcessSegment(byte[] keyBytes, byte[] ivBytes, byte[] inputBytes, Operation operation)133         private byte[] ProcessSegment(byte[] keyBytes, byte[] ivBytes, byte[] inputBytes, Operation operation)
134         {
135             return operation == Operation.Encryption
136                 ? Encrypt(keyBytes, ivBytes, inputBytes)
137                 : Decrypt(keyBytes, ivBytes, inputBytes);
138         }
139 
Encrypt(byte[] key, byte[] iv, byte[] input)140         private byte[] Encrypt(byte[] key, byte[] iv, byte[] input)
141         {
142             using(var ms = new MemoryStream())
143             using(var aes = Aes.Create())
144             {
145                 aes.Padding = PaddingMode.None;
146                 aes.Key = key;
147                 aes.IV = iv;
148                 using(var cs = new CryptoStream(ms, aes.CreateEncryptor(key, iv), CryptoStreamMode.Write))
149                 {
150                     cs.Write(input, 0, input.Length);
151                     cs.FlushFinalBlock();
152                     return ms.ToArray();
153                 }
154             }
155         }
156 
Decrypt(byte[] key, byte[] iv, byte[] input)157         private byte[] Decrypt(byte[] key, byte[] iv, byte[] input)
158         {
159             using(var aes = Aes.Create())
160             {
161                 aes.Padding = PaddingMode.None;
162                 using(var decryptor = aes.CreateDecryptor(key, iv))
163                 {
164                     return decryptor.TransformFinalBlock(input, 0, input.Length);
165                 }
166             }
167         }
168 
169         private byte[] segment;
170 
171         private readonly IBusController bus;
172         private readonly InternalMemoryManager manager;
173 
174         // These values are taken directly from the driver because they are not written to the internal memories
175         private const int KeyLengthByteCountAES256 = 32;
176         private const int KeyLengthByteCountAES128 = 16;
177         private const int InitializationVectorByteCount = 16;
178         private const int SegmentSize = 16;
179 
180         private enum IterationCount
181         {
182             AES128 = 10,
183             AES192 = 12,
184             AES256 = 14
185         }
186 
187         private enum Operation
188         {
189             Encryption,
190             Decryption
191         }
192 
193         private enum Mode
194         {
195             CBC,
196             CTR
197         }
198 
199         private enum AESRegisters
200         {
201             SegmentCount = 0x8,
202             IterationCount = 0xC,
203             Config = 0x20,
204             InputDataAddrDMA = 0x28,
205             ResultDataAddrDMA = 0x2C,
206             ConfigDMA = 0x3C,
207             InitVector = 0x8024,
208             InitVectorDMA = 0x8040,
209             Cipher = 0x8048,
210             InputData = 0x8058,
211             Key = 0x9000,
212         }
213     }
214 }
215