1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // Copyright (c) 2022-2025 Silicon Labs 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 9 using System; 10 using System.Collections.Generic; 11 using System.IO; 12 using Antmicro.Renode.Core; 13 using Antmicro.Renode.Core.Structure.Registers; 14 using Antmicro.Renode.Exceptions; 15 using Antmicro.Renode.Logging; 16 using Antmicro.Renode.Peripherals.Bus; 17 using Antmicro.Renode.Peripherals.Timers; 18 using Antmicro.Renode.Time; 19 using Org.BouncyCastle.Crypto; 20 using Org.BouncyCastle.Crypto.Engines; 21 using Org.BouncyCastle.Crypto.Modes; 22 using Org.BouncyCastle.Crypto.Parameters; 23 24 namespace Antmicro.Renode.Peripherals.Miscellaneous.SiLabs 25 { 26 public class EFR32xG2_AES_1 : IDoubleWordPeripheral, IKnownSize 27 { EFR32xG2_AES_1(Machine machine)28 public EFR32xG2_AES_1(Machine machine) 29 { 30 this.machine = machine; 31 32 IRQ = new GPIO(); 33 registersCollection = BuildRegistersCollection(); 34 } 35 Reset()36 public void Reset() 37 { 38 } 39 ReadDoubleWord(long offset)40 public uint ReadDoubleWord(long offset) 41 { 42 var result = 0U; 43 if(!registersCollection.TryRead(offset, out result)) 44 { 45 this.Log(LogLevel.Noisy, "Unhandled read at offset 0x{0:X} ({1}).", offset, (Registers)offset); 46 } 47 else 48 { 49 this.Log(LogLevel.Noisy, "Read at offset 0x{0:X} ({1}), returned 0x{2:X}.", offset, (Registers)offset, result); 50 } 51 return result; 52 } 53 WriteDoubleWord(long offset, uint value)54 public void WriteDoubleWord(long offset, uint value) 55 { 56 this.Log(LogLevel.Noisy, "Write at offset 0x{0:X} ({1}), value 0x{2:X}.", offset, (Registers)offset, value); 57 if(!registersCollection.TryWrite(offset, value)) 58 { 59 this.Log(LogLevel.Noisy, "Unhandled write at offset 0x{0:X} ({1}), value 0x{2:X}.", offset, (Registers)offset, value); 60 return; 61 } 62 } 63 BuildRegistersCollection()64 private DoubleWordRegisterCollection BuildRegistersCollection() 65 { 66 var registerDictionary = new Dictionary<long, DoubleWordRegister> 67 { 68 {(long)Registers.FetcherAddress, new DoubleWordRegister(this) 69 .WithValueField(0, 32, out fetcherAddress, name: "ADDR") 70 }, 71 {(long)Registers.FetcherLength, new DoubleWordRegister(this) 72 .WithValueField(0, 28, out fetcherLength, name: "LENGTH") 73 .WithFlag(28, out fetcherConstantAddress, name: "CONSTADDR") 74 .WithFlag(29, out fetcherRealignLength, name: "REALIGN") 75 .WithReservedBits(30, 2) 76 }, 77 {(long)Registers.FetcherTag, new DoubleWordRegister(this) 78 .WithValueField(0, 32, out fetcherTag, name: "TAG") 79 }, 80 {(long)Registers.PusherAddress, new DoubleWordRegister(this) 81 .WithValueField(0, 32, out pusherAddress, name: "ADDR") 82 }, 83 {(long)Registers.PusherLength, new DoubleWordRegister(this) 84 .WithValueField(0, 28, out pusherLength, name: "LENGTH") 85 .WithFlag(28, out pusherConstantAddress, name: "CONSTADDR") 86 .WithFlag(29, out pusherRealignLength, name: "REALIGN") 87 .WithFlag(30, out pusherDiscardData, name: "DISCARD") 88 .WithReservedBits(31, 1) 89 }, 90 {(long)Registers.InterruptEnable, new DoubleWordRegister(this) 91 .WithFlag(0, out fetcherEndOfBlockInterruptEnable, name: "FETCHERENDOFBLOCKIEN") 92 .WithFlag(1, out fetcherStoppedInterruptEnable, name: "FETCHERSTOPPEDIEN") 93 .WithFlag(2, out fetcherErrorInterruptEnable, name: "FETCHERERRORIEN") 94 .WithFlag(3, out pusherEndOfBlockInterruptEnable, name: "PUSHERENDOFBLOCKIEN") 95 .WithFlag(4, out pusherStoppedInterruptEnable, name: "PUSHERSTOPPEDIEN") 96 .WithFlag(5, out pusherErrorInterruptEnable, name: "PUSHERERRORIEN") 97 .WithReservedBits(6, 26) 98 .WithWriteCallback((_, __) => UpdateInterrupts()) 99 }, 100 {(long)Registers.InterruptEnableSet, new DoubleWordRegister(this) 101 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => { if (value) fetcherEndOfBlockInterruptEnable.Value = true; }, name: "FETCHERENDOFBLOCKIENSET") 102 .WithFlag(1, FieldMode.Write, writeCallback: (_, value) => { if (value) fetcherStoppedInterruptEnable.Value = true; }, name: "FETCHERSTOPPEDIENSET") 103 .WithFlag(2, FieldMode.Write, writeCallback: (_, value) => { if (value) fetcherErrorInterruptEnable.Value = true; }, name: "FETCHERERRORIENSET") 104 .WithFlag(3, FieldMode.Write, writeCallback: (_, value) => { if (value) pusherEndOfBlockInterruptEnable.Value = true; }, name: "PUSHERENDOFBLOCKIENSET") 105 .WithFlag(4, FieldMode.Write, writeCallback: (_, value) => { if (value) pusherStoppedInterruptEnable.Value = true; }, name: "PUSHERSTOPPEDIENSET") 106 .WithFlag(5, FieldMode.Write, writeCallback: (_, value) => { if (value) pusherErrorInterruptEnable.Value = true; }, name: "PUSHERERRORIENSET") 107 .WithReservedBits(6, 26) 108 .WithWriteCallback((_, __) => UpdateInterrupts()) 109 }, 110 {(long)Registers.InterruptEnableClear, new DoubleWordRegister(this) 111 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => { if (value) fetcherEndOfBlockInterruptEnable.Value = false; }, name: "FETCHERENDOFBLOCKIENCLR") 112 .WithFlag(1, FieldMode.Write, writeCallback: (_, value) => { if (value) fetcherStoppedInterruptEnable.Value = false; }, name: "FETCHERSTOPPEDIENCLR") 113 .WithFlag(2, FieldMode.Write, writeCallback: (_, value) => { if (value) fetcherErrorInterruptEnable.Value = false; }, name: "FETCHERERRORIENCLR") 114 .WithFlag(3, FieldMode.Write, writeCallback: (_, value) => { if (value) pusherEndOfBlockInterruptEnable.Value = false; }, name: "PUSHERENDOFBLOCKIENCLR") 115 .WithFlag(4, FieldMode.Write, writeCallback: (_, value) => { if (value) pusherStoppedInterruptEnable.Value = false; }, name: "PUSHERSTOPPEDIENCLR") 116 .WithFlag(5, FieldMode.Write, writeCallback: (_, value) => { if (value) pusherErrorInterruptEnable.Value = false; }, name: "PUSHERERRORIENCLR") 117 .WithReservedBits(6, 26) 118 .WithWriteCallback((_, __) => UpdateInterrupts()) 119 }, 120 {(long)Registers.InterruptFlag, new DoubleWordRegister(this) 121 .WithFlag(0, out fetcherEndOfBlockInterrupt, FieldMode.Read, name: "FETCHERENDOFBLOCKIF") 122 .WithFlag(1, out fetcherStoppedInterrupt, FieldMode.Read, name: "FETCHERSTOPPEDIF") 123 .WithFlag(2, out fetcherErrorInterrupt, FieldMode.Read, name: "FETCHERERRORIF") 124 .WithFlag(3, out pusherEndOfBlockInterrupt, FieldMode.Read, name: "PUSHERENDOFBLOCKIF") 125 .WithFlag(4, out pusherStoppedInterrupt, FieldMode.Read, name: "PUSHERSTOPPEDIF") 126 .WithFlag(5, out pusherErrorInterrupt, FieldMode.Read, name: "PUSHERERRORIF") 127 .WithReservedBits(6, 26) 128 .WithWriteCallback((_, __) => UpdateInterrupts()) 129 }, 130 {(long)Registers.InterruptFlagMasked, new DoubleWordRegister(this) 131 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => (fetcherEndOfBlockInterrupt.Value && fetcherEndOfBlockInterruptEnable.Value), name: "FETCHERENDOFBLOCKIF") 132 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => (fetcherStoppedInterrupt.Value && fetcherStoppedInterruptEnable.Value), name: "FETCHERSTOPPEDIF") 133 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => (fetcherErrorInterrupt.Value && fetcherErrorInterruptEnable.Value), name: "FETCHERERRORIF") 134 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => (pusherEndOfBlockInterrupt.Value && pusherEndOfBlockInterruptEnable.Value), name: "PUSHERENDOFBLOCKIF") 135 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => (pusherStoppedInterrupt.Value && pusherStoppedInterruptEnable.Value), name: "PUSHERSTOPPEDIF") 136 .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => (pusherErrorInterrupt.Value && pusherErrorInterruptEnable.Value), name: "PUSHERERRORIF") 137 .WithReservedBits(6, 26) 138 .WithWriteCallback((_, __) => UpdateInterrupts()) 139 }, 140 {(long)Registers.InterruptFlagClear, new DoubleWordRegister(this) 141 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => { if (value) fetcherEndOfBlockInterrupt.Value = false; }, name: "FETCHERENDOFBLOCKIFCLR") 142 .WithFlag(1, FieldMode.Write, writeCallback: (_, value) => { if (value) fetcherStoppedInterrupt.Value = false; }, name: "FETCHERSTOPPEDIFCLR") 143 .WithFlag(2, FieldMode.Write, writeCallback: (_, value) => { if (value) fetcherErrorInterrupt.Value = false; }, name: "FETCHERERRORIFCLR") 144 .WithFlag(3, FieldMode.Write, writeCallback: (_, value) => { if (value) pusherEndOfBlockInterrupt.Value = false; }, name: "PUSHERENDOFBLOCKIFCLR") 145 .WithFlag(4, FieldMode.Write, writeCallback: (_, value) => { if (value) pusherStoppedInterrupt.Value = false; }, name: "PUSHERSTOPPEDIFCLR") 146 .WithFlag(5, FieldMode.Write, writeCallback: (_, value) => { if (value) pusherErrorInterrupt.Value = false; }, name: "PUSHERERRORIFCLR") 147 .WithReservedBits(6, 26) 148 .WithWriteCallback((_, __) => UpdateInterrupts()) 149 }, 150 {(long)Registers.Control, new DoubleWordRegister(this) 151 .WithFlag(0, out fetcherScatterGather, name: "FETCHERSCATTERGATHER") 152 .WithFlag(1, out pusherScatterGather, name: "PUSHERSCATTERGATHER") 153 .WithFlag(2, out fetcherStopAtEndOfBlock, name: "STOPFETCHER") 154 .WithFlag(3, out pusherStopAtEndOfBlock, name: "STOPPUSHER") 155 .WithTaggedFlag("SWRESET", 4) 156 .WithReservedBits(5, 27) 157 }, 158 {(long)Registers.Command, new DoubleWordRegister(this) 159 .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => { if (value) { StartFetcher(); } }, name: "STARTFETCHER") 160 .WithFlag(1, FieldMode.Write, writeCallback: (_, value) => { if (value) { StartPusher(); } }, name: "STARTPUSHER") 161 .WithReservedBits(2, 30) 162 }, 163 {(long)Registers.Status, new DoubleWordRegister(this) 164 .WithFlag(0, out fetcherBusy, FieldMode.Read, name: "FETCHERBSY") 165 .WithFlag(1, out pusherBusy, FieldMode.Read, name: "PUSHERBSY") 166 .WithReservedBits(2, 2) 167 .WithTaggedFlag("NOTEMPTY", 4) 168 .WithTaggedFlag("WAITING", 5) 169 .WithTaggedFlag("SOFTRSTBSY", 6) 170 .WithReservedBits(7, 9) 171 .WithTag("FIFODATANUM", 16, 16) 172 //.WithValueField(16, 16, FieldMode.Read, valueProviderCallback: _ => /* TODO */ 0, name: "FIFODATANUM") 173 }, 174 }; 175 return new DoubleWordRegisterCollection(this, registerDictionary); 176 } 177 178 public long Size => 0x4000; 179 public GPIO IRQ { get; } 180 private readonly Machine machine; 181 private readonly DoubleWordRegisterCollection registersCollection; 182 #region register fields 183 // Direct mode: written by SW (address of the first data) 184 // Scatter/gather mode: Written by SW (address of first descriptor). Afterwards, it is updated 185 // by the hardware after each processed descriptor. 186 private IValueRegisterField fetcherAddress; 187 // Direct mode: written by SW 188 // Scatter/gather mode: not used 189 private IValueRegisterField fetcherLength; 190 // Direct mode: written by SW 191 // Scatter/gather mode: not used 192 private IFlagRegisterField fetcherConstantAddress; 193 // Direct mode: written by SW 194 // Scatter/gather mode: not used 195 private IFlagRegisterField fetcherRealignLength; 196 // Direct mode: written by SW 197 // Scatter/gather mode: not used 198 private IValueRegisterField fetcherTag; 199 // When this bit is high, the fetcher will stop at the end of the current block 200 // (even if the STOP bit in the descriptor is low). 201 private IFlagRegisterField fetcherStopAtEndOfBlock; 202 // When this bit is zero, the fetcher runs in direct mode. 203 // When this bit is one, the fetcher runs in scatter-gather mode. 204 private IFlagRegisterField fetcherScatterGather; 205 // This bit is high as long as the fetcher is busy 206 private IFlagRegisterField fetcherBusy; 207 // Direct mode: written by SW (address of the first data) 208 // Scatter/gather mode: Written by SW (address of first descriptor). Afterwards, it is updated 209 // by the hardware after each processed descriptor. 210 private IValueRegisterField pusherAddress; 211 // Direct mode: written by SW 212 // Scatter/gather mode: not used 213 private IValueRegisterField pusherLength; 214 // Direct mode: written by SW 215 // Scatter/gather mode: not used 216 private IFlagRegisterField pusherConstantAddress; 217 // Direct mode: written by SW 218 // Scatter/gather mode: not used 219 private IFlagRegisterField pusherRealignLength; 220 // Direct mode: written by SW 221 // Scatter/gather mode: not used 222 private IFlagRegisterField pusherDiscardData; 223 // When this bit is high, the pusher will stop at the end of the current block 224 // (even if the STOP bit in the descriptor is low). 225 private IFlagRegisterField pusherStopAtEndOfBlock; 226 // When this bit is zero, the pusher runs in direct mode. 227 // When this bit is one, the pusher runs in scatter-gather mode. 228 private IFlagRegisterField pusherScatterGather; 229 // This bit is high as long as the pusher is busy 230 private IFlagRegisterField pusherBusy; 231 232 // Interrupt flags 233 private IFlagRegisterField fetcherEndOfBlockInterruptEnable; 234 private IFlagRegisterField fetcherStoppedInterruptEnable; 235 private IFlagRegisterField fetcherErrorInterruptEnable; 236 private IFlagRegisterField pusherEndOfBlockInterruptEnable; 237 private IFlagRegisterField pusherStoppedInterruptEnable; 238 private IFlagRegisterField pusherErrorInterruptEnable; 239 // Triggered at the end of each block (if enabled in the descriptor - scatter-gather only) 240 private IFlagRegisterField fetcherEndOfBlockInterrupt; 241 // Triggered when reaching a block with Stop=1 (or end of direct transfer) 242 private IFlagRegisterField fetcherStoppedInterrupt; 243 // Triggered when an error response is received from AXI 244 private IFlagRegisterField fetcherErrorInterrupt; 245 // Triggered at the end of each block (if enabled in the descriptor - scatter-gather only) 246 private IFlagRegisterField pusherEndOfBlockInterrupt; 247 // Triggered when reaching a block with Stop=1 (or end of direct transfer) 248 private IFlagRegisterField pusherStoppedInterrupt; 249 // Triggered when an error response is received from AXI 250 private IFlagRegisterField pusherErrorInterrupt; 251 #endregion 252 253 #region methods UpdateInterrupts()254 private void UpdateInterrupts() 255 { 256 machine.ClockSource.ExecuteInLock(delegate { 257 var irq = ((fetcherEndOfBlockInterruptEnable.Value && fetcherEndOfBlockInterrupt.Value) 258 || (fetcherStoppedInterruptEnable.Value || fetcherStoppedInterrupt.Value) 259 || (fetcherErrorInterruptEnable.Value || fetcherErrorInterrupt.Value) 260 || (pusherEndOfBlockInterruptEnable.Value && pusherEndOfBlockInterrupt.Value) 261 || (pusherStoppedInterruptEnable.Value || pusherStoppedInterrupt.Value) 262 || (pusherErrorInterruptEnable.Value || pusherErrorInterrupt.Value)); 263 IRQ.Set(irq); 264 }); 265 } 266 267 // Commmands StartFetcher()268 private void StartFetcher() 269 { 270 // TODO: for now we support only Scatter/Gather mode for both fetcher and pusher 271 if (!fetcherScatterGather.Value || !pusherScatterGather.Value) 272 { 273 this.Log(LogLevel.Error, "START_FETCHER: direct mode not supported"); 274 return; 275 } 276 277 fetcherBusy.Value = true; 278 pusherBusy.Value = true; 279 280 this.Log(LogLevel.Noisy, "FETCHER Descriptor(s):"); 281 List<DmaDescriptor> fetcherDescriptorList = ParseDescriptors(true); 282 this.Log(LogLevel.Noisy, "PUSHER Descriptor(s):"); 283 List<DmaDescriptor> pusherDescriptorList = ParseDescriptors(false); 284 285 switch(fetcherDescriptorList[0].EngineSelect) 286 { 287 case CryptoEngine.Aes: 288 RunAesEngine(fetcherDescriptorList, pusherDescriptorList); 289 break; 290 default: 291 this.Log(LogLevel.Error, "START_FETCHER: crypto engine not supported"); 292 return; 293 } 294 295 fetcherBusy.Value = false; 296 pusherBusy.Value = false; 297 298 // TODO: we might need to set some interrupt flags here. However, sl_radioaes driver does not make use of them. 299 300 UpdateInterrupts(); 301 } 302 StartPusher()303 private void StartPusher() 304 { 305 // Nothing to do here, the StartFetcher command already grabs the pusher descriptors and writes them. 306 } 307 ParseDescriptors(bool parseFetcher)308 private List<DmaDescriptor> ParseDescriptors(bool parseFetcher) 309 { 310 List<DmaDescriptor> list = new List<DmaDescriptor>(); 311 uint currentDescriptorAddress = (uint)((parseFetcher) ? fetcherAddress.Value : pusherAddress.Value); 312 bool moreDescriptors = true; 313 uint descriptorIndex = 0; 314 315 while(moreDescriptors) 316 { 317 DmaDescriptor descriptor = new DmaDescriptor(); 318 descriptor.FirstDataAddress = machine.SystemBus.ReadDoubleWord(currentDescriptorAddress); 319 descriptor.NextDescriptorAddress = machine.SystemBus.ReadDoubleWord(currentDescriptorAddress + 0x4); 320 descriptor.LastDescriptor = ((descriptor.NextDescriptorAddress & 0x1) > 0); 321 descriptor.NextDescriptorAddress &= ~0x3U; 322 descriptor.Length = machine.SystemBus.ReadDoubleWord(currentDescriptorAddress + 0x8); 323 descriptor.ConstantAddress = ((descriptor.Length & 0x10000000) > 0); 324 descriptor.Realign = ((descriptor.Length & 0x20000000) > 0); 325 if (parseFetcher) 326 { 327 descriptor.ZeroPadding = ((descriptor.Length & 0x40000000) > 0); 328 } 329 else 330 { 331 descriptor.Discard = ((descriptor.Length & 0x40000000) > 0); 332 } 333 descriptor.InterruptEnable = ((descriptor.Length & 0x80000000) > 0); 334 descriptor.Length &= 0x0FFFFFFF; 335 descriptor.Tag = (parseFetcher) ? machine.SystemBus.ReadDoubleWord(currentDescriptorAddress + 0xC) : 0; 336 descriptor.Data = new byte[descriptor.Length]; 337 for(uint i=0; i<descriptor.Length; i++) 338 { 339 // When the zero-padding bit is set, the fetcher generates zeroes instead of reading data from memory. 340 // For pusher, we always zero the data. 341 descriptor.Data[i] = (byte)((descriptor.ZeroPadding || !parseFetcher) ? 0 : machine.SystemBus.ReadByte(descriptor.FirstDataAddress + i)); 342 } 343 list.Add(descriptor); 344 345 this.Log(LogLevel.Noisy, "DESCRIPTOR {0}: Tag:{1:X} Length:{2} Last:{3} Const:{4} Realign:{5} ZeroPad:{6} IE:{7} Data:[{8}]", 346 descriptorIndex, descriptor.Tag, descriptor.Length, descriptor.LastDescriptor, descriptor.ConstantAddress, 347 descriptor.Realign, descriptor.ZeroPadding, descriptor.InterruptEnable, BitConverter.ToString(descriptor.Data)); 348 this.Log(LogLevel.Noisy, "COMMON: Engine:{0}, Last:{1}", descriptor.EngineSelect, descriptor.IsLastDataOrConfig); 349 if (parseFetcher) 350 { 351 if (descriptor.IsData) 352 { 353 this.Log(LogLevel.Noisy, "DATA: Type:{0}, Invalid Bytes/Bits:{1}", descriptor.DataType, descriptor.InvalidBytesOrBits); 354 } 355 else 356 { 357 this.Log(LogLevel.Noisy, "CONFIG: Offset:{0}", descriptor.OffsetStartAddress); 358 } 359 } 360 361 moreDescriptors = !descriptor.LastDescriptor; 362 // TODO: handle the realign bit set here 363 currentDescriptorAddress = descriptor.NextDescriptorAddress; 364 descriptorIndex++; 365 366 // In scatter/gather node, the hardware updates the fetchAddress after each processed descriptor 367 // unless the constant address flag is set. 368 if (parseFetcher && fetcherScatterGather.Value && moreDescriptors && !descriptor.ConstantAddress) 369 { 370 fetcherAddress.Value = currentDescriptorAddress; 371 } 372 } 373 return list; 374 } 375 RunAesEngine(List<DmaDescriptor> fetcherDescriptorList, List<DmaDescriptor> pusherDescriptorList)376 void RunAesEngine(List<DmaDescriptor> fetcherDescriptorList, List<DmaDescriptor> pusherDescriptorList) 377 { 378 int configDescriptorIndex = -1; 379 int keyDescriptorIndex = -1; 380 int key2DescriptorIndex = -1; 381 int inputTextDescriptorIndex = -1; 382 int ivDescriptorIndex = -1; 383 int iv2DescriptorIndex = -1; 384 for(int i=0; i<fetcherDescriptorList.Count; i++) 385 { 386 if (fetcherDescriptorList[i].IsData && fetcherDescriptorList[i].DataType == CryptoDataType.Payload) 387 { 388 inputTextDescriptorIndex = i; 389 } 390 else if (fetcherDescriptorList[i].IsConfig && fetcherDescriptorList[i].OffsetStartAddress == 0x8) 391 { 392 keyDescriptorIndex = i; 393 } 394 else if (fetcherDescriptorList[i].IsConfig && fetcherDescriptorList[i].OffsetStartAddress == 0x0) 395 { 396 configDescriptorIndex = i; 397 } 398 else if (fetcherDescriptorList[i].IsConfig && fetcherDescriptorList[i].OffsetStartAddress == 0x28) 399 { 400 ivDescriptorIndex = i; 401 } 402 else if (fetcherDescriptorList[i].IsConfig && fetcherDescriptorList[i].OffsetStartAddress == 0x38) 403 { 404 iv2DescriptorIndex = i; 405 } 406 else if (fetcherDescriptorList[i].IsConfig && fetcherDescriptorList[i].OffsetStartAddress == 0x48) 407 { 408 key2DescriptorIndex = i; 409 } 410 } 411 412 this.Log(LogLevel.Noisy, "RunAesEngine(): config_index={0} key_index={1} key2_index={2} iv_index={3} iv2_index={4} plaintextIndex={5}", 413 configDescriptorIndex, keyDescriptorIndex, key2DescriptorIndex, ivDescriptorIndex, iv2DescriptorIndex, inputTextDescriptorIndex); 414 415 if (keyDescriptorIndex < 0 || configDescriptorIndex < 0 || inputTextDescriptorIndex < 0) 416 { 417 this.Log(LogLevel.Error, "RunAesEngine(): one or more expected descriptors is missing"); 418 return; 419 } 420 421 this.Log(LogLevel.Noisy, "RunAesEngine(): Config:[{0}]", BitConverter.ToString(fetcherDescriptorList[configDescriptorIndex].Data)); 422 423 IBlockCipher cipher = null; 424 KeyParameter keyParameter = new KeyParameter(fetcherDescriptorList[keyDescriptorIndex].Data); 425 this.Log(LogLevel.Noisy, "RunAesEngine(): key:[{0}]", BitConverter.ToString(fetcherDescriptorList[keyDescriptorIndex].Data)); 426 427 ParametersWithIV parametersWithIV = null; 428 if (ivDescriptorIndex >= 0) 429 { 430 parametersWithIV = new ParametersWithIV(keyParameter, fetcherDescriptorList[ivDescriptorIndex].Data); 431 this.Log(LogLevel.Noisy, "RunAesEngine(): IV:[{0}]", BitConverter.ToString(fetcherDescriptorList[ivDescriptorIndex].Data)); 432 } 433 434 this.Log(LogLevel.Noisy, "RunAesEngine(): Input Data:[{0}]", BitConverter.ToString(fetcherDescriptorList[inputTextDescriptorIndex].Data)); 435 436 // Bit 0: encryption or decryption operation 437 // 0: encryption operation 438 // 1: decryption operation 439 bool encrypt = ((fetcherDescriptorList[configDescriptorIndex].Data[0] & 0x1) == 0); 440 // Bit 4: Cx_Load: 441 // 0: AES operation is initial; no contet is given as input 442 // 1: AES operation is not initial; the context must be provided as input 443 bool cxLoad = ((fetcherDescriptorList[configDescriptorIndex].Data[0] & (0x1 << 4)) > 0); 444 // Bit 5: Cx_Save: 445 // 0: AES operation is final; the engine will not return the context 446 // 1: AES operation is not final; the engine will return the context 447 bool cxSave = ((fetcherDescriptorList[configDescriptorIndex].Data[0] & (0x1 << 4)) > 0); 448 // 16:8 Mode of Operation 449 AesMode mode = (AesMode)(fetcherDescriptorList[configDescriptorIndex].Data[1] | ((fetcherDescriptorList[configDescriptorIndex].Data[2] & 0x1) << 8)); 450 this.Log(LogLevel.Noisy, "RunAesEngine(): encrypt={0} cxLoad={1} cxSave={2} AES mode: {3}", encrypt, cxLoad, cxSave, mode); 451 452 int outputTextDescriptorIndex = -1; 453 int outputIvDescriptorIndex = -1; 454 455 switch(mode) 456 { 457 case AesMode.Ecb: 458 cipher = new AesEngine(); 459 // The output IV length is always 0 when using ECB 460 cipher.Init(encrypt, keyParameter); 461 // In ECB mode we expect a single pusher descriptor which stores the ouput text 462 outputTextDescriptorIndex = 0; 463 break; 464 case AesMode.Ctr: 465 cipher = new SicBlockCipher(new AesEngine()); 466 cipher.Init(encrypt, parametersWithIV); 467 outputTextDescriptorIndex = 0; 468 outputIvDescriptorIndex = 1; 469 break; 470 default: 471 this.Log(LogLevel.Error, "RunAesEngine(): AES mode not supported"); 472 return; 473 } 474 475 for(int i = 0; i < fetcherDescriptorList[inputTextDescriptorIndex].Length; i += 16) 476 { 477 cipher.ProcessBlock(fetcherDescriptorList[inputTextDescriptorIndex].Data, i, pusherDescriptorList[outputTextDescriptorIndex].Data, i); 478 } 479 480 for (uint i=0; i<pusherDescriptorList[outputTextDescriptorIndex].Length; i++) 481 { 482 machine.SystemBus.WriteByte(pusherDescriptorList[outputTextDescriptorIndex].FirstDataAddress + i, pusherDescriptorList[outputTextDescriptorIndex].Data[i]); 483 } 484 485 this.Log(LogLevel.Noisy, "RunAesEngine(): Output Data:[{0}]", BitConverter.ToString(pusherDescriptorList[outputTextDescriptorIndex].Data)); 486 487 // TODO: RENODE-51: The crypto mode classes do not expose the IV (for example the SicBlockCipher class). 488 // We should write the output IV here, for now we just do a +1 on each byte of the input IV. 489 if (cxSave) 490 { 491 for (uint i=0; i<pusherDescriptorList[outputIvDescriptorIndex].Length; i++) 492 { 493 pusherDescriptorList[outputIvDescriptorIndex].Data[i] = (byte)(fetcherDescriptorList[ivDescriptorIndex].Data[i] + 1); 494 machine.SystemBus.WriteByte(pusherDescriptorList[outputIvDescriptorIndex].FirstDataAddress + i, pusherDescriptorList[outputIvDescriptorIndex].Data[i]); 495 } 496 this.Log(LogLevel.Noisy, "RunAesEngine(): Output IV:[{0}]", BitConverter.ToString(pusherDescriptorList[outputIvDescriptorIndex].Data)); 497 } 498 } 499 #endregion 500 501 #region enums 502 private enum AesMode 503 { 504 Ecb = 0x001, 505 Ccb = 0x002, 506 Ctr = 0x004, 507 Cfb = 0x008, 508 Ofb = 0x010, 509 Ccm = 0x020, 510 GcmGmac = 0x040, 511 Xts = 0x080, 512 Cmac = 0x100, 513 } 514 private enum Registers 515 { 516 FetcherAddress = 0x000, 517 FetcherLength = 0x008, 518 FetcherTag = 0x00C, 519 PusherAddress = 0x010, 520 PusherLength = 0x018, 521 InterruptEnable = 0x01C, 522 InterruptEnableSet = 0x020, 523 InterruptEnableClear = 0x024, 524 InterruptFlag = 0x028, 525 InterruptFlagMasked = 0x02C, 526 InterruptFlagClear = 0x030, 527 Control = 0x034, 528 Command = 0x038, 529 Status = 0x03C, 530 } 531 532 private enum CryptoEngine 533 { 534 Bypass = 0x0, 535 Aes = 0x1, 536 Des = 0x2, 537 Hash = 0x3, 538 ChaChaPoly = 0x4, 539 Sha3 = 0x5, 540 AesGcm = 0x6, 541 AesXts = 0x7, 542 HashPlusAes = 0x8, 543 AesPlusHash = 0x9, 544 Zuc = 0xA, 545 Sm4 = 0xB, 546 HpChaChaPoly = 0xC, 547 Snow3g = 0xD, 548 Kasumi = 0xE, 549 Aria = 0xF, 550 } 551 552 private enum CryptoDataType 553 { 554 Unused, 555 Payload, 556 Header, 557 Message, 558 InitializationData, 559 HMAC_Key, 560 ReferenceHash, 561 ReferenceTag, 562 ReferenceDigest, 563 } 564 #endregion 565 566 private class DmaDescriptor 567 { DmaDescriptor()568 public DmaDescriptor() 569 { 570 } 571 572 public CryptoEngine EngineSelect 573 { 574 get => (CryptoEngine)(this.Tag & 0xF); 575 } 576 577 public bool IsData 578 { 579 get => ((this.Tag & 0x10) == 0); 580 } 581 582 public bool IsConfig 583 { 584 get => !this.IsData; 585 } 586 587 public bool IsLastDataOrConfig 588 { 589 get => ((this.Tag & 0x20) > 0); 590 } 591 public uint InvalidBytesOrBits 592 { 593 // Bits 13:8 594 get => IsData ? ((this.Tag & 0xCF00) >> 8) : 0; 595 } 596 597 public uint OffsetStartAddress 598 { 599 // Bits 15:8 600 get => IsData ? 0 : ((this.Tag & 0xFF00) >> 8); 601 } 602 603 public CryptoDataType DataType 604 { 605 get 606 { 607 if (!IsData) 608 { 609 return CryptoDataType.Unused; 610 } 611 612 // Bits 7:6 613 uint dataType = ((this.Tag & 0xC0) >> 6); 614 switch(this.EngineSelect) 615 { 616 case CryptoEngine.Aes: 617 case CryptoEngine.Sm4: 618 case CryptoEngine.Aria: 619 switch(dataType) 620 { 621 case 0: 622 return CryptoDataType.Payload; 623 case 1: 624 return CryptoDataType.Header; 625 } 626 break; 627 case CryptoEngine.Hash: 628 case CryptoEngine.Sha3: 629 switch(dataType) 630 { 631 case 0: 632 return CryptoDataType.Message; 633 case 1: 634 return CryptoDataType.InitializationData; 635 case 2: 636 return CryptoDataType.HMAC_Key; 637 case 3: 638 return CryptoDataType.ReferenceHash; 639 } 640 break; 641 case CryptoEngine.AesGcm: 642 switch(dataType) 643 { 644 case 0: 645 return CryptoDataType.Payload; 646 case 1: 647 return CryptoDataType.Header; 648 case 3: 649 return CryptoDataType.ReferenceTag; 650 } 651 break; 652 case CryptoEngine.ChaChaPoly: 653 case CryptoEngine.HpChaChaPoly: 654 switch(dataType) 655 { 656 case 0: 657 return CryptoDataType.Payload; 658 case 1: 659 return CryptoDataType.Header; 660 case 3: 661 return CryptoDataType.ReferenceDigest; 662 } 663 break; 664 } 665 return CryptoDataType.Unused; 666 } 667 } 668 669 public uint FirstDataAddress; 670 public bool LastDescriptor; 671 public uint NextDescriptorAddress; 672 public uint Length; 673 public bool ConstantAddress; 674 public bool Realign; 675 public bool Discard; 676 public bool ZeroPadding; 677 public bool InterruptEnable; 678 public uint Tag; 679 public byte[] Data; 680 } 681 } 682 }