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 }