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.Linq;
12 using System.IO;
13 using Antmicro.Renode.Core;
14 using Antmicro.Renode.Core.Structure.Registers;
15 using Antmicro.Renode.Exceptions;
16 using Antmicro.Renode.Logging;
17 using Antmicro.Renode.Peripherals.Bus;
18 using Antmicro.Renode.Peripherals.Timers;
19 using Antmicro.Renode.Time;
20 using Antmicro.Renode.Utilities;
21 using Antmicro.Renode.Utilities.Packets;
22 using Org.BouncyCastle.Crypto;
23 using Org.BouncyCastle.Crypto.Engines;
24 using Org.BouncyCastle.Crypto.Modes;
25 using Org.BouncyCastle.Crypto.Macs;
26 using Org.BouncyCastle.Crypto.Parameters;
27 using Org.BouncyCastle.Crypto.Digests;
28 
29 namespace Antmicro.Renode.Peripherals.Miscellaneous.SiLabs
30 {
31     public class Silabs_SecureElement
32     {
Silabs_SecureElement(Machine machine, IDoubleWordPeripheral parent, Queue<uint> txFifo, Queue<uint> rxFifo, bool series3)33         public Silabs_SecureElement(Machine machine, IDoubleWordPeripheral parent, Queue<uint> txFifo, Queue<uint> rxFifo, bool series3)
34             : this(machine, parent, txFifo, rxFifo, series3, 0, 0, 0, 0, 0, 0)
35         {
36         }
37 
Silabs_SecureElement(Machine machine, IDoubleWordPeripheral parent, Queue<uint> txFifo, Queue<uint> rxFifo, bool series3, uint flashSize, uint flashPageSize, uint flashRegionSize, uint flashCodeRegionStart, uint flashCodeRegionEnd=0, uint flashDataRegionStart=0)38         public Silabs_SecureElement(Machine machine, IDoubleWordPeripheral parent, Queue<uint> txFifo, Queue<uint> rxFifo, bool series3,
39                             uint flashSize, uint flashPageSize, uint flashRegionSize, uint flashCodeRegionStart, uint flashCodeRegionEnd=0, uint flashDataRegionStart=0)
40         {
41             this.machine = machine;
42             this.parent = parent;
43             this.txFifo = txFifo;
44             this.rxFifo = rxFifo;
45             this.series3 = series3;
46             this.flashSize = flashSize;
47             this.flashPageSize = flashPageSize;
48             this.flashRegionSize = flashRegionSize;
49             this.flashCodeRegionStart = flashCodeRegionStart;
50             this.flashCodeRegionEnd = flashCodeRegionEnd;
51             this.flashDataRegionStart = flashDataRegionStart;
52 
53             // TODO: the SE adds an internal key at slot 246 used for NVM3 encryption operations.
54             // We just add an arbitrary key here to faciliate all NVM3 operations.
55             byte[] key = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
56             volatileKeys[246] = key;
57         }
58 
59 #region fields
60         private readonly Machine machine;
61         private readonly IDoubleWordPeripheral parent;
62         private const uint NullDescriptor = 1;
63         private readonly bool series3;
64         private static PseudorandomNumberGenerator random = EmulationManager.Instance.CurrentEmulation.RandomGenerator;
65         private Queue<uint> txFifo;
66         private Queue<uint> rxFifo;
67         private uint wordsLeftToBeReceived;
68         // TODO: This is a HACK: the Bouncy Castle hash function implementation does not allow to
69         // set the state, which is needed for HASH_UPDATE commands.
70         // The solution is to keep around the hash engine until the HASH_FINAL command is called,
71         // but this requires all these commands to happen sequentially, hence the hack.
72         private IDigest currentHashEngine = null;
73         // Series3 specific value.
74         // Related to PSEC-5391, once that gets resolved, we might need to update this accordingly.
75         private const uint QspiFlashHostBase = 0x1000000;
76         private readonly uint flashSize;
77         private readonly uint flashPageSize;
78         private readonly uint flashRegionSize;
79         private readonly uint flashCodeRegionStart;
80         private readonly uint flashCodeRegionEnd;
81         private readonly uint flashDataRegionStart;
82         private Dictionary<uint, byte[]> volatileKeys = new Dictionary<uint, byte[]>();
83 #endregion
84 
85 #region public methods
Reset()86         public void Reset()
87         {
88             wordsLeftToBeReceived = 0;
89         }
90 
GetDefaultErrorStatus()91         public uint GetDefaultErrorStatus()
92         {
93             return (uint)ResponseCode.InternalError;
94         }
95 
TxHeaderSetCallback(uint header)96         public void TxHeaderSetCallback(uint header)
97         {
98             // Setting the TX header starts a new "transaction".
99             // The TX header as per HOST code, appears to be simply the number of
100             // bytes (multiple of 4) that constitute the message.
101             // At minimum a message contains:
102             // - The header itself
103             // - The command ID
104             // - Address in memory of command data input
105             // - Address in memory of command data output
106             // - Zero or more parameters
107             wordsLeftToBeReceived = header / 4;
108         }
109 
TxFifoEnqueueCallback(uint word)110         public bool TxFifoEnqueueCallback(uint word)
111         {
112             if (wordsLeftToBeReceived == 0)
113             {
114                 parent.Log(LogLevel.Error, "TxFifoEnqueueCallback: 0 words left");
115                 return false;
116             }
117 
118             wordsLeftToBeReceived--;
119 
120             if (wordsLeftToBeReceived == 0)
121             {
122                 ProcessCommand();
123                 return true;
124             }
125 
126             return false;
127         }
128 #endregion
129 
130 #region private methods
ProcessCommand()131         private void ProcessCommand()
132         {
133             uint commandHandle = 0;
134 
135             if (txFifo.Count == 0)
136             {
137                 parent.Log(LogLevel.Error, "ProcessCommand(): Queue is EMPTY!");
138                 WriteResponse(ResponseCode.InvalidParameter, commandHandle);
139             }
140 
141             uint header = txFifo.Dequeue();
142             // First 2 bytes of the header is the number of bytes in the message (header included)
143             uint wordsCount = (header & 0xFFFF)/4;
144 
145             if (txFifo.Count < wordsCount - 1)
146             {
147                 parent.Log(LogLevel.Error, "ProcessCommand(): Not enough words FifoSize={0}, expectedWords={1}", txFifo.Count, wordsCount - 1);
148                 WriteResponse(ResponseCode.InvalidParameter, commandHandle);
149             }
150 
151             if (series3)
152             {
153                 commandHandle = txFifo.Dequeue();
154             }
155 
156             uint commandOptions = txFifo.Dequeue();
157             var commandId = (CommandId)(commandOptions >> 16);
158             commandOptions &= 0xFFFF;
159             uint inputDmaDescriptorPtr = txFifo.Dequeue();
160             uint outputDmaDescriptorPtr = txFifo.Dequeue();
161             uint commandParamsCount = wordsCount - (series3 ? 5U : 4U);
162             uint[] commandParams = new uint[13];
163             for(var i = 0; i < commandParamsCount; i ++)
164             {
165                 commandParams[i] = txFifo.Dequeue();
166             }
167 
168             parent.Log(LogLevel.Info, "ProcessCommand(): command ID={0} command Options=0x{1:X} command params count={2}", commandId, commandOptions, commandParamsCount);
169 
170             ResponseCode responseCode;
171 
172             switch(commandId)
173             {
174                 case CommandId.ImportKey:
175                     responseCode = HandleImportKeyCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount);
176                     break;
177                 case CommandId.ExportKey:
178                     responseCode = HandleExportKeyCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, series3);
179                     break;
180                 case CommandId.Hash:
181                     responseCode = HandleHashCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions);
182                     break;
183                 case CommandId.HashUpdate:
184                 case CommandId.HashFinish:
185                     responseCode = HandleHashUpdateOrFinishCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions, (commandId == CommandId.HashFinish));
186                     break;
187                 case CommandId.AesEncrypt:
188                 case CommandId.AesDecrypt:
189                     responseCode = HandleAesEncryptOrDecryptCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions, (commandId == CommandId.AesEncrypt));
190                     break;
191                 case CommandId.AesCmac:
192                     responseCode = HandleAesCmacCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount);
193                     break;
194                 case CommandId.AesCcmEncrypt:
195                     responseCode = HandleAesCcmEncryptCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount);
196                     break;
197                 case CommandId.AesCcmDecrypt:
198                     responseCode = HandleAesCcmDecryptCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount);
199                     break;
200                 case CommandId.AesGcmEncrypt:
201                     responseCode = HandleAesGcmEncryptCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions);
202                     break;
203                 case CommandId.AesGcmDecrypt:
204                     responseCode = HandleAesGcmDecryptCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions);
205                     break;
206                 case CommandId.Random:
207                     responseCode = HandleRandomCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount);
208                     break;
209                 case CommandId.ReadDeviceData:
210                     responseCode = HandleReadDeviceDataCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions);
211                     break;
212                 case CommandId.FlashEraseDataRegion:
213                     responseCode = HandleFlashEraseDataRegionCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions);
214                     break;
215                 case CommandId.FlashWriteDataRegion:
216                     responseCode = HandleFlashWriteDataRegionCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions);
217                     break;
218                 case CommandId.FlashGetDataRegionLocation:
219                     responseCode = HandleFlashGetDataRegionLocationCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions);
220                     break;
221                 case CommandId.FlashGetCodeRegionConfig:
222                     responseCode = HandleFlashGetCodeRegionConfigCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions);
223                     break;
224                 case CommandId.ConfigureQspiRefClock:
225                     responseCode = HandleConfigureQspiRefClockCommand(inputDmaDescriptorPtr, outputDmaDescriptorPtr, commandParams, commandParamsCount, commandOptions);
226                     break;
227                 default:
228                     responseCode = ResponseCode.InvalidCommand;
229                     parent.Log(LogLevel.Error, "ProcessCommand(): Command ID 0x{0:X} not handled!", (uint)commandId);
230                     break;
231             }
232 
233             if (responseCode != ResponseCode.Ok)
234             {
235                 parent.Log(LogLevel.Info, "ProcessCommand(): Response code {0}", responseCode);
236             }
237 
238             WriteResponse(responseCode, commandHandle);
239         }
240 
WriteResponse(ResponseCode code, uint commandHandle)241         private void WriteResponse(ResponseCode code, uint commandHandle)
242         {
243             rxFifo.Enqueue((uint)code);
244             if (series3)
245             {
246                 rxFifo.Enqueue(commandHandle);
247             }
248         }
249 #endregion
250 
251 #region command handlers
HandleImportKeyCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount)252         private ResponseCode HandleImportKeyCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount)
253         {
254             if (commandParamsCount != 1)
255             {
256                 parent.Log(LogLevel.Error, "IMPORT_KEY: invalid parameter count");
257                 return ResponseCode.Abort;
258             }
259 
260             KeyMode keyMode;
261             KeyType keyType;
262             KeyRestriction keyRestriction;
263             uint keyIndex;
264             UnpackKeyMetadata(commandParams[0], out keyIndex, out keyType, out keyMode, out keyRestriction);
265 
266             parent.Log(LogLevel.Noisy, "IMPORT_KEY: keyIndex={0} keyType={1} keyMode={2} keyRestriction={3}",
267                      keyIndex, keyType, keyMode, keyRestriction);
268 
269             if (keyMode == KeyMode.Unprotected || keyMode == KeyMode.WrappedAntiReplay)
270             {
271                 parent.Log(LogLevel.Error, "HandleImportKeyCommand: invalid key mode");
272                 return ResponseCode.Abort;
273             }
274 
275             // First input DMA descriptor contains the plaintext key
276             uint plaintextKeyPtr;
277             uint keyLength;
278             DmaTranferOptions transferOptions;
279             uint nextDescriptorPtr;
280             UnpackDmaDescriptor(inputDma, out plaintextKeyPtr, out keyLength, out transferOptions, out nextDescriptorPtr, machine);
281             parent.Log(LogLevel.Noisy, "IMPORT_KEY: keyPtr=0x{0:X} keyLength={1} options={2} nextDescriptorPtr=0x{3:X}",
282                      plaintextKeyPtr, keyLength, transferOptions, nextDescriptorPtr);
283             byte[] key = new byte[keyLength];
284             FetchFromRam(plaintextKeyPtr, key, 0, keyLength);
285             parent.Log(LogLevel.Noisy, "Key=[{0}]", BitConverter.ToString(key));
286 
287             // Input DMA has actually a second descriptor containing 8 bytes all set to zeros. I assume that is the auth_data[8] field,
288             // TODO: For now we don't use the auth_data to do anything so we just ignore it.
289             if (keyMode == KeyMode.Volatile)
290             {
291                 // if keyMode == KeyMode.Volatile, we store the key in a dictionary,
292                 // since no data will be returned and the key will be transferred into an internal slot or KSU.
293                 // in our case, dictionary within SE model.
294                 // TODO: Double check if when doing FetchFromRam we need to account for offset.
295                 parent.Log(LogLevel.Noisy, "Assigning VOLATILE key to index {0}", keyIndex);
296                 volatileKeys[keyIndex] = key;
297 
298                 return ResponseCode.Ok;
299             }
300             else if (keyMode == KeyMode.Wrapped)
301             {
302                 uint outputDataPtr;
303                 uint outputDataLength;
304                 DmaTranferOptions outputTransferOptions;
305                 UnpackDmaDescriptor(outputDma, out outputDataPtr, out outputDataLength, out outputTransferOptions, out nextDescriptorPtr, machine);
306 
307                 // Output DMA is expected to be structured as follows:
308                 // - 12 bytes: random IV assigned at time of wrapping
309                 // - var bytes: encrypted key data
310                 // - 16 bytes: AESGCM authentication tag
311                 if (outputDataLength != (12 + keyLength + 16))
312                 {
313                     return ResponseCode.InvalidParameter;
314                 }
315 
316                 // All other key modes write a wrapped-up flavor of the key to the output DMA.
317                 // TODO: for now we simply copy the plaintext key to the output DMA.
318                 // Random IV and AESGCM tags are assigned to special markers.
319                 uint offset = 0;
320                 machine.SystemBus.WriteDoubleWord(outputDataPtr + offset, 0);
321                 machine.SystemBus.WriteDoubleWord(outputDataPtr + 4, 0);
322                 machine.SystemBus.WriteDoubleWord(outputDataPtr + 8, 0);
323                 // random IV
324                 for(uint i = 0; i < 3; i++)
325                 {
326                     machine.SystemBus.WriteDoubleWord(outputDataPtr + offset, 0x15151515);
327                     offset += 4;
328                 }
329                 // "encrypted" key data
330                 for(uint i = 0; i < keyLength/4; i++)
331                 {
332                     uint keyWord = (uint)machine.SystemBus.ReadDoubleWord(plaintextKeyPtr + i*4);
333                     machine.SystemBus.WriteDoubleWord(outputDataPtr + offset, keyWord);
334                     offset += 4;
335                 }
336                 // AESGCM authentication tag
337                 for(uint i = 0; i < 4; i++)
338                 {
339                     machine.SystemBus.WriteDoubleWord(outputDataPtr + offset, 0x5C5D5E5F);
340                     offset += 4;
341                 }
342 
343                 return ResponseCode.Ok;
344             }
345 
346             return ResponseCode.InvalidParameter;
347         }
348 
HandleExportKeyCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, bool series3)349         protected virtual ResponseCode HandleExportKeyCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, bool series3)
350         {
351             if (commandParamsCount != 1)
352             {
353                 parent.Log(LogLevel.Error, "EXPORT_KEY: invalid parameter count");
354                 return ResponseCode.Abort;
355             }
356 
357             KeyMode keyMode;
358             KeyType keyType;
359             KeyRestriction keyRestriction;
360             uint keyIndex;
361             UnpackKeyMetadata(commandParams[0], out keyIndex, out keyType, out keyMode, out keyRestriction);
362 
363             parent.Log(LogLevel.Noisy, "EXPORT_KEY: keyIndex={0} keyType={1} keyMode={2} keyRestriction={3}",
364                        keyIndex, keyType, keyMode, keyRestriction);
365 
366             if (keyMode == KeyMode.Unprotected || keyMode == KeyMode.WrappedAntiReplay)
367             {
368                 parent.Log(LogLevel.Error, "HandleExportKeyCommand: invalid key mode");
369                 return ResponseCode.Abort;
370             }
371 
372             if (keyMode == KeyMode.Volatile)
373             {
374                 // key must be present in the dictionary to be exported.
375                 if (!volatileKeys.ContainsKey(keyIndex))
376                 {
377                     return ResponseCode.InvalidParameter;
378                 }
379 
380                 byte[] key = volatileKeys[keyIndex];
381                 uint outputDataPtr;
382                 uint outputDataLength;
383                 DmaTranferOptions transferOptions;
384                 uint nextDescriptorPtr;
385                 // No data input is required when exporting a VOLATILE key, only output DMA is used.
386                 UnpackDmaDescriptor(outputDma, out outputDataPtr, out outputDataLength, out transferOptions, out nextDescriptorPtr, machine);
387                 parent.Log(LogLevel.Noisy, "EXPORT_VOLATILE_KEY: keyPtr=0x{0:X} keyLength={1} options={2} nextDescriptorPtr=0x{3:X}",
388                     outputDataPtr, key.Length, transferOptions, nextDescriptorPtr);
389 
390                 if (outputDataLength != key.Length)
391                 {
392                     return ResponseCode.InvalidParameter;
393                 }
394 
395                 for (uint i = 0; i < key.Length / 4; i++)
396                 {
397                     machine.SystemBus.WriteDoubleWord(outputDataPtr + i * 4, BitConverter.ToUInt32(key, (int)i * 4));
398                 }
399 
400                 return ResponseCode.Ok;
401             }
402             else if (keyMode == KeyMode.Wrapped)
403             {
404                 // Only "unlocked" keys can be exported.
405                 if (keyRestriction != KeyRestriction.Unlocked)
406                 {
407                     return ResponseCode.AuthorizationError;
408                 }
409 
410                 // First input DMA descriptor contains the wrapped key, expected to be structured as follows:
411                 // - 8 bytes: authorization data
412                 // - 12 bytes: random IV assigned at time of wrapping
413                 // - var bytes: encrypted key data
414                 // - 16 bytes: AESGCM authentication tag
415                 uint wrappedKeyPtr;
416                 uint keyLength;
417                 uint authDataPtr;
418                 uint authDataLength;
419                 DmaTranferOptions transferOptions;
420                 uint nextDescriptorPtr;
421 
422                 UnpackDmaDescriptor(inputDma, out authDataPtr, out authDataLength, out transferOptions, out nextDescriptorPtr, machine);
423                 UnpackDmaDescriptor(nextDescriptorPtr, out wrappedKeyPtr, out keyLength, out transferOptions, out nextDescriptorPtr, machine);
424                 uint ivLength = 12;
425                 uint tagLength = 16;
426                 keyLength -= (ivLength + tagLength);
427                 parent.Log(LogLevel.Noisy, "EXPORT_KEY: keyPtr=0x{0:X} keyLength={1} options={2} nextDescriptorPtr=0x{3:X}",
428                         wrappedKeyPtr, keyLength, transferOptions, nextDescriptorPtr);
429                 byte[] key = new byte[keyLength];
430                 FetchFromRam(wrappedKeyPtr + ivLength, key, 0, keyLength);
431                 parent.Log(LogLevel.Noisy, "Key=[{0}]", BitConverter.ToString(key));
432 
433                 uint outputDataPtr;
434                 uint outputDataLength;
435                 DmaTranferOptions outputTransferOptions;
436                 UnpackDmaDescriptor(outputDma, out outputDataPtr, out outputDataLength, out outputTransferOptions, out nextDescriptorPtr, machine);
437 
438                 // Output DMA is expected to contain the plaintext raw key
439                 if (outputDataLength != keyLength)
440                 {
441                     return ResponseCode.InvalidParameter;
442                 }
443 
444                 // Since for now we store the decrypted key "as is" in the ImportKey command, we can simply copy that as "decrypted" key data.
445                 for(uint i = 0; i < keyLength/4; i++)
446                 {
447                     uint keyWord = (uint)machine.SystemBus.ReadDoubleWord(wrappedKeyPtr + 12 + i*4);
448                     machine.SystemBus.WriteDoubleWord(outputDataPtr + i*4, keyWord);
449                 }
450 
451                 return ResponseCode.Ok;
452             }
453 
454             return ResponseCode.InvalidParameter;
455         }
456 
HandleHashCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)457         private ResponseCode HandleHashCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)
458         {
459             if (commandParamsCount != 1)
460             {
461                 parent.Log(LogLevel.Error, "HASH: invalid parameter count");
462                 return ResponseCode.Abort;
463             }
464 
465             ShaMode hashMode = (ShaMode)((commandOptions & 0xF00) >> 8);
466             uint dataSize = commandParams[0];
467 
468             parent.Log(LogLevel.Noisy, "HASH: mode={0} dataSize={1}", hashMode, dataSize);
469 
470             DmaTranferOptions transferOptions;
471             uint inputPayloadDescriptorPtr;
472             uint inputPayloadLength;
473             uint nextDescriptorPtr;
474             UnpackDmaDescriptor(inputDma, out inputPayloadDescriptorPtr, out inputPayloadLength, out transferOptions, out nextDescriptorPtr, machine);
475             parent.Log(LogLevel.Noisy, "HASH: INPUT0: payloadPtr=0x{0:X} payloadLength={1} options={2} nextDescriptorPtr=0x{3:X}",
476                     inputPayloadDescriptorPtr, inputPayloadLength, transferOptions, nextDescriptorPtr);
477             byte[] payload = new byte[inputPayloadLength];
478             FetchFromRam(inputPayloadDescriptorPtr, payload, 0, inputPayloadLength);
479             parent.Log(LogLevel.Noisy, "Payload=[{0}]", BitConverter.ToString(payload));
480 
481             uint outputDigestDescriptorPtr;
482             uint outputDigestLength;
483             UnpackDmaDescriptor(outputDma, out outputDigestDescriptorPtr, out outputDigestLength, out transferOptions, out nextDescriptorPtr, machine);
484             parent.Log(LogLevel.Noisy, "HASH: OUTPUT0: payloadPtr=0x{0:X} payloadLength={1} options={2} nextDescriptorPtr=0x{3:X}",
485                     outputDigestDescriptorPtr, outputDigestLength, transferOptions, nextDescriptorPtr);
486             byte[] digest = new byte[outputDigestLength];
487 
488             IDigest hashEngine = CreateHashEngine(hashMode);
489 
490             if(hashEngine == null)
491             {
492                 parent.Log(LogLevel.Error, "HASH: unable to create hashing engine");
493                 return ResponseCode.Abort;
494             }
495 
496             if (hashEngine.GetDigestSize() != outputDigestLength)
497             {
498                 parent.Log(LogLevel.Error, "HASH: digest size mismatch");
499                 return ResponseCode.Abort;
500             }
501 
502             hashEngine.BlockUpdate(payload, 0, (int)inputPayloadLength);
503             hashEngine.DoFinal(digest, 0);
504 
505             parent.Log(LogLevel.Noisy, "Digest=[{0}]", BitConverter.ToString(digest));
506             WriteToRam(digest, 0, outputDigestDescriptorPtr, outputDigestLength);
507             return ResponseCode.Ok;
508         }
509 
HandleHashUpdateOrFinishCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions, bool doFinish)510         private ResponseCode HandleHashUpdateOrFinishCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions, bool doFinish)
511         {
512             if (commandParamsCount != 1 && commandParamsCount != 2)
513             {
514                 parent.Log(LogLevel.Error, "HASH_UPDATE/FINISH: invalid parameter count");
515                 return ResponseCode.Abort;
516             }
517 
518             ShaMode hashMode = (ShaMode)((commandOptions & 0xF00) >> 8);
519             uint dataSize = commandParams[0];
520             uint counter = (commandParamsCount == 2) ? commandParams[1] : 0;
521 
522             parent.Log(LogLevel.Noisy, "HASH_UPDATE/FINISH: mode={0} dataSize={1} counter={2}", hashMode, dataSize, counter);
523 
524             DmaTranferOptions transferOptions;
525             uint inputStateDescriptorPtr;
526             uint inputStateLength;
527             uint nextDescriptorPtr;
528             // TODO: we don't use the input state, we just keep the hashing engine object around
529             // until the HASH_FINISH command is called.
530             UnpackDmaDescriptor(inputDma, out inputStateDescriptorPtr, out inputStateLength, out transferOptions, out nextDescriptorPtr, machine);
531             parent.Log(LogLevel.Noisy, "HASH_UPDATE/FINISH: INPUT0: statePtr=0x{0:X} inputStateLength={1} options={2} nextDescriptorPtr=0x{3:X}",
532                     inputStateDescriptorPtr, inputStateLength, transferOptions, nextDescriptorPtr);
533 
534             uint inputPayloadDescriptorPtr;
535             uint inputPayloadLength;
536             UnpackDmaDescriptor(nextDescriptorPtr, out inputPayloadDescriptorPtr, out inputPayloadLength, out transferOptions, out nextDescriptorPtr, machine);
537             parent.Log(LogLevel.Noisy, "HASH_UPDATE/FINISH: INPUT1: payloadPtr=0x{0:X} payloadLength={1} options={2} nextDescriptorPtr=0x{3:X}",
538                     inputPayloadDescriptorPtr, inputPayloadLength, transferOptions, nextDescriptorPtr);
539             byte[] payload = new byte[inputPayloadLength];
540             FetchFromRam(inputPayloadDescriptorPtr, payload, 0, inputPayloadLength);
541             parent.Log(LogLevel.Noisy, "Payload=[{0}]", BitConverter.ToString(payload));
542 
543             uint outputDescriptorPtr;
544             uint outputLength;
545             UnpackDmaDescriptor(outputDma, out outputDescriptorPtr, out outputLength, out transferOptions, out nextDescriptorPtr, machine);
546             parent.Log(LogLevel.Noisy, "HASH_UPDATE/FINISH: OUTPUT0: payloadPtr=0x{0:X} payloadLength={1} options={2} nextDescriptorPtr=0x{3:X}",
547                     outputDescriptorPtr, outputLength, transferOptions, nextDescriptorPtr);
548             byte[] output = new byte[outputLength];
549 
550             if (currentHashEngine == null)
551             {
552                 currentHashEngine = CreateHashEngine(hashMode);
553                 if(currentHashEngine == null)
554                 {
555                     parent.Log(LogLevel.Error, "HASH_UPDATE/FINISH: unable to create hashing engine");
556                     return ResponseCode.Abort;
557                 }
558             }
559             else if (!CheckHashEngine(currentHashEngine, hashMode))
560             {
561                 // We make sure the current engine is the one we expect.
562                 parent.Log(LogLevel.Error, "HASH_UPDATE/FINISH: current hashing engine mismatch");
563                 return ResponseCode.Abort;
564             }
565 
566             currentHashEngine.BlockUpdate(payload, 0, (int)inputPayloadLength);
567 
568             // TODO: we don't use the input state, we just keep the hashing engine object around
569             // until the HASH_FINISH command is called. So we don't write the output state either.
570 
571             if (doFinish)
572             {
573                 if (currentHashEngine.GetDigestSize() != outputLength)
574                 {
575                     parent.Log(LogLevel.Error, "HASH_UPDATE/FINISH: digest size mismatch");
576                     return ResponseCode.Abort;
577                 }
578 
579                 currentHashEngine.DoFinal(output, 0);
580                 currentHashEngine = null;
581 
582                 parent.Log(LogLevel.Noisy, "Digest=[{0}]", BitConverter.ToString(output));
583                 WriteToRam(output, 0, outputDescriptorPtr, outputLength);
584             }
585             return ResponseCode.Ok;
586         }
587 
HandleAesEncryptOrDecryptCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions, bool encrypt)588         private ResponseCode HandleAesEncryptOrDecryptCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions, bool encrypt)
589         {
590             if (commandParamsCount != 2)
591             {
592                 parent.Log(LogLevel.Error, "AES_ENCRYPT/DECRYPT: invalid parameter count");
593                 return ResponseCode.Abort;
594             }
595 
596             CryptoMode cryptoMode = (CryptoMode)((commandOptions & 0xF00) >> 8);
597             ContextMode contextMode = (ContextMode)(commandOptions & 0xF);
598 
599             parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: cryptoMode={0} contextMode={1}", cryptoMode, contextMode);
600 
601             KeyMode keyMode;
602             KeyType keyType;
603             KeyRestriction keyRestriction;
604             uint keyIndex;
605             UnpackKeyMetadata(commandParams[0], out keyIndex, out keyType, out keyMode, out keyRestriction);
606             parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: Key Metadata: keyIndex={0} keyType={1} keyMode={2} keyRestriction={3}",
607                      keyIndex, keyType, keyMode, keyRestriction);
608             uint dataSize = commandParams[1];
609             parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: dataSize={0}", dataSize);
610 
611             // Check that the length is compatible with the crypto mode
612             if (!IsDataLengthValid(dataSize, cryptoMode))
613             {
614                 return ResponseCode.InvalidParameter;
615             }
616 
617             // First input DMA descriptor is the authorization data
618             uint authPtr;
619             uint authLength;
620             DmaTranferOptions transferOptions;
621             uint nextDescriptorPtr;
622             UnpackDmaDescriptor(inputDma, out authPtr, out authLength, out transferOptions, out nextDescriptorPtr, machine);
623             parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: INPUT0: authPtr=0x{0:X} authLength={1} options={2} nextDescriptorPtr=0x{3:X}",
624                      authPtr, authLength, transferOptions, nextDescriptorPtr);
625 
626             // Second input DMA descriptor contains the key
627             uint keyPtr;
628             uint keyLength;
629             UnpackDmaDescriptor(nextDescriptorPtr, out keyPtr, out keyLength, out transferOptions, out nextDescriptorPtr, machine);
630             parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: INPUT1: keyPtr=0x{0:X} keyLength={1} options={2} nextDescriptorPtr=0x{3:X}",
631                      keyPtr, keyLength, transferOptions, nextDescriptorPtr);
632             byte[] key = CheckAndRetrieveKey(keyType, keyMode, keyIndex, keyPtr);
633             parent.Log(LogLevel.Noisy, "Key=[{0}]", BitConverter.ToString(key));
634             KeyParameter keyParameter = new KeyParameter(key);
635 
636             // Third input DMA descriptor contains the IV (for whole or start of message) or context (for middle/end)
637             // The input IV/Context size is 0 for ECB mode and 16 for all other modes
638             ParametersWithIV parametersWithIV = null;
639             if (cryptoMode != CryptoMode.Ecb)
640             {
641                 uint inputIvPtr = 0;
642                 uint inputIvLength = 0;
643                 UnpackDmaDescriptor(nextDescriptorPtr, out inputIvPtr, out inputIvLength, out transferOptions, out nextDescriptorPtr, machine);
644                 parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: INPUT2: inputIvPtr=0x{0:X} inputIvLength={1} options={2} nextDescriptorPtr=0x{3:X}",
645                         inputIvPtr, inputIvLength, transferOptions, nextDescriptorPtr);
646                 byte[] inputIv = new byte[inputIvLength];
647                 FetchFromRam(inputIvPtr, inputIv, 0, inputIvLength);
648                 parent.Log(LogLevel.Noisy, "InputIv=[{0}]", BitConverter.ToString(inputIv));
649                 parametersWithIV = new ParametersWithIV(keyParameter, inputIv);
650             }
651 
652             // Fourth input DMA descriptor(s) contains input data
653             uint inputDataPtr;
654             uint inputDataLength;
655             byte[] inputData = new byte[dataSize];
656             uint inputDataOffset = 0;
657 
658             while (inputDataOffset < dataSize)
659             {
660                 UnpackDmaDescriptor(nextDescriptorPtr, out inputDataPtr, out inputDataLength, out transferOptions, out nextDescriptorPtr, machine);
661                 parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: INPUT3: inputDataPtr=0x{0:X} inputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
662                         inputDataPtr, inputDataLength, transferOptions, nextDescriptorPtr);
663                 if (transferOptions != DmaTranferOptions.Discard)
664                 {
665                     FetchFromRam(inputDataPtr, inputData, inputDataOffset, inputDataLength);
666                     parent.Log(LogLevel.Noisy, "InputData=[{0}]", BitConverter.ToString(inputData));
667                     inputDataOffset += inputDataLength;
668                 }
669             }
670 
671             // First output DMA descriptor(s) contains output data
672             byte[] outputData = new byte[dataSize];
673             uint outputDataOffset = 0;
674             nextDescriptorPtr = outputDma;
675 
676             while (outputDataOffset < dataSize)
677             {
678                 uint tempOutputDataPtr;
679                 uint tempOutputDataLength;
680                 UnpackDmaDescriptor(nextDescriptorPtr, out tempOutputDataPtr, out tempOutputDataLength, out transferOptions, out nextDescriptorPtr, machine);
681                 parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: OUTPUT0: outputDataPtr=0x{0:X} outputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
682                         tempOutputDataPtr, tempOutputDataLength, transferOptions, nextDescriptorPtr);
683                 outputDataOffset += tempOutputDataLength;
684             }
685 
686             // Second output DMA descriptor contains the context of block encryption for passing to next encryption/dceryption call.
687             // The output context length is 0 if ECB mode is used or the mode is last/whole. It is 16 otherwise
688             uint outputContextPtr = 0;
689             uint outputContextLength = 0;
690             if (cryptoMode != CryptoMode.Ecb && contextMode != ContextMode.WholeMessage && contextMode != ContextMode.EndOfMessage)
691             {
692                 UnpackDmaDescriptor(nextDescriptorPtr, out outputContextPtr, out outputContextLength, out transferOptions, out nextDescriptorPtr, machine);
693                 parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: OUTPUT1: outputContextPtr=0x{0:X} outputContextLength={1} options={2} nextDescriptorPtr=0x{3:X}",
694                         outputContextPtr, outputContextLength, transferOptions, nextDescriptorPtr);
695             }
696 
697             IBlockCipher cipher;
698             switch(cryptoMode)
699             {
700                 case CryptoMode.Cbc:
701                     cipher = new CbcBlockCipher(new AesEngine());
702                     cipher.Init(encrypt, parametersWithIV);
703                 break;
704                 case CryptoMode.Ecb:
705                     cipher = new AesEngine();
706                     // The input IV length is always 0 when using ECB
707                     cipher.Init(encrypt, keyParameter);
708                 break;
709                 case CryptoMode.Ctr: // TODOs
710                 case CryptoMode.Cfb:
711                 case CryptoMode.Ofb:
712                 default:
713                     parent.Log(LogLevel.Error, "AES_ENCRYPT/DECRYPT: invalid crypto mode");
714                     return ResponseCode.Abort;
715             }
716 
717             for(int i = 0; i < dataSize; i += 16)
718             {
719                 cipher.ProcessBlock(inputData, i, outputData, i);
720             }
721 
722             outputDataOffset = 0;
723             nextDescriptorPtr = outputDma;
724 
725             while (outputDataOffset < dataSize)
726             {
727                 uint tempOutputDataPtr;
728                 uint tempOutputDataLength;
729                 UnpackDmaDescriptor(nextDescriptorPtr, out tempOutputDataPtr, out tempOutputDataLength, out transferOptions, out nextDescriptorPtr, machine);
730                 if (transferOptions != DmaTranferOptions.Discard)
731                 {
732                     WriteToRam(outputData, outputDataOffset, tempOutputDataPtr, tempOutputDataLength);
733                     parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: Writing output data: length={0} offset={1} at location {2:X}",
734                             tempOutputDataLength, outputDataOffset, tempOutputDataPtr);
735                     outputDataOffset += tempOutputDataLength;
736                 }
737             }
738 
739             parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: Output data=[{0}]", BitConverter.ToString(outputData));
740 
741             // The output iv_size is 0 if ECB mode is used or the mode is last/whole. It is 16 otherwise
742             if (cryptoMode != CryptoMode.Ecb && contextMode != ContextMode.EndOfMessage && contextMode != ContextMode.WholeMessage)
743             {
744                 // TODO: Write the output IV
745                 // - RENODE-46: For CBC mode, the output IV is the cbcV
746 
747                 // For now we just do a +1 on the input IV
748                 byte[] iv = parametersWithIV.GetIV();
749                 for (uint i=0; i<outputContextLength; i++)
750                 {
751                     iv[i] = (byte)(iv[i] + 1);
752                 }
753                 WriteToRam(iv, 0, outputContextPtr, outputContextLength);
754                 parent.Log(LogLevel.Noisy, "AES_ENCRYPT/DECRYPT: Output context=[{0}]", BitConverter.ToString(iv));
755             }
756             return ResponseCode.Ok;
757         }
758 
HandleAesCmacCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount)759         private ResponseCode HandleAesCmacCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount)
760         {
761             if (commandParamsCount != 2)
762             {
763                parent.Log(LogLevel.Error, "AES_CMAC: invalid parameter count");
764                return ResponseCode.Abort;
765             }
766 
767             KeyMode keyMode;
768             KeyType keyType;
769             KeyRestriction keyRestriction;
770             uint keyIndex;
771             UnpackKeyMetadata(commandParams[0], out keyIndex, out keyType, out keyMode, out keyRestriction);
772             parent.Log(LogLevel.Noisy, "AES_CMAC: Key Metadata: keyIndex={0} keyType={1} keyMode={2} keyRestriction={3}",
773                      keyIndex, keyType, keyMode, keyRestriction);
774             uint inputDataSize = commandParams[1];
775             parent.Log(LogLevel.Noisy, "AES_CMAC: dataSize={0}", inputDataSize);
776 
777             // First input DMA descriptor is the authorization data
778             uint authPtr;
779             uint authLength;
780             DmaTranferOptions transferOptions;
781             uint nextDescriptorPtr;
782             UnpackDmaDescriptor(inputDma, out authPtr, out authLength, out transferOptions, out nextDescriptorPtr, machine);
783             parent.Log(LogLevel.Noisy, "AES_CMAC: INPUT0: authPtr=0x{0:X} authLength={1} options={2} nextDescriptorPtr=0x{3:X}",
784                      authPtr, authLength, transferOptions, nextDescriptorPtr);
785 
786             // Second input DMA descriptor contains the key.
787             uint keyPtr;
788             uint keyLength;
789             UnpackDmaDescriptor(nextDescriptorPtr, out keyPtr, out keyLength, out transferOptions, out nextDescriptorPtr, machine);
790             parent.Log(LogLevel.Noisy, "AES_CMAC: INPUT1: keyPtr=0x{0:X} keyLength={1} options={2} nextDescriptorPtr=0x{3:X}",
791                      keyPtr, keyLength, transferOptions, nextDescriptorPtr);
792             byte[] key = CheckAndRetrieveKey(keyType, keyMode, keyIndex, keyPtr);
793             parent.Log(LogLevel.Noisy, "Key=[{0}]", BitConverter.ToString(key));
794             KeyParameter keyParameter = new KeyParameter(key);
795 
796             // Third input DMA descriptor contains the input data
797             uint inputDataPtr;
798             uint inputDataLength;
799             UnpackDmaDescriptor(nextDescriptorPtr, out inputDataPtr, out inputDataLength, out transferOptions, out nextDescriptorPtr, machine);
800             parent.Log(LogLevel.Noisy, "AES_CMAC: INPUT2: inputDataPtr=0x{0:X} inputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
801                      inputDataPtr, inputDataLength, transferOptions, nextDescriptorPtr);
802             byte[] inputData = new byte[inputDataLength];
803             FetchFromRam(inputDataPtr, inputData, 0, inputDataLength);
804             parent.Log(LogLevel.Noisy, "InputData=[{0}]", BitConverter.ToString(inputData));
805 
806             // First output DMA descriptor contains the output MAC
807             uint outputDataPtr;
808             uint outputDataLength;
809             UnpackDmaDescriptor(outputDma, out outputDataPtr, out outputDataLength, out transferOptions, out nextDescriptorPtr, machine);
810             parent.Log(LogLevel.Noisy, "AES_CMAC: OUTPUT0: outputDataPtr=0x{0:X} outputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
811                      outputDataPtr, outputDataLength, transferOptions, nextDescriptorPtr);
812             byte[] outputData = new byte[outputDataLength];
813 
814             CMac cmac = new CMac(new AesEngine());
815             cmac.Init(keyParameter);
816             cmac.BlockUpdate(inputData, 0, (int)inputDataLength);
817             cmac.DoFinal(outputData, 0);
818             WriteToRam(outputData, 0, outputDataPtr, outputDataLength);
819             parent.Log(LogLevel.Noisy, "AES_CMAC: Output MAC=[{0}]", BitConverter.ToString(outputData));
820             return ResponseCode.Ok;
821         }
822 
HandleAesCcmEncryptCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount)823         private ResponseCode HandleAesCcmEncryptCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount)
824         {
825             if (commandParamsCount != 4)
826             {
827                parent.Log(LogLevel.Error, "AES_CCM_ENCRYPT: invalid parameter count");
828                return ResponseCode.Abort;
829             }
830 
831             KeyMode keyMode;
832             KeyType keyType;
833             KeyRestriction keyRestriction;
834             uint keyIndex;
835             UnpackKeyMetadata(commandParams[0], out keyIndex, out keyType, out keyMode, out keyRestriction);
836             parent.Log(LogLevel.Noisy, "AES_CCM_ENCRYPT: Key Metadata: keyIndex={0} keyType={1} keyMode={2} keyRestriction={3}",
837                      keyIndex, keyType, keyMode, keyRestriction);
838             uint tagSize = commandParams[1] & 0xFFFF;
839             uint nonceSize = (commandParams[1] >> 16) & 0xFFFF;
840             uint associatedAuthenticatedDataSize = commandParams[2];
841             uint inputDataSize = commandParams[3];
842             parent.Log(LogLevel.Noisy, "AES_CCM_ENCRYPT: Other Command Params: tagSize={0} nonceSize={1} aadSize={2} inputDataSize={3}",
843                      tagSize, nonceSize, associatedAuthenticatedDataSize, inputDataSize);
844 
845             if (!IsTagSizeValid(tagSize) || !IsNonceSizeValid(nonceSize))
846             {
847                 return ResponseCode.InvalidParameter;
848             }
849 
850             // First input DMA descriptor is the authorization data
851             uint authPtr;
852             uint authLength;
853             DmaTranferOptions transferOptions;
854             uint nextDescriptorPtr;
855             UnpackDmaDescriptor(inputDma, out authPtr, out authLength, out transferOptions, out nextDescriptorPtr, machine);
856             parent.Log(LogLevel.Noisy, "AES_CCM_ENCRYPT: INPUT0: authPtr=0x{0:X} authLength={1} options={2} nextDescriptorPtr=0x{3:X}",
857                      authPtr, authLength, transferOptions, nextDescriptorPtr);
858 
859             // Second input DMA descriptor contains the key
860             uint keyPtr;
861             uint keyLength;
862             UnpackDmaDescriptor(nextDescriptorPtr, out keyPtr, out keyLength, out transferOptions, out nextDescriptorPtr, machine);
863             parent.Log(LogLevel.Noisy, "AES_CCM_ENCRYPT: INPUT1: keyPtr=0x{0:X} keyLength={1} options={2} nextDescriptorPtr=0x{3:X}",
864                      keyPtr, keyLength, transferOptions, nextDescriptorPtr);
865             byte[] key = CheckAndRetrieveKey(keyType, keyMode, keyIndex, keyPtr);
866             parent.Log(LogLevel.Noisy, "Key=[{0}]", BitConverter.ToString(key));
867             KeyParameter keyParameter = new KeyParameter(key);
868 
869             // Third input DMA descriptor contains the nonce data
870             uint noncePtr;
871             uint nonceLength;
872             UnpackDmaDescriptor(nextDescriptorPtr, out noncePtr, out nonceLength, out transferOptions, out nextDescriptorPtr, machine);
873             parent.Log(LogLevel.Noisy, "AES_CCM_ENCRYPT: INPUT2: noncePtr=0x{0:X} nonceLength={1} options={2} nextDescriptorPtr=0x{3:X}",
874                      noncePtr, nonceLength, transferOptions, nextDescriptorPtr);
875             byte[] nonce = new byte[nonceLength];
876             FetchFromRam(noncePtr, nonce, 0, nonceLength);
877             parent.Log(LogLevel.Noisy, "Nonce=[{0}]", BitConverter.ToString(nonce));
878 
879             // Fourth input DMA descriptor contains the associated authenticated data
880             uint aadPtr;
881             uint aadLength;
882             UnpackDmaDescriptor(nextDescriptorPtr, out aadPtr, out aadLength, out transferOptions, out nextDescriptorPtr, machine);
883             parent.Log(LogLevel.Noisy, "AES_CCM_ENCRYPT: INPUT3: aadPtr=0x{0:X} aadLength={1} options={2} nextDescriptorPtr=0x{3:X}",
884                      aadPtr, aadLength, transferOptions, nextDescriptorPtr);
885             byte[] aad = new byte[aadLength];
886             FetchFromRam(aadPtr, aad, 0, aadLength);
887             parent.Log(LogLevel.Noisy, "Aad=[{0}]", BitConverter.ToString(aad));
888 
889             // Fifth input DMA descriptor contains the plaintext input data
890             uint inputDataPtr;
891             uint inputDataLength;
892             UnpackDmaDescriptor(nextDescriptorPtr, out inputDataPtr, out inputDataLength, out transferOptions, out nextDescriptorPtr, machine);
893             parent.Log(LogLevel.Noisy, "AES_CCM_ENCRYPT: INPUT4: inputDataPtr=0x{0:X} inputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
894                      inputDataPtr, inputDataLength, transferOptions, nextDescriptorPtr);
895             byte[] inputData = new byte[inputDataLength];
896             FetchFromRam(inputDataPtr, inputData, 0, inputDataLength);
897             parent.Log(LogLevel.Noisy, "InputData=[{0}]", BitConverter.ToString(inputData));
898 
899             // First output DMA descriptor contains the encrypted output data
900             uint outputDataPtr;
901             uint outputDataLength;
902             UnpackDmaDescriptor(outputDma, out outputDataPtr, out outputDataLength, out transferOptions, out nextDescriptorPtr, machine);
903             parent.Log(LogLevel.Noisy, "AES_CCM_ENCRYPT: OUTPUT0: outputDataPtr=0x{0:X} outputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
904                      outputDataPtr, outputDataLength, transferOptions, nextDescriptorPtr);
905 
906             // Second output DMA descriptor contains the output tag
907             uint outputTagPtr;
908             uint outputTagLength;
909             UnpackDmaDescriptor(nextDescriptorPtr, out outputTagPtr, out outputTagLength, out transferOptions, out nextDescriptorPtr, machine);
910             parent.Log(LogLevel.Noisy, "AES_CCM_ENCRYPT: OUTPUT1: outputTagPtr=0x{0:X} outputTagLength={1} options={2} nextDescriptorPtr=0x{3:X}",
911                      outputTagPtr, outputTagLength, transferOptions, nextDescriptorPtr);
912 
913             CcmBlockCipher cipher = new CcmBlockCipher(new AesEngine());
914             AeadParameters parameters = new AeadParameters(keyParameter, (int)outputTagLength*8, nonce, aad);
915             cipher.Init(true, parameters);
916 
917             byte[] outputDataAndTag = new byte[outputDataLength + outputTagLength];
918             cipher.ProcessPacket(inputData, 0, (int)inputDataLength, outputDataAndTag, 0);
919             parent.Log(LogLevel.Noisy, "EncryptedDataAndTag=[{0}]", BitConverter.ToString(outputDataAndTag));
920 
921             WriteToRam(outputDataAndTag, 0, outputDataPtr, outputDataLength);
922             WriteToRam(outputDataAndTag, outputDataLength, outputTagPtr, outputTagLength);
923             return ResponseCode.Ok;
924         }
925 
HandleAesCcmDecryptCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount)926         private ResponseCode HandleAesCcmDecryptCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount)
927         {
928             if (commandParamsCount != 4)
929             {
930                 parent.Log(LogLevel.Error, "AES_CCM_DECRYPT: invalid parameter count");
931                 return ResponseCode.Abort;
932             }
933 
934             KeyMode keyMode;
935             KeyType keyType;
936             KeyRestriction keyRestriction;
937             uint keyIndex;
938             UnpackKeyMetadata(commandParams[0], out keyIndex, out keyType, out keyMode, out keyRestriction);
939             parent.Log(LogLevel.Noisy, "AES_CCM_DECRYPT: Key Metadata: keyIndex={0} keyType={1} keyMode={2} keyRestriction={3}",
940                      keyIndex, keyType, keyMode, keyRestriction);
941             uint tagSize = commandParams[1] & 0xFFFF;
942             uint nonceSize = (commandParams[1] >> 16) & 0xFFFF;
943             uint associatedAuthenticatedDataSize = commandParams[2];
944             uint inputDataSize = commandParams[3];
945             parent.Log(LogLevel.Noisy, "AES_CCM_DECRYPT: Other Command Params: tagSize={0} nonceSize={1} aadSize={2} inputDataSize={3}",
946                      tagSize, nonceSize, associatedAuthenticatedDataSize, inputDataSize);
947 
948             if (!IsTagSizeValid(tagSize) || !IsNonceSizeValid(nonceSize))
949             {
950                 return ResponseCode.InvalidParameter;
951             }
952 
953             // First input DMA descriptor is the authorization data
954             uint authPtr;
955             uint authLength;
956             DmaTranferOptions transferOptions;
957             uint nextDescriptorPtr;
958             UnpackDmaDescriptor(inputDma, out authPtr, out authLength, out transferOptions, out nextDescriptorPtr, machine);
959             parent.Log(LogLevel.Noisy, "AES_CCM_DECRYPT: INPUT0: authPtr=0x{0:X} authLength={1} options={2} nextDescriptorPtr=0x{3:X}",
960                      authPtr, authLength, transferOptions, nextDescriptorPtr);
961 
962             // Second input DMA descriptor contains the key
963             uint keyPtr;
964             uint keyLength;
965             UnpackDmaDescriptor(nextDescriptorPtr, out keyPtr, out keyLength, out transferOptions, out nextDescriptorPtr, machine);
966             parent.Log(LogLevel.Noisy, "AES_CCM_DECRYPT: INPUT1: keyPtr=0x{0:X} keyLength={1} options={2} nextDescriptorPtr=0x{3:X}",
967                      keyPtr, keyLength, transferOptions, nextDescriptorPtr);
968             byte[] key = CheckAndRetrieveKey(keyType, keyMode, keyIndex, keyPtr);
969             parent.Log(LogLevel.Noisy, "Key=[{0}]", BitConverter.ToString(key));
970             KeyParameter keyParameter = new KeyParameter(key);
971 
972             // Third input DMA descriptor contains the nonce data
973             uint noncePtr;
974             uint nonceLength;
975             UnpackDmaDescriptor(nextDescriptorPtr, out noncePtr, out nonceLength, out transferOptions, out nextDescriptorPtr, machine);
976             parent.Log(LogLevel.Noisy, "AES_CCM_DECRYPT: INPUT2: noncePtr=0x{0:X} nonceLength={1} options={2} nextDescriptorPtr=0x{3:X}",
977                      noncePtr, nonceLength, transferOptions, nextDescriptorPtr);
978             byte[] nonce = new byte[nonceLength];
979             FetchFromRam(noncePtr, nonce, 0, nonceLength);
980             parent.Log(LogLevel.Noisy, "Nonce=[{0}]", BitConverter.ToString(nonce));
981 
982             // Fourth input DMA descriptor contains the associated authenticated data
983             uint aadPtr;
984             uint aadLength;
985             UnpackDmaDescriptor(nextDescriptorPtr, out aadPtr, out aadLength, out transferOptions, out nextDescriptorPtr, machine);
986             parent.Log(LogLevel.Noisy, "AES_CCM_DECRYPT: INPUT3: aadPtr=0x{0:X} aadLength={1} options={2} nextDescriptorPtr=0x{3:X}",
987                      aadPtr, aadLength, transferOptions, nextDescriptorPtr);
988             byte[] aad = new byte[aadLength];
989             FetchFromRam(aadPtr, aad, 0, aadLength);
990             parent.Log(LogLevel.Noisy, "Aad=[{0}]", BitConverter.ToString(aad));
991 
992             // Fifth input DMA descriptor contains the plaintext input data
993             uint inputDataPtr;
994             uint inputDataLength;
995             UnpackDmaDescriptor(nextDescriptorPtr, out inputDataPtr, out inputDataLength, out transferOptions, out nextDescriptorPtr, machine);
996             parent.Log(LogLevel.Noisy, "AES_CCM_DECRYPT: INPUT4: inputDataPtr=0x{0:X} inputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
997                      inputDataPtr, inputDataLength, transferOptions, nextDescriptorPtr);
998 
999             // Sixth input DMA descriptor contains the tag to be verified
1000             uint tagPtr;
1001             uint tagLength;
1002             UnpackDmaDescriptor(nextDescriptorPtr, out tagPtr, out tagLength, out transferOptions, out nextDescriptorPtr, machine);
1003             parent.Log(LogLevel.Noisy, "AES_CCM_DECRYPT: INPUT5: tagPtr=0x{0:X} tagLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1004                      tagPtr, tagLength, transferOptions, nextDescriptorPtr);
1005 
1006             byte[] inputDataAndTag = new byte[inputDataLength + tagLength];
1007             FetchFromRam(inputDataPtr, inputDataAndTag, 0, inputDataLength);
1008             FetchFromRam(tagPtr, inputDataAndTag, inputDataLength, tagLength);
1009             parent.Log(LogLevel.Noisy, "InputDataAndTag=[{0}]", BitConverter.ToString(inputDataAndTag));
1010 
1011             // First output DMA descriptor contains the decrypted output data
1012             uint outputDataPtr;
1013             uint outputDataLength;
1014             UnpackDmaDescriptor(outputDma, out outputDataPtr, out outputDataLength, out transferOptions, out nextDescriptorPtr, machine);
1015             parent.Log(LogLevel.Noisy, "AES_CCM_DECRYPT: OUTPUT0: outputDataPtr=0x{0:X} outputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1016                      outputDataPtr, outputDataLength, transferOptions, nextDescriptorPtr);
1017             byte[] outputData = new byte[outputDataLength];
1018 
1019             CcmBlockCipher cipher = new CcmBlockCipher(new AesEngine());
1020             AeadParameters parameters = new AeadParameters(keyParameter, (int)tagLength*8, nonce, aad);
1021             cipher.Init(false, parameters);
1022             bool tagMatch = true;
1023 
1024             try
1025             {
1026                 cipher.ProcessPacket(inputDataAndTag, 0, (int)(inputDataLength+tagLength), outputData, 0);
1027             }
1028             catch (Exception e)
1029             {
1030                 if (e is InvalidCipherTextException)
1031                 {
1032                     tagMatch = false;
1033                 }
1034                 else
1035                 {
1036                     throw e;
1037                 }
1038             }
1039 
1040             WriteToRam(outputData, 0, outputDataPtr, outputDataLength);
1041             parent.Log(LogLevel.Noisy, "Decrypted data=[{0}] tagMatch={1}", BitConverter.ToString(outputData), tagMatch);
1042 
1043             return tagMatch ? ResponseCode.Ok : ResponseCode.CryptoError;
1044         }
1045 
HandleAesGcmEncryptCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)1046         private ResponseCode HandleAesGcmEncryptCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)
1047         {
1048             if (commandParamsCount != 3)
1049             {
1050                 parent.Log(LogLevel.Error, "AES_GCM_ENCRYPT: invalid parameter count");
1051                 return ResponseCode.Abort;
1052             }
1053 
1054             KeyMode keyMode;
1055             KeyType keyType;
1056             KeyRestriction keyRestriction;
1057             uint keyIndex;
1058             UnpackKeyMetadata(commandParams[0], out keyIndex, out keyType, out keyMode, out keyRestriction);
1059             parent.Log(LogLevel.Noisy, "AES_GCM_ENCRYPT: Key Metadata: keyIndex={0} keyType={1} keyMode={2} keyRestriction={3}",
1060                     keyIndex, keyType, keyMode, keyRestriction);
1061             uint associatedAuthenticatedDataSize = commandParams[1];
1062             uint inputDataSize = commandParams[2];
1063 
1064             // Extract Command Options
1065             uint tagLength = GetTagLength((commandOptions >> 8) & 0xFF);
1066             ContextMode contextMode = (ContextMode)(commandOptions & 0xFF);
1067 
1068             parent.Log(LogLevel.Noisy, "AES_GCM_ENCRYPT: Command Params: aadSize={0} inputDataSize={1} Command Options: contextMode={2} tagLength={3}",
1069                     associatedAuthenticatedDataSize, inputDataSize, contextMode, tagLength);
1070 
1071             if (contextMode != ContextMode.WholeMessage)
1072             {
1073                 parent.Log(LogLevel.Error, "AES_GCM_ENCRYPT: only support WholeMessage context mode");
1074                 return ResponseCode.Abort;
1075             }
1076 
1077             // First input DMA descriptor is the authorization data
1078             uint authPtr;
1079             uint authLength;
1080             DmaTranferOptions transferOptions;
1081             uint nextDescriptorPtr;
1082             UnpackDmaDescriptor(inputDma, out authPtr, out authLength, out transferOptions, out nextDescriptorPtr, machine);
1083             parent.Log(LogLevel.Noisy, "AES_GCM_ENCRYPT: INPUT0: authPtr=0x{0:X} authLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1084                     authPtr, authLength, transferOptions, nextDescriptorPtr);
1085 
1086             // Second input DMA descriptor contains the key
1087             uint keyPtr;
1088             uint keyLength;
1089             UnpackDmaDescriptor(nextDescriptorPtr, out keyPtr, out keyLength, out transferOptions, out nextDescriptorPtr, machine);
1090             parent.Log(LogLevel.Noisy, "AES_GCM_ENCRYPT: INPUT1: keyPtr=0x{0:X} keyLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1091                     keyPtr, keyLength, transferOptions, nextDescriptorPtr);
1092             byte[] key = CheckAndRetrieveKey(keyType, keyMode, keyIndex, keyPtr);
1093             parent.Log(LogLevel.Noisy, "Key=[{0}]", BitConverter.ToString(key));
1094             KeyParameter keyParameter = new KeyParameter(key);
1095 
1096             // Third input DMA descriptor contains the IV (for Whole or Start) or context data (for Middle or End)
1097             uint ivPtr;
1098             uint ivLength;
1099             UnpackDmaDescriptor(nextDescriptorPtr, out ivPtr, out ivLength, out transferOptions, out nextDescriptorPtr, machine);
1100             parent.Log(LogLevel.Noisy, "AES_GCM_ENCRYPT: INPUT2: ivPtr=0x{0:X} ivLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1101                     ivPtr, ivLength, transferOptions, nextDescriptorPtr);
1102             byte[] iv = new byte[ivLength];
1103             FetchFromRam(ivPtr, iv, 0, ivLength);
1104             parent.Log(LogLevel.Noisy, "IV/Context=[{0}]", BitConverter.ToString(iv));
1105 
1106             // The iv_size is 12 for Whole and Start of message (= initial IV) and 32 for Middle/End of message (= context input).
1107             // For now we only support Whole, so iv_size should always be 12.
1108             if (ivLength != 12)
1109             {
1110                 parent.Log(LogLevel.Error, "AES_GCM_ENCRYPT: invalid IV length");
1111                 return ResponseCode.Abort;
1112             }
1113 
1114             // Fourth input DMA descriptor contains the associated authenticated data
1115             uint aadPtr;
1116             uint aadLength;
1117             UnpackDmaDescriptor(nextDescriptorPtr, out aadPtr, out aadLength, out transferOptions, out nextDescriptorPtr, machine);
1118             parent.Log(LogLevel.Noisy, "AES_GCM_ENCRYPT: INPUT3: aadPtr=0x{0:X} aadLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1119                     aadPtr, aadLength, transferOptions, nextDescriptorPtr);
1120             byte[] aad = new byte[aadLength];
1121             FetchFromRam(aadPtr, aad, 0, aadLength);
1122             parent.Log(LogLevel.Noisy, "Aad=[{0}]", BitConverter.ToString(aad));
1123 
1124             // Fifth input DMA descriptor contains the plaintext input data
1125             uint inputDataPtr;
1126             uint inputDataLength;
1127             UnpackDmaDescriptor(nextDescriptorPtr, out inputDataPtr, out inputDataLength, out transferOptions, out nextDescriptorPtr, machine);
1128             parent.Log(LogLevel.Noisy, "AES_GCM_ENCRYPT: INPUT4: inputDataPtr=0x{0:X} inputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1129                     inputDataPtr, inputDataLength, transferOptions, nextDescriptorPtr);
1130             byte[] inputData = new byte[inputDataLength];
1131             FetchFromRam(inputDataPtr, inputData, 0, inputDataLength);
1132             parent.Log(LogLevel.Noisy, "InputData=[{0}]", BitConverter.ToString(inputData));
1133 
1134             // Sixth input DMA descriptor contains the len(A)||len(C) (if applicable)
1135             uint lenAlenCPtr = 0;
1136             uint lenAlenCLength = 0;
1137             if (nextDescriptorPtr != NullDescriptor)
1138             {
1139                 UnpackDmaDescriptor(nextDescriptorPtr, out lenAlenCPtr, out lenAlenCLength, out transferOptions, out nextDescriptorPtr, machine);
1140                 parent.Log(LogLevel.Noisy, "AES_GCM_ENCRYPT: INPUT5: lenAlenCPtr=0x{0:X} lenAlenCLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1141                         lenAlenCPtr, lenAlenCLength, transferOptions, nextDescriptorPtr);
1142             }
1143             byte[] lenAlenC = new byte[lenAlenCLength];
1144             if (lenAlenCLength > 0)
1145             {
1146                 FetchFromRam(lenAlenCPtr, lenAlenC, 0, lenAlenCLength);
1147                 parent.Log(LogLevel.Noisy, "LenAlenC=[{0}]", BitConverter.ToString(lenAlenC));
1148             }
1149 
1150             // First output DMA descriptor contains the encrypted output data
1151             uint outputDataPtr;
1152             uint outputDataLength;
1153             UnpackDmaDescriptor(outputDma, out outputDataPtr, out outputDataLength, out transferOptions, out nextDescriptorPtr, machine);
1154             parent.Log(LogLevel.Noisy, "AES_GCM_ENCRYPT: OUTPUT0: outputDataPtr=0x{0:X} outputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1155                     outputDataPtr, outputDataLength, transferOptions, nextDescriptorPtr);
1156 
1157             // Second output DMA descriptor contains the context or tag.
1158             uint outputContextPtr;
1159             uint outputContextLength;
1160             UnpackDmaDescriptor(nextDescriptorPtr, out outputContextPtr, out outputContextLength, out transferOptions, out nextDescriptorPtr, machine);
1161             parent.Log(LogLevel.Noisy, "AES_GCM_ENCRYPT: OUTPUT1: outputContextPtr=0x{0:X} outputContextLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1162                     outputContextPtr, outputContextLength, transferOptions, nextDescriptorPtr);
1163 
1164             GcmBlockCipher cipher = new GcmBlockCipher(new AesEngine());
1165             AeadParameters parameters = new AeadParameters(keyParameter, (int)tagLength*8, iv, aad);
1166             cipher.Init(true, parameters);
1167 
1168             byte[] outputDataAndTag = new byte[outputDataLength + tagLength];
1169             int len = cipher.ProcessBytes(inputData, 0, (int)inputDataLength, outputDataAndTag, 0);
1170             len += cipher.DoFinal(outputDataAndTag, len);
1171             parent.Log(LogLevel.Noisy, "EncryptedDataAndTag=[{0}]", BitConverter.ToString(outputDataAndTag));
1172             WriteToRam(outputDataAndTag, 0, outputDataPtr, outputDataLength);
1173 
1174             // For End/Whole mode, the output context is the MAC.
1175             parent.Log(LogLevel.Noisy, "MAC=[{0}]", BitConverter.ToString(cipher.GetMac()));
1176             WriteToRam(cipher.GetMac(), 0, outputContextPtr, outputContextLength);
1177 
1178             return ResponseCode.Ok;
1179         }
1180 
HandleAesGcmDecryptCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)1181         private ResponseCode HandleAesGcmDecryptCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)
1182         {
1183             if (commandParamsCount != 3)
1184             {
1185                 parent.Log(LogLevel.Error, "AES_GCM_DECRYPT: invalid parameter count");
1186                 return ResponseCode.Abort;
1187             }
1188 
1189             KeyMode keyMode;
1190             KeyType keyType;
1191             KeyRestriction keyRestriction;
1192             uint keyIndex;
1193             UnpackKeyMetadata(commandParams[0], out keyIndex, out keyType, out keyMode, out keyRestriction);
1194             parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: Key Metadata: keyIndex={0} keyType={1} keyMode={2} keyRestriction={3}",
1195                     keyIndex, keyType, keyMode, keyRestriction);
1196             uint associatedAuthenticatedDataSize = commandParams[1];
1197             uint inputDataSize = commandParams[2];
1198 
1199             // Extract Command Options
1200             uint tagLength = GetTagLength((commandOptions >> 8) & 0xFF);
1201             ContextMode contextMode = (ContextMode)(commandOptions & 0xFF);
1202 
1203             parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: Command Params: aadSize={0} inputDataSize={1} Command Options: contextMode={2} tagLength={3}",
1204                     associatedAuthenticatedDataSize, inputDataSize, contextMode, tagLength);
1205 
1206             if (contextMode != ContextMode.WholeMessage)
1207             {
1208                 parent.Log(LogLevel.Error, "AES_GCM_DECRYPT: only support WholeMessage context mode");
1209                 return ResponseCode.Abort;
1210             }
1211 
1212             // First input DMA descriptor is the authorization data
1213             uint authPtr;
1214             uint authLength;
1215             DmaTranferOptions transferOptions;
1216             uint nextDescriptorPtr;
1217             UnpackDmaDescriptor(inputDma, out authPtr, out authLength, out transferOptions, out nextDescriptorPtr, machine);
1218             parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: INPUT0: authPtr=0x{0:X} authLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1219                     authPtr, authLength, transferOptions, nextDescriptorPtr);
1220 
1221             // Second input DMA descriptor contains the key
1222             uint keyPtr;
1223             uint keyLength;
1224             UnpackDmaDescriptor(nextDescriptorPtr, out keyPtr, out keyLength, out transferOptions, out nextDescriptorPtr, machine);
1225             parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: INPUT1: keyPtr=0x{0:X} keyLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1226                     keyPtr, keyLength, transferOptions, nextDescriptorPtr);
1227             byte[] key = CheckAndRetrieveKey(keyType, keyMode, keyIndex, keyPtr);
1228             parent.Log(LogLevel.Noisy, "Key=[{0}]", BitConverter.ToString(key));
1229             KeyParameter keyParameter = new KeyParameter(key);
1230 
1231             // Third input DMA descriptor contains the IV (for Whole or Start) or context data (for Middle or End)
1232             uint ivPtr;
1233             uint ivLength;
1234             UnpackDmaDescriptor(nextDescriptorPtr, out ivPtr, out ivLength, out transferOptions, out nextDescriptorPtr, machine);
1235             parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: INPUT2: ivPtr=0x{0:X} ivLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1236                     ivPtr, ivLength, transferOptions, nextDescriptorPtr);
1237             byte[] iv = new byte[ivLength];
1238             FetchFromRam(ivPtr, iv, 0, ivLength);
1239             parent.Log(LogLevel.Noisy, "IV/Context=[{0}]", BitConverter.ToString(iv));
1240 
1241             // The iv_size is 12 for Whole and Start of message (= initial IV) and 32 for Middle/End of message (= context input).
1242             // For now we only support Whole, so iv_size should always be 12.
1243             if (ivLength != 12)
1244             {
1245                 parent.Log(LogLevel.Error, "AES_GCM_DECRYPT: invalid IV length");
1246                 return ResponseCode.Abort;
1247             }
1248 
1249             // Fourth input DMA descriptor contains the associated authenticated data
1250             uint aadPtr;
1251             uint aadLength;
1252             UnpackDmaDescriptor(nextDescriptorPtr, out aadPtr, out aadLength, out transferOptions, out nextDescriptorPtr, machine);
1253             parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: INPUT3: aadPtr=0x{0:X} aadLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1254                     aadPtr, aadLength, transferOptions, nextDescriptorPtr);
1255             byte[] aad = new byte[aadLength];
1256             FetchFromRam(aadPtr, aad, 0, aadLength);
1257             parent.Log(LogLevel.Noisy, "Aad=[{0}]", BitConverter.ToString(aad));
1258 
1259             // Fifth input DMA descriptor contains the ciphertext input data
1260             uint inputDataPtr;
1261             uint inputDataLength;
1262             UnpackDmaDescriptor(nextDescriptorPtr, out inputDataPtr, out inputDataLength, out transferOptions, out nextDescriptorPtr, machine);
1263             parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: INPUT4: inputDataPtr=0x{0:X} inputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1264                     inputDataPtr, inputDataLength, transferOptions, nextDescriptorPtr);
1265 
1266             // Sixth input DMA descriptor contains the MAC (End/Whole only)
1267             uint macPtr = 0;
1268             uint macLength = 0;
1269             if (nextDescriptorPtr != NullDescriptor)
1270             {
1271                 UnpackDmaDescriptor(nextDescriptorPtr, out macPtr, out macLength, out transferOptions, out nextDescriptorPtr, machine);
1272                 parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: INPUT5: macPtr=0x{0:X} macLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1273                         macPtr, macLength, transferOptions, nextDescriptorPtr);
1274             }
1275 
1276             // Seventh input DMA descriptor contains the len(A)||len(C) (End only)
1277             uint lenAlenCPtr = 0;
1278             uint lenAlenCLength = 0;
1279             if (nextDescriptorPtr != NullDescriptor)
1280             {
1281                 UnpackDmaDescriptor(nextDescriptorPtr, out lenAlenCPtr, out lenAlenCLength, out transferOptions, out nextDescriptorPtr, machine);
1282                 parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: INPUT6: lenAlenCPtr=0x{0:X} lenAlenCLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1283                         lenAlenCPtr, lenAlenCLength, transferOptions, nextDescriptorPtr);
1284             }
1285             byte[] lenAlenC = new byte[lenAlenCLength];
1286             if (lenAlenCLength > 0)
1287             {
1288                 FetchFromRam(lenAlenCPtr, lenAlenC, 0, lenAlenCLength);
1289                 parent.Log(LogLevel.Noisy, "LenAlenC=[{0}]", BitConverter.ToString(lenAlenC));
1290             }
1291 
1292             byte[] inputDataAndTag = new byte[inputDataLength + tagLength];
1293             FetchFromRam(inputDataPtr, inputDataAndTag, 0, inputDataLength);
1294             FetchFromRam(macPtr, inputDataAndTag, inputDataLength, (uint)tagLength);
1295             parent.Log(LogLevel.Noisy, "InputDataAndTag=[{0}]", BitConverter.ToString(inputDataAndTag));
1296 
1297             // First output DMA descriptor contains the decrypted output data
1298             uint outputDataPtr;
1299             uint outputDataLength;
1300             UnpackDmaDescriptor(outputDma, out outputDataPtr, out outputDataLength, out transferOptions, out nextDescriptorPtr, machine);
1301             parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: OUTPUT0: outputDataPtr=0x{0:X} outputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1302                     outputDataPtr, outputDataLength, transferOptions, nextDescriptorPtr);
1303             byte[] outputData = new byte[outputDataLength];
1304 
1305             // Second output DMA descriptor contains the context
1306             uint outputContextPtr = 0;
1307             uint outputContextLength = 0;
1308             if (nextDescriptorPtr != NullDescriptor)
1309             {
1310                 UnpackDmaDescriptor(nextDescriptorPtr, out outputContextPtr, out outputContextLength, out transferOptions, out nextDescriptorPtr, machine);
1311                 parent.Log(LogLevel.Noisy, "AES_GCM_DECRYPT: OUTPUT1: outputContextPtr=0x{0:X} outputContextLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1312                         outputContextPtr, outputContextLength, transferOptions, nextDescriptorPtr);
1313             }
1314 
1315             GcmBlockCipher cipher = new GcmBlockCipher(new AesEngine());
1316             AeadParameters parameters = new AeadParameters(keyParameter, (int)tagLength*8, iv, aad);
1317             cipher.Init(false, parameters);
1318 
1319             bool tagMatch = true;
1320             int len = cipher.ProcessBytes(inputDataAndTag, 0, (int)(inputDataLength+tagLength), outputData, 0);
1321 
1322             try
1323             {
1324                 len += cipher.DoFinal(outputData, len);
1325             }
1326             catch (Exception e)
1327             {
1328                 if (e is InvalidCipherTextException)
1329                 {
1330                     tagMatch = false;
1331                 }
1332                 else
1333                 {
1334                     throw e;
1335                 }
1336             }
1337 
1338             WriteToRam(outputData, 0, outputDataPtr, outputDataLength);
1339             parent.Log(LogLevel.Noisy, "DecryptedData=[{0}] tagMatch={1}", BitConverter.ToString(outputData), tagMatch);
1340 
1341             // TODO: write the output context here when we implement Start/Middle mode.
1342 
1343             return tagMatch ? ResponseCode.Ok : ResponseCode.CryptoError;
1344         }
1345 
HandleRandomCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount)1346         private ResponseCode HandleRandomCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount)
1347         {
1348             if (commandParamsCount != 1)
1349             {
1350                 parent.Log(LogLevel.Error, "RANDOM: invalid param count {0}", commandParamsCount);
1351                 return ResponseCode.InvalidParameter;
1352             }
1353 
1354             uint randomLength = commandParams[0];
1355 
1356             parent.Log(LogLevel.Noisy, "RANDOM: random length = {0}", randomLength);
1357 
1358             // First output DMA descriptor contains the random data
1359             uint outputDataPtr;
1360             uint outputDataLength;
1361             DmaTranferOptions transferOptions;
1362             uint nextDescriptorPtr;
1363             UnpackDmaDescriptor(outputDma, out outputDataPtr, out outputDataLength, out transferOptions, out nextDescriptorPtr, machine);
1364             parent.Log(LogLevel.Noisy, "RANDOM: OUTPUT0: outputDataPtr=0x{0:X} outputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1365                      outputDataPtr, outputDataLength, transferOptions, nextDescriptorPtr);
1366 
1367             for(uint i = 0; i < randomLength; i++)
1368             {
1369                 byte b = (byte)random.Next();
1370                 machine.SystemBus.WriteByte(outputDataPtr + i, b);
1371             }
1372             return ResponseCode.Ok;
1373         }
1374 
HandleReadDeviceDataCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)1375         private ResponseCode HandleReadDeviceDataCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)
1376         {
1377             if (commandParamsCount < 1 || commandParamsCount > 2)
1378             {
1379                 parent.Log(LogLevel.Error, "ReadDeviceData: invalid param count {0}", commandParamsCount);
1380                 return ResponseCode.InvalidParameter;
1381             }
1382 
1383             uint readLocation = commandOptions >> 12;
1384             ReadDeviceDataLocationType readLocationType = (ReadDeviceDataLocationType)(readLocation >> 4);
1385 
1386             switch(readLocationType)
1387             {
1388                 case ReadDeviceDataLocationType.CC:
1389                     //update location offset to CC
1390                     break;
1391                 case ReadDeviceDataLocationType.DI:
1392                     //update location offset to DI
1393                     break;
1394                 case ReadDeviceDataLocationType.WaferProbe:
1395                     //update location offset to WaferProbe
1396                     break;
1397                 default:
1398                     return ResponseCode.InvalidParameter;
1399             }
1400 
1401             DeviceDataReadSize readSize = (DeviceDataReadSize)(commandOptions & 0xFF);
1402             uint output = 1;
1403 
1404             switch(readSize)
1405             {
1406                 case DeviceDataReadSize.WholeElement:
1407                     //Get whole element data, size will depend on the readLocationType
1408                     break;
1409                 case DeviceDataReadSize.ChunkOfElement:
1410                     if (commandParamsCount != 2)
1411                     {
1412                         parent.Log(LogLevel.Error, "ReadDeviceData: invalid param count for ChunkOfElement read size");
1413                         return ResponseCode.Abort;
1414                     }
1415                     //Get chunk of element, need to check if we remain in bounds
1416                     break;
1417                 case DeviceDataReadSize.OneWord:
1418                     //Get one word from specified offset
1419                     break;
1420                 case DeviceDataReadSize.GetSize:
1421                     //Get size of element
1422                     break;
1423                 case DeviceDataReadSize.GetValue:
1424                     if (readLocation != 0)
1425                     {
1426                         return ResponseCode.InvalidParameter;
1427                     }
1428                     //Get value corresponding to address (only for CC section)
1429                     break;
1430                 default:
1431                     return ResponseCode.InvalidParameter;
1432             }
1433 
1434             // First output DMA descriptor contains the location to which we send the data
1435             uint outputDataPtr;
1436             uint outputDataLength;
1437             DmaTranferOptions transferOptions;
1438             uint nextDescriptorPtr;
1439             UnpackDmaDescriptor(outputDma, out outputDataPtr, out outputDataLength, out transferOptions, out nextDescriptorPtr, machine);
1440             parent.Log(LogLevel.Noisy, "ReadDeviceData: OUTPUT0: outputDataPtr=0x{0:X} outputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1441                      outputDataPtr, outputDataLength, transferOptions, nextDescriptorPtr);
1442 
1443             // For now, return 1 regardless of the location/option selected
1444             machine.SystemBus.WriteDoubleWord(outputDataPtr, output);
1445             return ResponseCode.Ok;
1446         }
1447 
HandleFlashEraseDataRegionCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)1448         private ResponseCode HandleFlashEraseDataRegionCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)
1449         {
1450             if (commandParamsCount != 2)
1451             {
1452                 parent.Log(LogLevel.Error, "FlashEraseDataRegion: invalid param count {0}", commandParamsCount);
1453                 return ResponseCode.InvalidParameter;
1454             }
1455 
1456             // check that flash is properly initialized
1457             if (series3 && (flashSize == 0 || flashPageSize == 0))
1458             {
1459                 parent.Log(LogLevel.Error, "flashSize = {0} and flashPageSize = {1}. These must be initialized with non-zero values.", flashSize, flashPageSize);
1460                 return ResponseCode.Abort;
1461             }
1462 
1463             // For erase operations, the address may be any within the page to be erased.
1464             uint startAddress = commandParams[0] & ~(flashPageSize - 1);
1465             uint sectorsCount = commandParams[1];
1466 
1467             parent.Log(LogLevel.Noisy, "FLASH_ERASE_DATA_REGION: startAddress=0x{0:X} sectorNumber={1}", startAddress, sectorsCount);
1468 
1469             machine.ClockSource.ExecuteInLock(delegate {
1470                 for (uint i = 0; i < sectorsCount; i++)
1471                 {
1472                     for(uint addr = startAddress + i*flashPageSize; addr < startAddress + (i+1)*flashPageSize; addr += 4)
1473                     {
1474                         machine.SystemBus.WriteDoubleWord(addr, 0xFFFFFFFF);
1475                     }
1476                 }
1477             });
1478             return ResponseCode.Ok;
1479         }
1480 
HandleFlashWriteDataRegionCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)1481         private ResponseCode HandleFlashWriteDataRegionCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)
1482         {
1483             if (commandParamsCount != 2)
1484             {
1485                 parent.Log(LogLevel.Error, "FlashWriteDataRegion: invalid param count {0}", commandParamsCount);
1486                 return ResponseCode.InvalidParameter;
1487             }
1488             // check that flash is properly initialized
1489             if (series3 && (flashSize == 0 || flashPageSize == 0))
1490             {
1491                 parent.Log(LogLevel.Error, "flashSize = {0} and flashPageSize = {1}. These must be initialized with non-zero values.", flashSize, flashPageSize);
1492                 return ResponseCode.Abort;
1493             }
1494 
1495             uint startAddress = commandParams[0];
1496             uint writeLength = commandParams[1];
1497 
1498             parent.Log(LogLevel.Noisy, "FLASH_WRITE_DATA: startAddress=0x{0:X} length={1}", startAddress, writeLength);
1499 
1500             // First input DMA descriptor contains the data to be written
1501             uint inputDataPtr;
1502             uint inputDataLength;
1503             DmaTranferOptions transferOptions;
1504             uint nextDescriptorPtr;
1505             UnpackDmaDescriptor(inputDma, out inputDataPtr, out inputDataLength, out transferOptions, out nextDescriptorPtr, machine);
1506             parent.Log(LogLevel.Noisy, "FLASH_WRITE_DATA: INPUT0: inputDataPtr=0x{0:X} inputDataLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1507                      inputDataPtr, inputDataLength, transferOptions, nextDescriptorPtr);
1508 
1509             machine.ClockSource.ExecuteInLock(delegate {
1510                 for(uint i = 0; i<writeLength; i+=4)
1511                 {
1512                     uint word = machine.SystemBus.ReadDoubleWord(inputDataPtr + i);
1513                     machine.SystemBus.WriteDoubleWord(startAddress + i, word);
1514                 }
1515             });
1516             return ResponseCode.Ok;
1517         }
1518 
HandleFlashGetDataRegionLocationCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)1519         private ResponseCode HandleFlashGetDataRegionLocationCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)
1520         {
1521             if (commandParamsCount != 0)
1522             {
1523                 parent.Log(LogLevel.Error, "FlashGetDataRegionLocation: invalid param count {0}", commandParamsCount);
1524                 return ResponseCode.InvalidParameter;
1525             }
1526 
1527             // First output DMA descriptor contains the data region address
1528             uint outputDataRegionAddressPtr;
1529             uint outputDataRegionAddressLength;
1530             DmaTranferOptions transferOptions;
1531             uint nextDescriptorPtr;
1532             UnpackDmaDescriptor(outputDma, out outputDataRegionAddressPtr, out outputDataRegionAddressLength, out transferOptions, out nextDescriptorPtr, machine);
1533             parent.Log(LogLevel.Noisy, "FLASH_GET_DATA_REGION_LOC: OUTPUT0: outputDataRegionAddressPtr=0x{0:X} outputDataRegionAddressLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1534                      outputDataRegionAddressPtr, outputDataRegionAddressLength, transferOptions, nextDescriptorPtr);
1535 
1536             // Second output DMA descriptor contains the data region length
1537             uint outputDataRegionLengthPtr;
1538             uint outputDataRegionLengthLength;
1539             UnpackDmaDescriptor(nextDescriptorPtr, out outputDataRegionLengthPtr, out outputDataRegionLengthLength, out transferOptions, out nextDescriptorPtr, machine);
1540             parent.Log(LogLevel.Noisy, "FLASH_GET_DATA_REGION_LOC: OUTPUT1: outputDataRegionLengthPtr=0x{0:X} outputDataRegionLengthLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1541                      outputDataRegionLengthPtr, outputDataRegionLengthLength, transferOptions, nextDescriptorPtr);
1542 
1543 
1544             // check that flash is properly initialized
1545             if (series3 && (flashSize == 0 || flashPageSize == 0))
1546             {
1547                 parent.Log(LogLevel.Error, "flashSize = {0} and flashPageSize = {1}. These must be initialized with non-zero values.", flashSize, flashPageSize);
1548                 return ResponseCode.Abort;
1549             }
1550             uint flashDataSpaceLength = GetInitialDataSpaceLength;
1551             machine.SystemBus.WriteDoubleWord(outputDataRegionAddressPtr, QspiFlashHostBase + (flashSize - flashDataSpaceLength));
1552             machine.SystemBus.WriteDoubleWord(outputDataRegionLengthPtr, flashDataSpaceLength);
1553             return ResponseCode.Ok;
1554         }
1555 
HandleFlashGetCodeRegionConfigCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)1556         private ResponseCode HandleFlashGetCodeRegionConfigCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)
1557         {
1558             if (commandParamsCount != 0)
1559             {
1560                 parent.Log(LogLevel.Error, "HandleFlashGetCodeRegionConfigCommand: invalid param count {0}", commandParamsCount);
1561                 return ResponseCode.InvalidParameter;
1562             }
1563 
1564             // Output DMA descriptor contains the region config array
1565             uint outputCodeRegionConfigAddressPtr;
1566             uint outputCodeRegionConfigAddressLength;
1567             DmaTranferOptions transferOptions;
1568             uint nextDescriptorPtr;
1569             UnpackDmaDescriptor(outputDma, out outputCodeRegionConfigAddressPtr, out outputCodeRegionConfigAddressLength, out transferOptions, out nextDescriptorPtr, machine);
1570             parent.Log(LogLevel.Noisy, "FLASH_GET_CODE_REGION_CONFIG: OUTPUT0: outputCodeRegionConfigAddressPtr=0x{0:X} outputCodeRegionConfigAddressLength={1} options={2} nextDescriptorPtr=0x{3:X}",
1571                      outputCodeRegionConfigAddressPtr, outputCodeRegionConfigAddressLength, transferOptions, nextDescriptorPtr);
1572 
1573             // check that flash is properly initialized
1574             if (series3 && (flashSize == 0 || flashPageSize == 0))
1575             {
1576                 parent.Log(LogLevel.Error, "flashSize = {0} and flashPageSize = {1}. These must be initialized with non-zero values.", flashSize, flashPageSize);
1577                 return ResponseCode.Abort;
1578             }
1579 
1580             uint regionSize = (outputCodeRegionConfigAddressPtr & 0xFFF) * 32 * 1024; // Bits 0:11
1581             uint protectionMode = (outputCodeRegionConfigAddressPtr >> 12) & 0x3; // Bits 12:13
1582             bool bankSwappingEnabled = ((outputCodeRegionConfigAddressPtr >> 14) & 0x1) == 1; // Bit 14
1583             bool regionClosed = ((outputCodeRegionConfigAddressPtr >> 15) & 0x1) == 1; // Bit 15
1584 
1585             uint data = (regionSize / (32 * 1024)) & 0xFFF; // Bits 0:11
1586             data |= (protectionMode & 0x3) << 12; // Bits 12:13
1587             data |= (bankSwappingEnabled ? 1u : 0u) << 14; // Bit 14
1588             data |= (regionClosed ? 1u : 0u) << 15; // Bit 15
1589 
1590             machine.SystemBus.WriteDoubleWord(outputCodeRegionConfigAddressPtr, data);
1591 
1592             return ResponseCode.Ok;
1593         }
1594 
HandleConfigureQspiRefClockCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)1595         private ResponseCode HandleConfigureQspiRefClockCommand(uint inputDma, uint outputDma, uint[] commandParams, uint commandParamsCount, uint commandOptions)
1596         {
1597             switch (commandOptions)
1598             {
1599                 case 0x01:
1600                 case 0x0100:
1601                     // Set FSRCO as the QSPI controller clock source
1602                     if (commandParamsCount != 0)
1603                     {
1604                         parent.Log(LogLevel.Error, "ConfigureQspiRefClock: invalid param count {0} for option 0x01", commandParamsCount);
1605                         return ResponseCode.InvalidParameter;
1606                     }
1607                     parent.Log(LogLevel.Noisy, "QSPI Clock Source set to FSRCO");
1608                     break;
1609 
1610                 case 0x02:
1611                 case 0x0200:
1612                     // Set FLPLL as the QSPI controller clock source
1613                     if (commandParamsCount != 4)
1614                     {
1615                         parent.Log(LogLevel.Error, "ConfigureQspiRefClock: invalid param count {0} for option 0x02", commandParamsCount);
1616                         return ResponseCode.InvalidParameter;
1617                     }
1618 
1619                     uint flpllRefClock = commandParams[0];
1620                     uint intDiv = (commandParams[1] >> 16) & 0xFFFF;
1621                     uint fracDiv = commandParams[1] & 0xFFFF;
1622                     uint flpllFreqRange = commandParams[2] & 0xF;
1623                     uint qspiClockPrescaler = (commandParams[2] >> 4) & 0xF;
1624 
1625                     if (flpllRefClock != 0x0 && flpllRefClock != 0x2)
1626                     {
1627                         parent.Log(LogLevel.Error, "ConfigureQspiRefClock: invalid FLPLL reference clock {0}", flpllRefClock);
1628                         return ResponseCode.InvalidParameter;
1629                     }
1630                     if (fracDiv >= 2048 || intDiv <= 5 || intDiv >= 12)
1631                     {
1632                         parent.Log(LogLevel.Error, "ConfigureQspiRefClock: invalid INT_DIV {0} or FRAC_DIV {1}", intDiv, fracDiv);
1633                         return ResponseCode.InvalidParameter;
1634                     }
1635 
1636                     parent.Log(LogLevel.Noisy, "QSPI Clock Source set to FLPLL");
1637                     parent.Log(LogLevel.Noisy, "FLPLL Ref Clock: {0}, INT_DIV: {1}, FRAC_DIV: {2}, Freq Range: {3}, Prescaler: {4}",
1638                         flpllRefClock, intDiv, fracDiv, flpllFreqRange, qspiClockPrescaler);
1639                     break;
1640 
1641                 default:
1642                     parent.Log(LogLevel.Error, "ConfigureQspiRefClock: invalid command option {0}", commandOptions);
1643                     return ResponseCode.InvalidParameter;
1644             }
1645 
1646             return ResponseCode.Ok;
1647         }
1648 #endregion
1649 
1650 #region command utility methods
FetchFromRam(uint sourcePointer, byte[] destination, uint destinationOffset, uint length)1651         private void FetchFromRam(uint sourcePointer, byte[] destination, uint destinationOffset, uint length)
1652         {
1653             for (uint i=0; i<length; i++)
1654             {
1655                 destination[destinationOffset + i] = (byte)machine.SystemBus.ReadByte(sourcePointer + i);
1656             }
1657         }
1658 
WriteToRam(byte[] source, uint sourceOffset, uint destinationPointer, uint length)1659         private void WriteToRam(byte[] source, uint sourceOffset, uint destinationPointer, uint length)
1660         {
1661             for (uint i=0; i<length; i++)
1662             {
1663                 machine.SystemBus.WriteByte(destinationPointer + i, source[sourceOffset + i]);
1664             }
1665         }
1666 
UnpackDmaDescriptor(uint dmaPointer, out uint dataPointer, out uint dataSize, out DmaTranferOptions options, out uint nextDescriptorPtr, Machine machine)1667         private void UnpackDmaDescriptor(uint dmaPointer, out uint dataPointer, out uint dataSize, out DmaTranferOptions options, out uint nextDescriptorPtr, Machine machine)
1668         {
1669             dataPointer = (uint)machine.SystemBus.ReadDoubleWord(dmaPointer);
1670             nextDescriptorPtr = (uint)machine.SystemBus.ReadDoubleWord(dmaPointer + 4);
1671             var word2 = (uint)machine.SystemBus.ReadDoubleWord(dmaPointer + 8);
1672             dataSize = word2 & 0xFFFFFFF;
1673             options = (DmaTranferOptions)(word2 >> 28);
1674 
1675             parent.Log(LogLevel.Noisy, "UnpackDmaDescriptor(): dataPointer=0x{0:X} dataSize={1} options={2} nextDescriptorPtr=0x{3:X}",
1676                      dataPointer, dataSize, options, nextDescriptorPtr);
1677             for(uint i = 0; i < dataSize; i+=4)
1678             {
1679                 parent.Log(LogLevel.Noisy, "UnpackDmaDescriptor(): DATA word{0}=0x{1:X}", i/4, machine.SystemBus.ReadDoubleWord(dataPointer+i));
1680             }
1681         }
1682 
UnpackKeyMetadata(uint keyMetadata, out uint index, out KeyType type, out KeyMode mode, out KeyRestriction restriction)1683         private void UnpackKeyMetadata(uint keyMetadata, out uint index, out KeyType type, out KeyMode mode, out KeyRestriction restriction)
1684         {
1685             // [31:28]
1686             type = (KeyType)((keyMetadata >> 28) & 0xF);
1687             // [27:26]
1688             mode = (KeyMode)((keyMetadata >> 26) & 0x3);
1689             // [25:24]
1690             restriction = (KeyRestriction)((keyMetadata >> 24) & 0x3);
1691             // [23:16]
1692             index = ((keyMetadata >> 16) & 0xFF);
1693 
1694             parent.Log(LogLevel.Noisy, "UnpackKeyMetadata(): keyMetadata=0x{0:X} index={1} type={2} mode={3} restriction={4}",
1695                      keyMetadata, index, type, mode, restriction);
1696         }
1697 
CreateHashEngine(ShaMode hashMode)1698         IDigest CreateHashEngine(ShaMode hashMode)
1699         {
1700             IDigest ret = null;
1701 
1702             switch(hashMode)
1703             {
1704                 case ShaMode.Sha1:
1705                     ret = new Sha1Digest();
1706                     break;
1707                 case ShaMode.Sha224:
1708                     ret = new Sha224Digest();
1709                     break;
1710                 case ShaMode.Sha256:
1711                     ret = new Sha256Digest();
1712                     break;
1713                 case ShaMode.Sha384:
1714                     ret = new Sha384Digest();
1715                     break;
1716                 case ShaMode.Sha512:
1717                     ret = new Sha512Digest();
1718                     break;
1719                 default:
1720                     parent.Log(LogLevel.Error, "CreateHashEngine(): invalid hash mode");
1721                     break;
1722             }
1723             return ret;
1724         }
1725 
CheckHashEngine(IDigest hashEngine, ShaMode hashMode)1726         bool CheckHashEngine(IDigest hashEngine, ShaMode hashMode)
1727         {
1728             bool ret = false;
1729 
1730             switch(hashMode)
1731             {
1732                 case ShaMode.Sha1:
1733                     if (hashEngine is Sha1Digest)
1734                     {
1735                         ret = true;
1736                     }
1737                     break;
1738                 case ShaMode.Sha224:
1739                     if (hashEngine is Sha224Digest)
1740                     {
1741                         ret = true;
1742                     }
1743                     break;
1744                 case ShaMode.Sha256:
1745                     if (hashEngine is Sha256Digest)
1746                     {
1747                         ret = true;
1748                     }
1749                     break;
1750                 case ShaMode.Sha384:
1751                     if (hashEngine is Sha384Digest)
1752                     {
1753                         ret = true;
1754                     }
1755                     break;
1756                 case ShaMode.Sha512:
1757                     if (hashEngine is Sha512Digest)
1758                     {
1759                         ret = true;
1760                     }
1761                     break;
1762                 default:
1763                     parent.Log(LogLevel.Error, "CheckHashEngine(): invalid hash mode");
1764                     break;
1765             }
1766             return ret;
1767         }
1768 
IsTagSizeValid(uint tagSize)1769         bool IsTagSizeValid(uint tagSize)
1770         {
1771             // Tag size must be 0, 4, 6, 8, 10, 12, 14 or 16 bytes
1772             return (tagSize == 0 || tagSize == 4 || tagSize == 6 || tagSize == 8 || tagSize == 10 || tagSize == 12 || tagSize == 14 || tagSize == 16);
1773         }
1774 
IsNonceSizeValid(uint nonceSize)1775         bool IsNonceSizeValid(uint nonceSize)
1776         {
1777             return (nonceSize >= 8 && nonceSize <= 13);
1778         }
1779 
IsDataLengthValid(uint dataSize, CryptoMode cryptoMode)1780         bool IsDataLengthValid(uint dataSize, CryptoMode cryptoMode)
1781         {
1782             bool lengthOk = false;
1783             switch(cryptoMode)
1784             {
1785                 case CryptoMode.Ecb:
1786                 case CryptoMode.Cfb:
1787                 case CryptoMode.Ofb:
1788                     // Must be > 0 and multiple of 16
1789                     lengthOk = ((dataSize > 0) && ((dataSize & 0xF) == 0));
1790                     break;
1791                 case CryptoMode.Cbc:
1792                     // Must be > 16
1793                     lengthOk = (dataSize >= 16);
1794                     break;
1795                 case CryptoMode.Ctr:
1796                     // Must be > 0
1797                     lengthOk = (dataSize > 0);
1798                     break;
1799             }
1800             return lengthOk;
1801         }
1802 
GetTagLength(uint tagLengthOption)1803         uint GetTagLength(uint tagLengthOption)
1804         {
1805             uint tagLength;
1806             switch (tagLengthOption)
1807             {
1808                 case 0x4:
1809                     tagLength = 4;
1810                     break;
1811                 case 0x8:
1812                     tagLength = 8;
1813                     break;
1814                 case 0xC:
1815                     tagLength = 12;
1816                     break;
1817                 case 0xD:
1818                     tagLength = 13;
1819                     break;
1820                 case 0xE:
1821                     tagLength = 14;
1822                     break;
1823                 case 0xF:
1824                     tagLength = 15;
1825                     break;
1826                 default:
1827                     tagLength = 16;
1828                     break;
1829             }
1830             return tagLength;
1831         }
1832 
CheckAndRetrieveKey(KeyType keyType, KeyMode keyMode, uint keyIndex, uint keyPointer)1833         private byte[] CheckAndRetrieveKey(KeyType keyType, KeyMode keyMode, uint keyIndex, uint keyPointer)
1834         {
1835             byte[] key = new byte[16];
1836 
1837             // TODO: for now we only support "raw" key type.
1838             if (keyType != KeyType.Raw)
1839             {
1840                 parent.Log(LogLevel.Error, "Key TYPE not supported");
1841                 return key;
1842             }
1843 
1844             // TODO: for now we don't support "WrappedAntiReplay" key mode.
1845             if (keyMode == KeyMode.WrappedAntiReplay)
1846             {
1847                 parent.Log(LogLevel.Error, "Key MODE WrappedAntiReplay not supported");
1848                 return key;
1849             }
1850 
1851             if (keyMode == KeyMode.Unprotected || keyMode == KeyMode.Wrapped)
1852             {
1853                 // IV - 12 bytes
1854                 // Actual key
1855                 // AESGCM tag - 16 bytes
1856                 uint keyOffset = 12;
1857                 FetchFromRam(keyPointer + keyOffset, key, 0, 16);
1858             }
1859             else if (keyMode == KeyMode.Volatile)
1860             {
1861                 if (!volatileKeys.ContainsKey(keyIndex))
1862                 {
1863                     parent.Log(LogLevel.Error, "Volatile key not found");
1864                     return key;
1865                 }
1866 
1867                 key = volatileKeys[keyIndex];
1868                 parent.Log(LogLevel.Noisy, "CheckAndRetrieveKey (volatile): keyIndex={0} key=[{1}]", keyIndex, BitConverter.ToString(key));
1869             }
1870 
1871             return key;
1872         }
1873 
1874         private uint GetInitialDataSpaceLength
1875         {
1876             get
1877             {
1878                 return flashSize - flashDataRegionStart;
1879             }
1880         }
1881 #endregion
1882 
1883 #region enums
1884         private enum CommandId
1885         {
1886             ImportKey                       = 0x0100,
1887             ExportKey                       = 0x0102,
1888             DeleteKey                       = 0x0105,
1889             TransferKey                     = 0x0106,
1890             InstallKey                      = 0x0107,
1891             CreateKey                       = 0x0200,
1892             ReadPublicKey                   = 0x0201,
1893             DeriveKey                       = 0x0202,
1894             Hash                            = 0x0300,
1895             HashUpdate                      = 0x0301,
1896             HashHmac                        = 0x0302,
1897             HashFinish                      = 0x0303,
1898             AesEncrypt                      = 0x0400,
1899             AesDecrypt                      = 0x0401,
1900             AesGcmEncrypt                   = 0x0402,
1901             AesGcmDecrypt                   = 0x0403,
1902             AesCmac                         = 0x0404,
1903             AesCcmEncrypt                   = 0x0405,
1904             AesCcmDecrypt                   = 0x0406,
1905             ReadDeviceData                  = 0x4330,
1906             Random                          = 0x0700,
1907             ConfigureQspiRefClock           = 0xFF15,
1908             FlashGetCodeRegionConfig        = 0xFF53,
1909             FlashEraseDataRegion            = 0xFF62,
1910             FlashWriteDataRegion            = 0xFF63,
1911             FlashGetDataRegionLocation      = 0xFF64,
1912         }
1913 
1914         private enum ShaMode
1915         {
1916             Sha1    = 0x2,
1917             Sha224  = 0x3,
1918             Sha256  = 0x4,
1919             Sha384  = 0x5,
1920             Sha512  = 0x6,
1921         }
1922 
1923         private enum CryptoMode
1924         {
1925             Ecb = 0x1,
1926             Cbc = 0x2,
1927             Ctr = 0x3,
1928             Cfb = 0x4,
1929             Ofb = 0x5,
1930         }
1931 
1932         private enum ContextMode
1933         {
1934             WholeMessage    = 0x0,
1935             StartOfMessage  = 0x1,
1936             EndOfMessage    = 0x2,
1937             MiddleOfMessage = 0x3,
1938         }
1939 
1940         private enum DmaTranferOptions
1941         {
1942             Register       = 0x1,
1943             MemoryRealign  = 0x2,
1944             Discard        = 0x4,
1945         }
1946 
1947         private enum KeyRestriction
1948         {
1949             Unlocked   = 0x0,
1950             Locked     = 0x1,
1951             Internal   = 0x2,
1952             Restricted = 0x3,
1953         }
1954 
1955         private enum KeyMode
1956         {
1957             Unprotected        = 0x0,
1958             Volatile           = 0x1,
1959             Wrapped            = 0x2,
1960             WrappedAntiReplay  = 0x3,
1961         }
1962 
1963         private enum KeyType
1964         {
1965             Raw                         = 0x0,
1966             EccWeirstrabPrimeFieldCurve = 0x8,
1967             EccMontgomeryCurve          = 0xB,
1968             Ed25519                     = 0xC,
1969         }
1970 
1971         public enum ResponseCode
1972         {
1973             Ok                 = 0x00000000,
1974             InvalidCommand     = 0x00010000,
1975             AuthorizationError = 0x00020000,
1976             InvalidSignature   = 0x00030000,
1977             BusError           = 0x00040000,
1978             InternalError      = 0x00050000,
1979             CryptoError        = 0x00060000,
1980             InvalidParameter   = 0x00070000,
1981             SecureBootError    = 0x00090000,
1982             SelfTestError      = 0x000A0000,
1983             NotInitialized     = 0x000B0000,
1984             MailboxInvalid     = 0x00FE0000,
1985             Abort              = 0x00FF0000,
1986         }
1987 
1988         private enum ReadDeviceDataLocationType
1989         {
1990             CC         = 0x0,
1991             DI         = 0x1,
1992             WaferProbe = 0x2,
1993         }
1994 
1995         private enum DeviceDataReadSize
1996         {
1997             WholeElement   = 0x00,
1998             ChunkOfElement = 0x01,
1999             OneWord        = 0x02,
2000             GetSize        = 0x03,
2001             GetValue       = 0x04,
2002         }
2003 #endregion
2004     }
2005 }