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