/// <summary> /// genAIS command. Always use section-by-section CRC checks /// </summary> /// <param name="mainObjectFileName"></param> /// <param name="bootMode"></param> /// <returns>Bytes of the binary or text AIS command</returns> public static Byte[] GenAIS( AISGen devAISGen, List<String> inputFileNames, IniFile iniFile ) { UInt32 numWords; // Setup the binary writer to generate the temp AIS file devAISGen.devAISStream = new MemoryStream(); using ( devAISGen.writer = new EndianBinaryWriter( devAISGen.devAISStream, devAISGen.devEndian) ) { // List to keep track of loadable sections and their occupied memory ranges devAISGen.sectionMemory = new List<MemoryRange>(); // Initiate list to keep track of the input files devAISGen.objectFiles = new List<ObjectFile>(); // Get data from the GENERAL INI Section GeneralIniSectionParse(devAISGen, iniFile); #region Main AIS Generation // --------------------------------------------------------- // ****************** BEGIN AIS GENERATION ***************** // --------------------------------------------------------- Console.WriteLine("Begining the AIS file generation."); // Diaplay currently selected boot mode Console.WriteLine("AIS file being generated for bootmode: {0}.",Enum.GetName(typeof(AisBootModes),devAISGen.bootMode)); // Write the premilinary header and fields (everything before first AIS command) devAISGen.InsertAISPreamble(); Debug.DebugMSG("Preamble Complete"); // Parse the INI sections in order, inserting needed AIS commands if (iniFile != null) { foreach(IniSection sec in iniFile.Sections) { InsertAISCommandViaINI(devAISGen, sec); } Debug.DebugMSG("INI parsing complete"); } // Insert the object file passed in on the top-level (if it exists) if (inputFileNames != null) { foreach (String fn in inputFileNames) { String[] nameAndAddr = fn.Split('@'); Debug.DebugMSG("Inserting file " + nameAndAddr[0]); if (!File.Exists(nameAndAddr[0])) { Console.WriteLine("ERROR: {0} does not exist. Aborting...", nameAndAddr[0]); return null; } if (nameAndAddr.Length == 2) { UInt32 loadAddr; nameAndAddr[1] = nameAndAddr[1].ToLower(); if (nameAndAddr[1].StartsWith("0x")) { if (!UInt32.TryParse(nameAndAddr[1].Replace("0x", ""), NumberStyles.HexNumber, null, out loadAddr)) { Console.WriteLine("WARNING: Invalid address format, {0}. Ignoring...", nameAndAddr[1]); } else { devAISGen.InsertAISObjectFile(nameAndAddr[0], loadAddr); } } else if (UInt32.TryParse(nameAndAddr[1], out loadAddr)) { devAISGen.InsertAISObjectFile(nameAndAddr[0], loadAddr); } else { Console.WriteLine("WARNING: Invalid address format, {0}. Ignoring...", nameAndAddr[1]); } } else if (nameAndAddr.Length == 1) { // If we still have not had a valid entry point set, then use entry point from // first encountered non-binary file in the inputFileNames list if (devAISGen.entryPoint == 0xFFFFFFFF) { devAISGen.InsertAISObjectFile(nameAndAddr[0], true); } else { devAISGen.InsertAISObjectFile(nameAndAddr[0], false); } } else { Console.WriteLine("WARNING: Invalid filename format, {0}. Ignoring...", fn); } } Debug.DebugMSG("Main input file insertion complete."); } // If CRC type is for single CRC, send Request CRC now if (devAISGen.aisCRCType == AisCRCCheckType.SINGLE_CRC) { devAISGen.InsertAISRequestCRC(); } // Insert closing JumpClose AIS command (issue warning) if (devAISGen.entryPoint == 0xFFFFFFFF) { // No valid entry point was ever set (issue warning) Console.WriteLine("WARNING: Entry point set to null pointer!"); devAISGen.InsertAISJumpClose(0x00000000); } else { devAISGen.InsertAISJumpClose(devAISGen.entryPoint); } // Flush the data and then return to start devAISGen.devAISStream.Flush(); devAISGen.devAISStream.Seek(0,SeekOrigin.Begin); Console.WriteLine("AIS file generation was successful."); // --------------------------------------------------------- // ******************* END AIS GENERATION ****************** // --------------------------------------------------------- #endregion // Now create return Byte array based on tempAIS file and the bootmode EndianBinaryReader tempAIS_br = new EndianBinaryReader(devAISGen.devAISStream, Endian.LittleEndian); // Setup the binary reader object numWords = ((UInt32)tempAIS_br.BaseStream.Length) >> 2; devAISGen.AISData = new Byte[numWords << 2]; //Each word converts to 4 binary bytes Debug.DebugMSG("Number of words in the AIS output is {0}", numWords); // Copy the data to the output Byte array for (UInt32 i = 0; i < numWords; i++) { BitConverter.GetBytes(tempAIS_br.ReadUInt32()).CopyTo(devAISGen.AISData, i * 4); } // Close the binary reader tempAIS_br.Close(); } // Dispose of all object files foreach (ObjectFile file in devAISGen.objectFiles) { try { file.Dispose(); } catch (Exception e) { Console.WriteLine(e.Message); } } // Clean up any embedded file resources that may have been extracted EmbeddedFileIO.CleanUpEmbeddedFiles(); // Return Byte Array return devAISGen.AISData; }
/// <summary> /// SecureGenAIS command. /// </summary> /// <param name="inputFileNames">File name of input .out file</param> /// <param name="bootMode">AISGen Object for the particular device</param> /// <returns>Bytes of the binary or AIS boot image</returns> public static Byte[] SecureGenAIS(AISGen devAISGen, List<String> inputFileNames, IniFile iniFile) { UInt32 numWords; // Set defaults devAISGen.bootLoaderExitType = BootLoaderExitType.NONE; devAISGen.currHashAlgorithmValue = SHA_Algorithm.SHA1; devAISGen.sectionsToEncrypt = null; devAISGen.rsaObject = null; devAISGen.customerEncryptionKey = null; devAISGen.keyEncryptionKey = null; devAISGen.genericKeyHeaderData = null; devAISGen.currHashAlgorithm = null; // Setup the binary writer to generate the temp AIS file devAISGen.sigStream = new MemoryStream(); devAISGen.devAISStream = new MemoryStream(); devAISGen.sigWriter = new EndianBinaryWriter( devAISGen.sigStream, devAISGen.devEndian); using ( devAISGen.writer = new EndianBinaryWriter( devAISGen.devAISStream, devAISGen.devEndian) ) { // List to keep track of loadable sections and their occupied memory ranges devAISGen.sectionMemory = new List<MemoryRange>(); // Initiate list to keep track of the input files devAISGen.objectFiles = new List<ObjectFile>(); // Get data from the GENERAL INI Section GeneralIniSectionParse(devAISGen, iniFile); // Get data from the SECURITY INI Section if (SecurityIniSectionParse(devAISGen, iniFile) != retType.SUCCESS) { Console.WriteLine("Aborting..."); return null; } #region Handle the case of Legacy boot mode if (devAISGen.bootMode == AisBootModes.LEGACY) { UInt32 fileSize = 0, secureDataSize = 0, totalImgSize = 0, paddingSize = 0; UInt32 loadAddr = 0, fileCount = 0; Byte[] fileData; String fileName = null; Boolean encryptSections = false; UInt32 entryPointAddr = 0x00000000; // Check for legacy input file foreach( IniSection sec in iniFile.Sections) { if (sec.sectionName.Equals("LEGACYINPUTFILE", StringComparison.OrdinalIgnoreCase)) { fileCount++; foreach (DictionaryEntry de in sec.sectionValues) { // File name for binary section data if (((String)de.Key).Equals("FILENAME", StringComparison.OrdinalIgnoreCase)) { fileName = (String) sec.sectionValues["FILENAME"]; } // Binary section's load address in the memory map if (((String)de.Key).Equals("LOADADDRESS", StringComparison.OrdinalIgnoreCase)) { loadAddr = (UInt32) sec.sectionValues["LOADADDRESS"]; } // Binary section's entry point address in the memory map if (((String)de.Key).Equals("ENTRYPOINTADDRESS", StringComparison.OrdinalIgnoreCase)) { entryPointAddr = (UInt32) sec.sectionValues["ENTRYPOINTADDRESS"]; } // Binary section's entry point address in the memory map if (((String)de.Key).Equals("ENCRYPT", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["ENCRYPT"]).Equals("YES", StringComparison.OrdinalIgnoreCase)) encryptSections = true; if (((String)sec.sectionValues["ENCRYPT"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) encryptSections = true; } } if (fileName == null) { Console.WriteLine("ERROR: File name must be provided in INPUTFILE section."); return null; } // Insert the file into the AIS image if (( entryPointAddr == 0x00000000)) { Console.WriteLine("Entrypoint Address = {0} is not valid.", entryPointAddr); return null; } } } // Validate an input binary file was given in the INI file if (fileCount == 0) { Console.WriteLine("ERROR: You did not supply a binary file section in the INI file!"); return null; } if (fileCount > 1) { Console.WriteLine("WARNING: You supplied too many binary file sections in the INI file."); Console.WriteLine(" Only using the first one."); } // Figure out the size of the secure data region (signature + keystruct) if (devAISGen.SecureType == AisSecureType.CUSTOM) { // On custom secure we have rsa keySize bits for signature and modulus of key struct, // plus eight additional bytes from key struct secureDataSize = (UInt32) (8 + (devAISGen.rsaObject.KeySize >> 3) + (devAISGen.rsaObject.KeySize >> 3)); } else if (devAISGen.SecureType == AisSecureType.GENERIC) { // On generic secure we have 32 for key and HashSize bits rounded up to nearst 16 bytes // for signature data. secureDataSize = (UInt32) (32 + ((((devAISGen.currHashAlgorithm.HashSize >> 3)+15)>>4)<<4)); } // Verify legacy input binary file exists, and get data if it does if (File.Exists(fileName)) { Byte[] tempFileData = FileIO.GetFileData(fileName); fileSize = (UInt32) tempFileData.Length; totalImgSize = 16 + fileSize + secureDataSize; if (totalImgSize > 16*1024) { Console.WriteLine("WARNING: The input image is too large for the ROM boot loader."); Console.WriteLine("Reduce its size by {0} bytes.", (totalImgSize - (16*1024))); } // Figure out how much to pad input file region to acheive complete image ending on 1K boundary paddingSize = (((totalImgSize+1023) >> 10) << 10) - totalImgSize; // Copy to final data array of fileSize fileSize = fileSize + paddingSize; fileData = new Byte[fileSize]; tempFileData.CopyTo(fileData,0); // Adjust total image size to final amount totalImgSize = 16 + fileSize + secureDataSize; } else { Console.WriteLine("Error: Binary file was not found!"); return null; } if ( ((entryPointAddr & 0x00FFFFFF) < loadAddr) || ((entryPointAddr & 0x00FFFFFF) > (loadAddr+fileSize)) ) { Console.WriteLine("ERROR: Entry point falls outside load image region."); return null; } // Place header // Config Word - indicates total image size, nor width (if applicable) if (devAISGen.busWidth == 16) { devAISGen.writer.Write ((UInt32)(((((totalImgSize >> 10)-1) & 0xFFFF) << 8)|(0x1 << 0)|(0x0 << 4))); devAISGen.sigWriter.Write((UInt32)(((((totalImgSize >> 10)-1) & 0xFFFF) << 8)|(0x1 << 0)|(0x0 << 4))); } else { devAISGen.writer.Write ((UInt32)(((((totalImgSize >> 10)-1) & 0xFFFF) << 8)|(0x0 << 0)|(0x0 << 4))); devAISGen.sigWriter.Write((UInt32)(((((totalImgSize >> 10)-1) & 0xFFFF) << 8)|(0x0 << 0)|(0x0 << 4))); } // Magic Number - indicates signed or encrypted if (encryptSections) { devAISGen.writer.Write((UInt32)SecureLegacyMagic.ENCMOD_MAGIC); devAISGen.sigWriter.Write((UInt32)SecureLegacyMagic.ENCMOD_MAGIC); } else { devAISGen.writer.Write((UInt32)SecureLegacyMagic.SIGNMOD_MAGIC); devAISGen.sigWriter.Write((UInt32)SecureLegacyMagic.SIGNMOD_MAGIC); } // Entry Point - where to jump within the image upon load devAISGen.writer.Write( entryPointAddr ); devAISGen.sigWriter.Write( entryPointAddr ); // SecureDataSize - size of data following image for key struct & signature devAISGen.writer.Write( (UInt32)secureDataSize ); devAISGen.sigWriter.Write( (UInt32)secureDataSize ); // Now place padded binary contents if (!encryptSections) { // Non-encrypted section devAISGen.writer.Write(fileData); devAISGen.sigWriter.Write(fileData); } else { // Encrypted section // Write unencrypted data to the signature buffer devAISGen.sigWriter.Write(fileData); // Encrypt data using CBC algorithm try { Byte[] encData = AesManagedUtil.AesCTSEncrypt(fileData,devAISGen.customerEncryptionKey,devAISGen.CEKInitialValue); // Write encrypted section data out to AIS data stream devAISGen.writer.Write(encData); } catch(Exception e) { Console.WriteLine("Exception during encryption operation: {0}",e.Message); } } // Now place the key data devAISGen.writer.Write(devAISGen.secureKeyData); devAISGen.sigWriter.Write(devAISGen.secureKeyData); // Finally place the signature which covers the entire image InsertAISSecureSignature( devAISGen ); // Flush the data and then return to start devAISGen.devAISStream.Flush(); devAISGen.devAISStream.Seek(0,SeekOrigin.Begin); devAISGen.sigStream.Close(); } #endregion #region AIS Generation else { // --------------------------------------------------------- // ****************** BEGIN AIS GENERATION ***************** // --------------------------------------------------------- Console.WriteLine("Begining the Secure AIS file generation."); // Diaplay currently selected boot mode Console.WriteLine("AIS file being generated for bootmode: {0}.",Enum.GetName(typeof(AisBootModes),devAISGen.bootMode)); // Write the premilinary header and fields (everything before first AIS command) devAISGen.InsertAISPreamble(); Debug.DebugMSG("Preamble Complete"); // Write the Secure Key command and key data devAISGen.InsertAISSecureKeyLoad(devAISGen.secureKeyData); Debug.DebugMSG("Secure Key Insertion Complete"); // Insert Exit Mode type devAISGen.InsertAISSetExitMode(devAISGen.bootLoaderExitType); Debug.DebugMSG("Set Exit Mode complete"); // Parse the INI sections in order, inserting needed AIS commands foreach(IniSection sec in iniFile.Sections) { InsertSecureAISCommandViaINI(devAISGen, sec); } Debug.DebugMSG("INI parsing complete"); // Insert the object file(s) passed in on the top-level (if it exists) foreach (String fn in inputFileNames) { String[] nameAndAddr = fn.Split('@'); Debug.DebugMSG("Inserting file " + nameAndAddr[0]); if (!File.Exists(nameAndAddr[0])) { Console.WriteLine("ERROR: {0} does not exist. Aborting...", nameAndAddr[0]); return null; } // Handle binary files provided with a load address if (nameAndAddr.Length == 2) { UInt32 loadAddr; nameAndAddr[1] = nameAndAddr[1].ToLower(); if (nameAndAddr[1].StartsWith("0x")) { if (!UInt32.TryParse(nameAndAddr[1].Replace("0x", ""), NumberStyles.HexNumber, null, out loadAddr)) { Console.WriteLine("WARNING: Invalid address format, {0}. Ignoring...", nameAndAddr[1]); } else { devAISGen.InsertAISSecureObjectFile(nameAndAddr[0], loadAddr, false); } } else if (UInt32.TryParse(nameAndAddr[1], out loadAddr)) { devAISGen.InsertAISSecureObjectFile(nameAndAddr[0], loadAddr, false); } else { Console.WriteLine("WARNING: Invalid address format, {0}. Ignoring...", nameAndAddr[1]); } } // Handle Object files (ones provided without load address) else if (nameAndAddr.Length == 1) { // If we still have not had a valid entry point set, then use entry point from // first encountered non-binary file in the inputFileNames list if (devAISGen.entryPoint == 0xFFFFFFFF) { devAISGen.InsertAISSecureObjectFile(nameAndAddr[0], true, false); } else { devAISGen.InsertAISSecureObjectFile(nameAndAddr[0], false, false); } } else { Console.WriteLine("WARNING: Invalid filename format, {0}. Ignoring...", fn); } } Debug.DebugMSG("Main input file insertion complete."); // Insert closing JumpClose AIS command (issue warning) if (devAISGen.entryPoint == 0x00000000) { Console.WriteLine("WARNING: Entry point set to null pointer!"); } devAISGen.InsertAISJumpClose(devAISGen.entryPoint); // Insert final Signature InsertAISSecureSignature(devAISGen); // Flush the data and then return to start devAISGen.devAISStream.Flush(); devAISGen.devAISStream.Seek(0,SeekOrigin.Begin); Console.WriteLine("AIS file generation was successful."); // --------------------------------------------------------- // ******************* END AIS GENERATION ****************** // --------------------------------------------------------- } #endregion // Now create return byte array based on AIS Stream data EndianBinaryReader tempAIS_br = new EndianBinaryReader(devAISGen.devAISStream,Endian.LittleEndian); numWords = ((UInt32)tempAIS_br.BaseStream.Length) >> 2; devAISGen.AISData = new Byte[numWords << 2]; //Each word converts to 4 binary bytes Debug.DebugMSG("Number of words in the stream is {0}", numWords); // Copy the data to the output Byte array for (UInt32 i = 0; i < numWords; i++) { BitConverter.GetBytes(tempAIS_br.ReadUInt32()).CopyTo(devAISGen.AISData, i * 4); } // Close the binary reader tempAIS_br.Close(); } // Dispose of all object files foreach (ObjectFile file in devAISGen.objectFiles) { try { file.Dispose(); } catch (Exception e) { Console.WriteLine(e.Message); } } // Clean up any embedded file resources that may have been extracted EmbeddedFileIO.CleanUpEmbeddedFiles(); // Return Byte Array return devAISGen.AISData; }