├── .gitignore ├── AmigaROMHashes.h ├── AmigaROMMajorMinorVersions.h ├── AmigaROMUtil.c ├── AmigaROMUtil.h ├── LICENSE ├── Makefile ├── README.md ├── RemusTools.h ├── main.c └── teeny-sha1.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.obj 3 | *.lib 4 | *.dll 5 | *.o 6 | *.a 7 | *.so 8 | *.dylib 9 | AmigaROMUtil -------------------------------------------------------------------------------- /AmigaROMHashes.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2025 Christopher Gelatt 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #ifndef AMIGAROMHASHES_H 26 | #define AMIGAROMHASHES_H 27 | 28 | #include 29 | 30 | typedef struct { 31 | const char sha1hash[41]; 32 | const size_t file_size; 33 | const char version[128]; 34 | const char type; 35 | const int byte_swap; 36 | } AmigaROMInfo; 37 | 38 | static const AmigaROMInfo AMIGA_ROM_INFO[] = { 39 | // Merged, unswapped Kickstart ROMs 40 | {"fa685ebb666c3d8b09afe1329b7e41b443312f69", 262144, "AmigaOS 0.7b [27.003b] (A1000)", 'M', 0}, 41 | {"00c15406beb4b8ab1a16aa66c05860e1a7c1ad79", 262144, "AmigaOS 1.0 (A1000)", 'M', 0}, 42 | {"4192c505d130f446b2ada6bdc91dae730acafb4c", 262144, "AmigaOS 1.1 [31.034] (NTSC, A1000)", 'M', 0}, 43 | {"16df8b5fd524c5a1c7584b2457ac15aff9e3ad6d", 262144, "AmigaOS 1.1 [31.034] (PAL, A1000)", 'M', 0}, 44 | {"6a7bfb5dbd6b8f179f03da84d8d9528267b6273b", 262144, "AmigaOS 1.2 [33.166] (A500/A1000/A2000)", 'M', 0}, 45 | {"11f9e62cf299f72184835b7b2a70a16333fc0d88", 262144, "AmigaOS 1.2 [33.180] (A500/A1000/A2000)", 'M', 0}, 46 | {"891e9a547772fe0c6c19b610baf8bc4ea7fcb785", 262144, "AmigaOS 1.3 [34.005] (A500/A1000/A2000/CDTV)", 'M', 0}, 47 | {"c39bd9094d4e5f4e28c1411f3086950406062e87", 262144, "AmigaOS 1.3 [34.005] (A3000)", 'M', 0}, 48 | {"f76316bf36dff14b20fa349ed02e4b11dd932b07", 524288, "AmigaOS 1.4 [36.016] (A3000)", 'M', 0}, 49 | {"f2cc0cc8bf9321df63456c439884c15cda0fe752", 524288, "AmigaOS 2.02 [36.207] (A3000)", 'M', 0}, 50 | {"c5839f5cb98a7a8947065c3ed2f14f5f42e334a1", 524288, "AmigaOS 2.04 [37.175] (A500+)", 'M', 0}, 51 | {"d82ebb59afc53540ddf2d7187ecf239b7ea91590", 524288, "AmigaOS 2.04 [37.175] (A3000)", 'M', 0}, 52 | {"87508de834dc7eb47359cede72d2e3c8a2e5d8db", 524288, "AmigaOS 2.05 [37.299] (A600)", 'M', 0}, 53 | {"f72d89148dac39c696e30b10859ebc859226637b", 524288, "AmigaOS 2.05 [37.300] (A600HD)", 'M', 0}, 54 | {"02843c4253bbd29aba535b0aa3bd9a85034ecde4", 524288, "AmigaOS 2.05 [37.350] (A600HD)", 'M', 0}, 55 | {"70033828182fffc7ed106e5373a8b89dda76faa5", 524288, "AmigaOS 3.0 [39.106] (A1200)", 'M', 0}, 56 | {"f0b4e9e29e12218c2d5bd7020e4e785297d91fd7", 524288, "AmigaOS 3.0 [39.106] (A4000)", 'M', 0}, 57 | {"a268617888b2c8ffb10db85ea9b92d1129a0cd24", 524288, "AmigaOS 3.1 [40.055] (A3000)", 'M', 0}, 58 | {"3525be8887f79b5929e017b42380a79edfee542d", 524288, "AmigaOS 3.1 [40.060] (CD32)", 'M', 0}, 59 | {"3b7f1493b27e212830f989f26ca76c02049f09ca", 524288, "AmigaOS 3.1 [40.063] (A500/A600/A2000)", 'M', 0}, 60 | {"e21545723fe8374e91342617604f1b3d703094f1", 524288, "AmigaOS 3.1 [40.068] (A1200)", 'M', 0}, 61 | {"f8e210d72b4c4853e0c9b85d223ba20e3d1b36ee", 524288, "AmigaOS 3.1 [40.068] (A3000)", 'M', 0}, 62 | {"5fe04842d04a489720f0f4bb0e46948199406f49", 524288, "AmigaOS 3.1 [40.068] (A4000)", 'M', 0}, 63 | {"b0ec8b84d6768321e01209f11e6248f2f5281a21", 524288, "AmigaOS 3.1 [40.070] (A4000T)", 'M', 0}, 64 | {"7a9095f1107966f90267dc4cb3c1972efb4b78a8", 524288, "AmigaOS 3.2b [43.001b] (Walker)", 'M', 0}, 65 | {"3cbfc9e1fe396360157bd161de74fc901abee7ec", 524288, "AmigaOS 3.x AF3.0 [45.057] (A4000)", 'M', 0}, 66 | {"187adf4e016af8ebcdd3a63943638aa6039f37e3", 524288, "AmigaOS 3.x AF6.8 [45.061] (A4000)", 'M', 0}, 67 | {"e035bfee642e4dfa667db40c0553298774e538d0", 524288, "AmigaOS 3.x AF7.0 [45.061] (A500/A600/A2000)", 'M', 0}, 68 | {"676f706fe558ba87d1b6fcc82107d030781d08e7", 524288, "AmigaOS 3.x AF7.0 [45.061] (A1200)", 'M', 0}, 69 | {"2f0c6efa00ef8a6943a636fd002098964a05de32", 524288, "AmigaOS 3.x AF7.0 [45.061] (A3000)", 'M', 0}, 70 | {"d908162580417b00d32abe5ef130c64c93706c57", 524288, "AmigaOS 3.x AF7.0 [45.061] (A4000T)", 'M', 0}, 71 | {"abca7c05bde8bfc77e7a22d5e83727a50106e353", 524288, "AmigaOS 3.x AF7.1 [45.064] (A500/A600/A2000)", 'M', 0}, 72 | {"63076f74dc557cfb0b7e7b17d99f3a6f76d9276d", 524288, "AmigaOS 3.x AF7.1 [45.064] (A1200)", 'M', 0}, 73 | {"84d399c46b9d38d41da1bd3f99335a34feafa876", 524288, "AmigaOS 3.x AF7.1 [45.064] (A3000)", 'M', 0}, 74 | {"a681c63f6c075998a19e6e7707f6220f57cd307e", 524288, "AmigaOS 3.x AF7.1 [45.064] (A4000)", 'M', 0}, 75 | {"d553fc1416c6faf3a73fd8c056038c023df2321e", 524288, "AmigaOS 3.x AF7.1 [45.064] (A4000T)", 'M', 0}, 76 | {"46f15c7a50b45eed7cc1a1670b164aff71b01907", 524288, "AmigaOS 3.x AF8.0 [45.066] (A500/A600/A2000)", 'M', 0}, 77 | {"279c6a27f8cb81c74e10b263d20f03433f98dc07", 524288, "AmigaOS 3.x AF8.0 [45.066] (A1200)", 'M', 0}, 78 | {"10390d4169b1009e6c81f8a572cddd83127f583d", 524288, "AmigaOS 3.x AF8.0 [45.066] (A3000)", 'M', 0}, 79 | {"0e1a4b5062826d8e3520cce752f47409f4adef96", 524288, "AmigaOS 3.x AF8.0 [45.066] (A4000)", 'M', 0}, 80 | {"d5f1be640c38e7a8585567e4ed71b7d5e1ff772c", 524288, "AmigaOS 3.x AF8.0 [45.066] (A4000T)", 'M', 0}, 81 | {"8a2405087ce182225656dd0b93069c45743f9e34", 524288, "AmigaOS 3.1.4 [46.143] (A500/A600/A2000) (Old Copyright)", 'M', 0}, 82 | {"6355a9ed5dc840422f9b73308a91be0d0bb506bd", 524288, "AmigaOS 3.1.4 [46.143] (A1200) (Old Copyright)", 'M', 0}, 83 | {"dd42f228616af9159856365b906c17e700e5424c", 524288, "AmigaOS 3.1.4 [46.143] (A2000) (Old Copyright)", 'M', 0}, 84 | {"1a34b25a25e260e38e879172850143c80b461a64", 524288, "AmigaOS 3.1.4 [46.143] (A3000) (Old Copyright)", 'M', 0}, 85 | {"bad0ae388442db02eaeb6a5363ef43eb4e308ae6", 524288, "AmigaOS 3.1.4 [46.143] (A4000) (Old Copyright)", 'M', 0}, 86 | {"938a60a1d2c0d411f64bb27e5af40258b8decbf3", 524288, "AmigaOS 3.1.4 [46.143] (A4000T) (Old Copyright)", 'M', 0}, 87 | {"d81cd6f131040895843d9dfa95a45bc95edd9704", 524288, "AmigaOS 3.1.4 [46.143] (A500/A600/A2000) (New Copyright)", 'M', 0}, 88 | {"ef36c4638ee45de6bb93701761216c958cd0d57b", 524288, "AmigaOS 3.1.4 [46.143] (A1200) (New Copyright)", 'M', 0}, 89 | {"d73ae3a36f12bb49bbf6ba04a890ff7aac419015", 524288, "AmigaOS 3.1.4 [46.143] (A3000) (New Copyright)", 'M', 0}, 90 | {"aab44cd651e6b6f81a3effd8e0ba6b37ab322f32", 524288, "AmigaOS 3.1.4 [46.143] (A4000) (New Copyright)", 'M', 0}, 91 | {"cd73aefe9cbfc258e7966cd14a7b2f4647c9ba45", 524288, "AmigaOS 3.1.4 [46.143] (A4000T) (New Copyright)", 'M', 0}, 92 | {"b88e364daf23c9c9920e548b0d3d944e65b1031d", 524288, "AmigaOS 3.2 [47.096] (A500/A600/A1000/A2000/CDTV)", 'M', 0}, 93 | {"5b2982876fec2166673be447643881262c84090e", 524288, "AmigaOS 3.2 [47.096] (A1200)", 'M', 0}, 94 | {"7bc0e75622d7254e11ea708e5d149007866c93ab", 524288, "AmigaOS 3.2 [47.096] (A3000)", 'M', 0}, 95 | {"37a8aa0b83782d75ce0b4a80631ff3459e91dc63", 524288, "AmigaOS 3.2 [47.096] (A4000)", 'M', 0}, 96 | {"ede1748eb2cbb1e86ac5bf7dc9b97246a4a54358", 524288, "AmigaOS 3.2 [47.096] (A4000T)", 'M', 0}, 97 | {"8f64ada68a7f128ba782e8dc9fa583344171590a", 524288, "AmigaOS 3.2.1 [47.102] (A500/A600/A1000/A2000/CDTV)", 'M', 0}, 98 | {"0984fc0df07dc0585db0923d580629f70fca420d", 524288, "AmigaOS 3.2.1 [47.102] (A1200)", 'M', 0}, 99 | {"eb93508f0bb0cde81d88bf22d05045565d66ef74", 524288, "AmigaOS 3.2.1 [47.102] (A3000)", 'M', 0}, 100 | {"7db3c3226acc0bfe548c788cf1bc7c4c8774d66f", 524288, "AmigaOS 3.2.1 [47.102] (A4000)", 'M', 0}, 101 | {"a75fcd349680cedeab06e496c6338394e81788d7", 524288, "AmigaOS 3.2.1 [47.102] (A4000T)", 'M', 0}, 102 | {"7d5ebe686b69d59a863cc77a36b2cd60359a9ed2", 524288, "AmigaOS 3.2.2 [47.111] (A500/A600/A1000/A2000/CDTV)", 'M', 0}, 103 | {"d9622547d84741b52c5472607f9aca75565cbba3", 524288, "AmigaOS 3.2.2 [47.111] (A1200)", 'M', 0}, 104 | {"443d98369aca3ba51ab2d4789d14fa9a26379c0b", 524288, "AmigaOS 3.2.2 [47.111] (A3000)", 'M', 0}, 105 | {"a3207bd5b5a3ca629010f3159ac793040fa813ef", 524288, "AmigaOS 3.2.2 [47.111] (A4000)", 'M', 0}, 106 | {"8e3fff2675cc1b97b4f072b63fd4de7093f7c627", 524288, "AmigaOS 3.2.2 [47.111] (A4000T)", 'M', 0}, 107 | {"a9d51491d4b1356673621b61f789aed979bd01be", 524288, "AmigaOS 3.2.3 [47.115] (A500/A600/A1000/A2000/CDTV)", 'M', 0}, 108 | {"3f48ef0eca607855d7872796ba886d7889451fad", 524288, "AmigaOS 3.2.3 [47.115] (A1200)", 'M', 0}, 109 | {"76222baa6d5654dbba4a769bb86c1f39322d1c1c", 524288, "AmigaOS 3.2.3 [47.115] (A3000)", 'M', 0}, 110 | {"81902f41cbf6fc6b7d18c691a4ada6245d174bde", 524288, "AmigaOS 3.2.3 [47.115] (A4000)", 'M', 0}, 111 | {"8eeb6c2b282e589bd1589ebba3a78a41722499ec", 524288, "AmigaOS 3.2.3 [47.115] (A4000T)", 'M', 0}, 112 | 113 | // Swapped Kickstart ROMs 114 | {"4e2ee86c5675312ec4319bc694bdcabc81897e46", 262144, "AmigaOS 0.7b [27.003b] (A1000)", 'M', 1}, 115 | {"19c02d1a53bc3a3559699f990f6ff6a238bc854d", 262144, "AmigaOS 1.0 (A1000)", 'M', 1}, 116 | {"8b47fd3feac0e138be71b49448c99d9713333728", 262144, "AmigaOS 1.1 [31.034] (NTSC, A1000)", 'M', 1}, 117 | {"3bf4e177195d50d6c350e403961cc9b1b8822cac", 262144, "AmigaOS 1.1 [31.034] (PAL, A1000)", 'M', 1}, 118 | {"a6fca3d9c4e67283dc12f2ddebb4bf08adef638d", 262144, "AmigaOS 1.2 [33.166] (A500/A1000/A2000)", 'M', 1}, 119 | {"feb4c7ddffd2864d2695628bce95454aaf5925c2", 262144, "AmigaOS 1.2 [33.180] (A500/A1000/A2000)", 'M', 1}, 120 | {"e84e6ec0d65eeae7cf3a1dd3947c6695497dd31d", 262144, "AmigaOS 1.3 [34.005] (A500/A1000/A2000/CDTV)", 'M', 1}, 121 | {"b7f61e452d668449e2e76682d427ec17a379557a", 524288, "AmigaOS 2.04 [37.175] (A500+)", 'M', 1}, 122 | {"d0a8a9ad7ae0aa6418f6de63450f0bc628c87801", 524288, "AmigaOS 2.05 [37.299] (A600)", 'M', 1}, 123 | {"199697d832caca8e4c15a6f432fd2d08d78e230f", 524288, "AmigaOS 2.05 [37.300] (A600HD)", 'M', 1}, 124 | {"f9b7d78169aca89759cd362ab108e65a784a4988", 524288, "AmigaOS 2.05 [37.350] (A600HD)", 'M', 1}, 125 | {"5a5719ad375741e8c23f9dd288ebe74abda18911", 524288, "AmigaOS 3.1 [40.063] (A500/A600/A2000)", 'M', 1}, 126 | {"99fea56af9b7745dee75a9036cd37dfd41d8e8a9", 524288, "AmigaOS 3.x AF7.0 [45.061] (A500/A600/A2000)", 'M', 1}, 127 | {"6c5c0d4d0917e4ae413ac1c1cc14395508aa158a", 524288, "AmigaOS 3.x AF7.1 [45.064] (A500/A600/A2000)", 'M', 1}, 128 | {"65f78c13db26f6b6d1ee3e9ecec1867f1658d163", 524288, "AmigaOS 3.x AF8.0 [45.066] (A500/A600/A2000)", 'M', 1}, 129 | {"10a5eb4ccb3b88afeaa2ebbe860ae5e05611d893", 524288, "AmigaOS 3.1.4 [46.143] (A500/A600/A2000) (Old Copyright)", 'M', 1}, 130 | {"6f55f7afe5ef3f7d2045db2399758477d9bccdbf", 524288, "AmigaOS 3.1.4 [46.143] (A2000) (Old Copyright)", 'M', 1}, 131 | {"c50a0e32b4d59770b617c9817038bdfd1947eb46", 524288, "AmigaOS 3.1.4 [46.143] (A500/A600/A2000) (New Copyright)", 'M', 1}, 132 | {"dfae20c0a043d548d57299e64bc1d8bbfc8b011b", 524288, "AmigaOS 3.2 [47.096] (A500/A600/A1000/A2000/CDTV)", 'M', 1}, 133 | {"6019741ce39b994405ccfc073267b4deb21e94d1", 524288, "AmigaOS 3.2.1 [47.102] (A500/A600/A1000/A2000/CDTV)", 'M', 1}, 134 | {"7dc0de0699d01cc0a80562c296daa462a367da3b", 524288, "AmigaOS 3.2.2 [47.111] (A500/A600/A1000/A2000/CDTV)", 'M', 1}, 135 | {"5f53c7566fed3c6c20cc797161b751059f8a7ba0", 524288, "AmigaOS 3.2.3 [47.115] (A500/A600/A1000/A2000/CDTV)", 'M', 1}, 136 | 137 | // Split/swapped Kickstart ROMs for burning 138 | {"2be27a7b8c47c2a47bd3c8298d00b3b71bba9629", 262144, "AmigaOS 1.3 [34.005] (A3000) Hi", 'A', 1}, 139 | {"d562a41ca084b4a9133128be636652b6b2199673", 262144, "AmigaOS 1.3 [34.005] (A3000) Lo", 'B', 1}, 140 | {"64d17c73dc1bf0aab035575fa4d9eaae3cb90839", 262144, "AmigaOS 1.4 [36.016] (A3000) Hi", 'A', 1}, 141 | {"a4353efe86bb029143ebc176a765299c93d3bd94", 262144, "AmigaOS 1.4 [36.016] (A3000) Lo", 'B', 1}, 142 | {"2be0a39977e35ac4b07e23d98a8ae6d66018daaa", 262144, "AmigaOS 2.02 [36.207] (A3000) Hi", 'A', 1}, 143 | {"1ad296045fb024e21ce7c67ab8d8ae47d33fc361", 262144, "AmigaOS 2.02 [36.207] (A3000) Lo", 'B', 1}, 144 | {"a7e9d4f574d34d75f1812bc5e9301e23040a10e5", 262144, "AmigaOS 2.04 [37.175] (A3000) Hi", 'A', 1}, 145 | {"d6bee4a6f90361e1c87c7bda0d6fa7d371b8b18a", 262144, "AmigaOS 2.04 [37.175] (A3000) Lo", 'B', 1}, 146 | {"ca749555bd7d53c22f182bf605698fdebe8cceb2", 262144, "AmigaOS 3.0 [39.106] (A1200) Hi", 'A', 1}, 147 | {"bc269462de6265ebd4c2d6bb8db2140e267dbea7", 262144, "AmigaOS 3.0 [39.106] (A1200) Lo", 'B', 1}, 148 | {"2097527d060b2b1a70c0e2b4273b5ad3b5278603", 262144, "AmigaOS 3.0 [39.106] (A4000) Hi", 'A', 1}, 149 | {"995db56375b7a5d1edc5037b8c110a7c67bb20ec", 262144, "AmigaOS 3.0 [39.106] (A4000) Lo", 'B', 1}, 150 | {"e2e663ca1bb5b44a27d3c97ec06d1bbacbc2fccd", 262144, "AmigaOS 3.1 [40.055] (A3000) Hi", 'A', 1}, 151 | {"03f57d9e0a97660749141d247a7464da3ff6eba4", 262144, "AmigaOS 3.1 [40.055] (A3000) Lo", 'B', 1}, 152 | {"4f27f07aa08f043802cc9910b97f2392ff3d81d5", 262144, "AmigaOS 3.1 [40.060] (CD32) Hi", 'A', 1}, 153 | {"2f010d95f38556a1a61cc828c29d69b8450a2891", 262144, "AmigaOS 3.1 [40.060] (CD32) Hi", 'B', 1}, 154 | {"cd6409ceb748566fbd89ed31f8d1c01e474b4d97", 262144, "AmigaOS 3.1 [40.068] (A1200) Hi", 'A', 1}, 155 | {"dcbaa8aa562d69842a05bdcc04abd9aa32da4a05", 262144, "AmigaOS 3.1 [40.068] (A1200) Lo", 'B', 1}, 156 | {"668a396cda15178d0fcd99c7b9bdcdc870f64221", 262144, "AmigaOS 3.1 [40.068] (A3000) Hi", 'A', 1}, 157 | {"a84f5ef6cfb73a45f9e49582850ff9ed619f5ed2", 262144, "AmigaOS 3.1 [40.068] (A3000) Lo", 'B', 1}, 158 | {"4b58a68209a43d68c802963eb0f4eaa8cb872496", 262144, "AmigaOS 3.1 [40.068] (A4000) Hi", 'A', 1}, 159 | {"2552398aae971a8d4721c78bb1685fa9f2c4c42e", 262144, "AmigaOS 3.1 [40.068] (A4000) Lo", 'B', 1}, 160 | {"959ed70d723ba1454f40039548ee901ab8dfae85", 262144, "AmigaOS 3.1 [40.070] (A4000T) Hi", 'A', 1}, 161 | {"adcf8d61250eedf193a4269900b35e878e55b4ac", 262144, "AmigaOS 3.1 [40.070] (A4000T) Lo", 'B', 1}, 162 | {"a69531064c413aeee4513151f8f234c0f9d8eac8", 262144, "AmigaOS 3.2b [43.001b] (Walker) Hi", 'A', 1}, 163 | {"683f256e0f6ef6a8f73f1c63713ac2aaa0e716a5", 262144, "AmigaOS 3.2b [43.001b] (Walker) Lo", 'B', 1}, 164 | {"d2c2e4e72975892e800c74b55a79190cd8af5b21", 262144, "AmigaOS 3.x AF3.0 [45.057] (A4000) Hi", 'A', 1}, 165 | {"10bc268167d9191ae6871bea2f729fe64ca063c4", 262144, "AmigaOS 3.x AF3.0 [45.057] (A4000) Lo", 'B', 1}, 166 | {"77ed865ee4ae74965a3a9184f9b657933546ba1d", 262144, "AmigaOS 3.x AF6.8 [45.061] (A4000) Hi", 'A', 1}, 167 | {"e70e36a213975fbe49a917aa7651e913e108618a", 262144, "AmigaOS 3.x AF6.8 [45.061] (A4000) Lo", 'B', 1}, 168 | {"0c146318a9441c3c1c9e1c683c81c4be3ae3cf4b", 262144, "AmigaOS 3.x AF7.0 [45.061] (A1200) Hi", 'A', 1}, 169 | {"f6b567b89d8b6a4c318c7a542de30b96d66d174d", 262144, "AmigaOS 3.x AF7.0 [45.061] (A1200) Lo", 'B', 1}, 170 | {"6eed8859b54e61ffbb28ef355fbc54483aa47919", 262144, "AmigaOS 3.x AF7.0 [45.061] (A3000) Hi", 'A', 1}, 171 | {"80f9f5e7013831d9bb250ca9082694077be4cb09", 262144, "AmigaOS 3.x AF7.0 [45.061] (A3000) Lo", 'B', 1}, 172 | {"27aa3afc0b01183819bb52b8ec74bfbcec9cd15b", 262144, "AmigaOS 3.x AF7.0 [45.061] (A4000T) Hi", 'A', 1}, 173 | {"f111d0c5f0be80018549a2526c4294e49c59d683", 262144, "AmigaOS 3.x AF7.0 [45.061] (A4000T) Lo", 'B', 1}, 174 | {"011c26bbffaf764cdcc686a152e38cef76c6ad1b", 262144, "AmigaOS 3.x AF7.1 [45.064] (A1200) Hi", 'A', 1}, 175 | {"73e3df252520785d6b18df055eb91f36e36b09f8", 262144, "AmigaOS 3.x AF7.1 [45.064] (A1200) Lo", 'B', 1}, 176 | {"622b5dd4b582d3b8eab22ff74c1741cccb28cf56", 262144, "AmigaOS 3.x AF7.1 [45.064] (A3000) Hi", 'A', 1}, 177 | {"7c7f2b3efef8231c498d2ed342c652fd54ef6f14", 262144, "AmigaOS 3.x AF7.1 [45.064] (A3000) Lo", 'B', 1}, 178 | {"f6ebefa5ee7012845f6b9c8940ab8980eedcab34", 262144, "AmigaOS 3.x AF7.1 [45.064] (A4000) Hi", 'A', 1}, 179 | {"18cb0a9d156b32e0d5197a82fbc6532cffd9bd92", 262144, "AmigaOS 3.x AF7.1 [45.064] (A4000) Lo", 'B', 1}, 180 | {"a6546c92f1c8487515519d393891468572dad2e4", 262144, "AmigaOS 3.x AF7.1 [45.064] (A4000T) Hi", 'A', 1}, 181 | {"3f5359b5e3b8e052a6fe9d56ece8ca4494310087", 262144, "AmigaOS 3.x AF7.1 [45.064] (A4000T) Lo", 'B', 1}, 182 | {"28f6ba44f4747def792cf525ec0660fde9c36533", 262144, "AmigaOS 3.x AF8.0 [45.066] (A1200) Hi", 'A', 1}, 183 | {"6f87d784fec320b59a9965fca5e25560d6004688", 262144, "AmigaOS 3.x AF8.0 [45.066] (A1200) Lo", 'B', 1}, 184 | {"747e8dfa105f8e06e071b71a6d289c1b731a5454", 262144, "AmigaOS 3.x AF8.0 [45.066] (A3000) Hi", 'A', 1}, 185 | {"5ebf30b0221de0aba473504a64f2891d5fa61a11", 262144, "AmigaOS 3.x AF8.0 [45.066] (A3000) Lo", 'B', 1}, 186 | {"08321a3ac619d4f8c085f3cc1fa16db44575d5fc", 262144, "AmigaOS 3.x AF8.0 [45.066] (A4000) Hi", 'A', 1}, 187 | {"e5450996be2ee0420cbadee8bc92f340b28a501d", 262144, "AmigaOS 3.x AF8.0 [45.066] (A4000) Lo", 'B', 1}, 188 | {"3327bd7731813ab9e0b9b478aa7871c4b2a479da", 262144, "AmigaOS 3.x AF8.0 [45.066] (A4000T) Hi", 'A', 1}, 189 | {"73b4dc7f158dc39c4d61faa2534bebcaa199a1cf", 262144, "AmigaOS 3.x AF8.0 [45.066] (A4000T) Lo", 'B', 1}, 190 | {"4daed46da9e75560db1dc81585dff8120ea01c25", 262144, "AmigaOS 3.1.4 [46.143] (A1200) (Old Copyright) Hi", 'A', 1}, 191 | {"5728fa8a538fabd39ed733a4b33d2da4a04277f8", 262144, "AmigaOS 3.1.4 [46.143] (A1200) (Old Copyright) Lo", 'B', 1}, 192 | {"0addca53892d65dbcd81524a361eb3498a4a02d7", 262144, "AmigaOS 3.1.4 [46.143] (A3000) (Old Copyright) Hi", 'A', 1}, 193 | {"24b7857087494f26d298776e6cd2fddfde33770e", 262144, "AmigaOS 3.1.4 [46.143] (A3000) (Old Copyright) Lo", 'B', 1}, 194 | {"646fc9c44a4619f9be64b2790911740fa9a5f281", 262144, "AmigaOS 3.1.4 [46.143] (A4000) (Old Copyright) Hi", 'A', 1}, 195 | {"7efc6e89d3141d4f974ae7423435b53c29b7a5eb", 262144, "AmigaOS 3.1.4 [46.143] (A4000) (Old Copyright) Lo", 'B', 1}, 196 | {"f4d7dc6c6f913c1465c9a939dca9a641154c2636", 262144, "AmigaOS 3.1.4 [46.143] (A4000T) (Old Copyright) Hi", 'A', 1}, 197 | {"0a2e1ceef5758a44a4c066d793279e82e99af1fe", 262144, "AmigaOS 3.1.4 [46.143] (A4000T) (Old Copyright) Lo", 'B', 1}, 198 | {"eada0c5da801c41e4f7a685f5e26ac42695be8f0", 262144, "AmigaOS 3.1.4 [46.143] (A1200) (New Copyright) Hi", 'A', 1}, 199 | {"5f7f0473b6c15cbfd3950e72f2f9d4bc2fda5426", 262144, "AmigaOS 3.1.4 [46.143] (A1200) (New Copyright) Lo", 'B', 1}, 200 | {"d5d81008234ab71b835942c9070b60d083988493", 262144, "AmigaOS 3.1.4 [46.143] (A3000) (New Copyright) Hi", 'A', 1}, 201 | {"45218ed6052be144e1287b57c6c980e351e57dc2", 262144, "AmigaOS 3.1.4 [46.143] (A3000) (New Copyright) Lo", 'B', 1}, 202 | {"4a42d093f1965ddc97a7df810743c594a2e8b280", 262144, "AmigaOS 3.1.4 [46.143] (A4000) (New Copyright) Hi", 'A', 1}, 203 | {"28708dd807903eb92cbbbf47a34c0d225fb5ce81", 262144, "AmigaOS 3.1.4 [46.143] (A4000) (New Copyright) Lo", 'B', 1}, 204 | {"af4760379f4bc677e25a07cbb5f941fae54e38f7", 262144, "AmigaOS 3.1.4 [46.143] (A4000T) (New Copyright) Hi", 'A', 1}, 205 | {"6be4cfd65c9d2a6869b57b97c3bd141fcdce77bd", 262144, "AmigaOS 3.1.4 [46.143] (A4000T) (New Copyright) Lo", 'B', 1}, 206 | {"6180165db63db311591fa581dc531aba7340207d", 262144, "AmigaOS 3.2 [47.096] (A1200) Hi", 'A', 1}, 207 | {"5ff86b1a41429b365b085e7709572b5957f956a4", 262144, "AmigaOS 3.2 [47.096] (A1200) Lo", 'B', 1}, 208 | {"89a3d438c33d195baca0742d5504315b5888ade2", 262144, "AmigaOS 3.2 [47.096] (A3000) Hi", 'A', 1}, 209 | {"d08a1f405283748ade32fe67bd3fb9d79f88567d", 262144, "AmigaOS 3.2 [47.096] (A3000) Lo", 'B', 1}, 210 | {"5fe056ae79adc23e7e65de7f3e5aad71df72be59", 262144, "AmigaOS 3.2 [47.096] (A4000) Hi", 'A', 1}, 211 | {"8c27ae8bdc9db1dbe49e300e11fea0df0082eac6", 262144, "AmigaOS 3.2 [47.096] (A4000) Lo", 'B', 1}, 212 | {"49a3d36203c0185d6c0a50bcda047e83c1192bbd", 262144, "AmigaOS 3.2 [47.096] (A4000T) Hi", 'A', 1}, 213 | {"9ba0bac48fd9b92e4d3d821a12d7d0bf51c885fe", 262144, "AmigaOS 3.2 [47.096] (A4000T) Lo", 'B', 1}, 214 | {"a7fb54d23ee26bf59c8c4ba5574f6482d6c93607", 262144, "AmigaOS 3.2.1 [47.102] (A1200) Hi", 'A', 1}, 215 | {"0fc5b3277c9fc107459cf15328fe642c4aaa53d0", 262144, "AmigaOS 3.2.1 [47.102] (A1200) Lo", 'B', 1}, 216 | {"c9668ecfcba0cdc29729aed2f656d6d53f8e7bfc", 262144, "AmigaOS 3.2.1 [47.102] (A3000) Hi", 'A', 1}, 217 | {"53c97fbec6052360b43e9be99456806366b7ae85", 262144, "AmigaOS 3.2.1 [47.102] (A3000) Lo", 'B', 1}, 218 | {"48b97a8c9854d8a0254e4bcd4a96cc35def4e3a7", 262144, "AmigaOS 3.2.1 [47.102] (A4000) Hi", 'A', 1}, 219 | {"8546b9baadbdc391e2fb52d9b0f2cbb85f780a4c", 262144, "AmigaOS 3.2.1 [47.102] (A4000) Lo", 'B', 1}, 220 | {"c59c779bd94e5e8c9620e78339ba1b9f3b64251c", 262144, "AmigaOS 3.2.1 [47.102] (A4000T) Hi", 'A', 1}, 221 | {"998bea2daa4051127ffe0c4701b42abc7c4c1cfc", 262144, "AmigaOS 3.2.1 [47.102] (A4000T) Lo", 'B', 1}, 222 | {"d08959195f260c1eddd8104ce80eee6c666fa352", 262144, "AmigaOS 3.2.2 [47.111] (A1200) Hi", 'A', 1}, 223 | {"f215641da4b59dc4dca448c41a6f8a2d06411c38", 262144, "AmigaOS 3.2.2 [47.111] (A1200) Lo", 'B', 1}, 224 | {"8b32d734eb9977bc0d2b87226fd3795c163ed587", 262144, "AmigaOS 3.2.2 [47.111] (A3000) Hi", 'A', 1}, 225 | {"fbe314870981a0c911a4bec5c9c581e43a649347", 262144, "AmigaOS 3.2.2 [47.111] (A3000) Lo", 'B', 1}, 226 | {"d9e1badba7b50ae0a8d21383da96dbba6892cfe1", 262144, "AmigaOS 3.2.2 [47.111] (A4000) Hi", 'A', 1}, 227 | {"92107dd42ba3b90a41b28a0e58c51d9d2fb04a61", 262144, "AmigaOS 3.2.2 [47.111] (A4000) Lo", 'B', 1}, 228 | {"8618ede52eee4a2e7e7a7d27120d9d13d87cf1ac", 262144, "AmigaOS 3.2.2 [47.111] (A4000T) Hi", 'A', 1}, 229 | {"a1261042bc11bc2c0bb44525de7d57c2b4ba39b0", 262144, "AmigaOS 3.2.2 [47.111] (A4000T) Lo", 'B', 1}, 230 | {"ef74df7d0103d4a1f06248455b30b85db24ffd5a", 262144, "AmigaOS 3.2.3 [47.115] (A1200) Hi", 'A', 1}, 231 | {"85a36c01392dac8c8ac5ba73854f2fca61495668", 262144, "AmigaOS 3.2.3 [47.115] (A1200) Lo", 'B', 1}, 232 | {"d7a31bef244715075228465f6d3d126fd7629224", 262144, "AmigaOS 3.2.3 [47.115] (A3000) Hi", 'A', 1}, 233 | {"9bc15df22a2b6c2132dae4e19a73ec7caf507248", 262144, "AmigaOS 3.2.3 [47.115] (A3000) Lo", 'B', 1}, 234 | {"770bb69935f18389ab24b7472afbd955e6625c7a", 262144, "AmigaOS 3.2.3 [47.115] (A4000) Hi", 'A', 1}, 235 | {"a12a13aebc18f09c71ad5c9f6ee5e3d76550eef8", 262144, "AmigaOS 3.2.3 [47.115] (A4000) Lo", 'B', 1}, 236 | {"be72613b9a5b8ff1c9acad3553993d0b061ec8e3", 262144, "AmigaOS 3.2.3 [47.115] (A4000T) Hi", 'A', 1}, 237 | {"350157c6668c58dacd73b3bce37570c8af17a2e3", 262144, "AmigaOS 3.2.3 [47.115] (A4000T) Lo", 'B', 1}, 238 | 239 | // Extended Amiga ROMs 240 | {"ed7e461d1fff3cda321631ae42b80e3cd4fa5ebb", 262144, "Ext. ROM 1.3 (A570)", 'E', 0}, 241 | {"7ba40ffa17e500ed9fed041f3424bd81d9c907be", 262144, "Ext. ROM 1.3 (CDTV)", 'E', 0}, 242 | {"14271106fe97e655345ba8cccac52be999c37990", 262144, "Ext. ROM 2.3 (CDTV)", 'E', 0}, 243 | {"08ad97eea88ad621bd4dfdbf3d8259fb187ab1dc", 262144, "Ext. ROM 2.35 (A570) (Unofficial)", 'E', 0}, 244 | {"e3809198a6ffe7cbcd5a3d87c640c791f9581f05", 262144, "Ext. ROM 2.35 (A690) (Unofficial)", 'E', 0}, 245 | {"426ef4b3a229154ed320b2f84022261e7b4219a8", 262144, "Ext. ROM 2.35 (CDTV) (Unofficial)", 'E', 0}, 246 | {"5bef3d628ce59cc02a66e6e4ae0da48f60e78f7f", 524288, "Ext. ROM [40.060] (CD32)", 'E', 0}, 247 | {"cfc16f8e930badcb9c3e7f889a57d645571fa86a", 262144, "Ext. ROM 3.2 [47.096] (CDTV)", 'E', 0}, 248 | 249 | // Other unswapped ROMs 250 | {"03ca81c7a7b259cf64bc9582863eca0f6529f435", 262144, "Amiga CRT 3.1 FMV (CD32)", 'O', 0}, 251 | {"c87f9fada4ee4e69f3cca0c36193be822b9f5fe6", 8192, "Amiga SCSI Boot ROM (A1000)", 'O', 0}, 252 | {"e50f01baf28998928554786372a82c333c91276e", 16384, "Amiga SCSI Boot ROM (A590)", 'O', 0}, 253 | {"3ce66919f6fd67974923a12d91b730f1ffb4a7ba", 32768, "Amiga SCSI Boot ROM (A4091)", 'O', 0}, 254 | {"ba10d16166b2e2d6177c979c99edf8462b21651e", 524288, "Logica Dialoga 2.0", 'O', 0}, 255 | {"9e292178d20a6773f90664b00b137d8f4e52233d", 131072, "Ralph Schmidt Cyberstorm PPC [44.071]", 'O', 0}, 256 | {"cafafb916f16b9f3ec9b49aa4b40eb4eeceb5b5b", 131072, "Village Tronic Picasso IV 7.4", 'O', 0} 257 | }; 258 | 259 | #endif 260 | -------------------------------------------------------------------------------- /AmigaROMMajorMinorVersions.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 Christopher Gelatt 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #ifndef AMIGAROMMAJORMINORVERSIONS_H 26 | #define AMIGAROMMAJORMINORVERSIONS_H 27 | 28 | #include 29 | 30 | typedef struct { 31 | const uint16_t major_version; 32 | const uint16_t minor_version; // 0xffff is a "don't care", as the major_version has a 1:1 match with a version 33 | const char version[128]; 34 | } AmigaROMMajorMinorVersions; 35 | 36 | static const AmigaROMMajorMinorVersions AMIGA_ROM_MAJOR_MINOR_VERSIONS[] = { 37 | {23, 0xffff, "AmigaOS \"Velvet\" prerelease"}, 38 | {24, 0xffff, "AmigaOS 0.4 (A1000)"}, 39 | {26, 0xffff, "AmigaOS 0.6 (A1000)"}, 40 | {27, 0xffff, "AmigaOS 0.7 (A1000)"}, 41 | {29, 0xffff, "AmigaOS 0.9 (A1000)"}, 42 | {30, 0xffff, "AmigaOS 1.0 (A1000)"}, 43 | {31, 0xffff, "AmigaOS 1.1 (A1000)"}, 44 | {32, 0xffff, "AmigaOS 1.1 (A1000)"}, 45 | {33, 0xffff, "AmigaOS 1.2 (A500/A1000/A2000)"}, 46 | {34, 0xffff, "AmigaOS 1.3 (A500/A1000/A2000/A3000/CDTV)"}, 47 | {35, 0xffff, "AmigaOS 1.3 (A2024)"}, 48 | {36, 0xffff, "AmigaOS 2.0 (A500+ ECS/A3000)"}, 49 | {37, 175, "AmigaOS 2.04 (A500+/A2000/A3000)"}, 50 | {37, 210, "AmigaOS 2.05 (A600)"}, 51 | {37, 299, "AmigaOS 2.05 (A600 ECS)"}, 52 | {37, 300, "AmigaOS 2.05 (A600HD)"}, 53 | {37, 350, "AmigaOS 2.05 (A600HD)"}, 54 | {38, 0xffff, "AmigaOS 2.1"}, 55 | {39, 0xffff, "AmigaOS 3.0 (A1200/A4000)"}, 56 | {40, 0xffff, "AmigaOS 3.1 (A500/A600/A1200/A2000/A3000/A4000/A4000T/CD32)"}, 57 | {41, 0xffff, "AmigaOS 3.1 (Japan localization)"}, 58 | {43, 0xffff, "AmigaOS 3.1 (patched) / AmigaOS 3.2 (Walker prototype)"}, 59 | {44, 0xffff, "Haage & Partner AmigaOS 3.5"}, 60 | {45, 0xffff, "Cloanto AmigaOS 3.x / Haage & Partner AmigaOS 3.9"}, 61 | {46, 0xffff, "Hyperion Entertainment AmigaOS 3.1.4"}, 62 | {47, 0xffff, "Hyperion Entertainment AmigaOS 3.2"}, 63 | {50, 0xffff, "Hyperion Entertainment AmigaOS 4 Beta / MorphOS 1"}, 64 | {51, 0xffff, "Hyperion Entertainment AmigaOS 4 Beta / MorphOS 2+"}, 65 | {52, 0xffff, "Hyperion Entertainment AmigaOS 4.0"}, 66 | {53, 0xffff, "Hyperion Entertainment AmigaOS 4.1"} 67 | }; 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /AmigaROMUtil.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 Christopher Gelatt 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include "AmigaROMUtil.h" 26 | #include "AmigaROMHashes.h" 27 | #include "AmigaROMMajorMinorVersions.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #if defined(__APPLE__) && defined(__MACH__) 38 | 39 | #include 40 | 41 | #define htobe16(x) OSSwapHostToBigInt16(x) 42 | #define be16toh(x) OSSwapBigToHostInt16(x) 43 | 44 | #define htobe32(x) OSSwapHostToBigInt32(x) 45 | #define be32toh(x) OSSwapBigToHostInt32(x) 46 | 47 | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) 48 | 49 | #include 50 | 51 | #elif defined(__OpenBSD__) 52 | 53 | #include 54 | 55 | #define be16toh(x) betoh16(x) 56 | #define be32toh(x) betoh32(x) 57 | 58 | #elif defined(__linux__) || defined(__CYGWIN__) 59 | 60 | #include 61 | 62 | #elif defined(_WIN32) || defined(_WIN64) 63 | 64 | #if !defined(_M_ARM) && !defined(_M_ARM64) 65 | 66 | #if defined(_MSC_VER) 67 | 68 | #include 69 | 70 | #define htobe16(x) _byteswap_ushort(x) 71 | #define be16toh(x) _byteswap_ushort(x) 72 | 73 | #define htobe32(x) _byteswap_ulong(x) 74 | #define be32toh(x) _byteswap_ulong(x) 75 | 76 | #elif defined(__GNUC__) || defined(__clang__) // Compiler (Windows, Intel) 77 | 78 | #define htobe16(x) __builtin_bswap16(x) 79 | #define be16toh(x) __builtin_bswap16(x) 80 | 81 | #define htobe32(x) __builtin_bswap32(x) 82 | #define be32toh(x) __builtin_bswap32(x) 83 | 84 | #endif // Compiler (Windows, Intel) 85 | 86 | #else // Architecture (Windows, ARM) 87 | 88 | #define htobe16(x) (x) 89 | #define be16toh(x) (x) 90 | 91 | #define htobe32(x) (x) 92 | #define be32toh(x) (x) 93 | 94 | #endif // Architecture (Windows) 95 | 96 | #endif // Platform 97 | 98 | #define AMIGA_256_ROM_HEADER 0x11114EF9 99 | #define AMIGA_256_ROM_HEADER_BYTESWAP 0x1111F94E 100 | #define AMIGA_512_ROM_HEADER 0x11144EF9 101 | #define AMIGA_512_ROM_HEADER_BYTESWAP 0x1411F94E 102 | #define AMIGA_EXT_ROM_HEADER 0x11144EF9 103 | #define AMIGA_EXT_ROM_HEADER_BYTESWAP 0x1411F94E 104 | #define AMIGA_512_REKICK_ROM_HEADER 0x11164EF9 //TODO: Properly detect size/handle these 105 | #define AMIGA_512_REKICK_ROM_HEADER_BYTESWAP 0x1611F94E //TODO: Properly detect size/handle these 106 | 107 | extern int sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databytes); 108 | 109 | // Create and return a new and initialized struct. 110 | // Pointers are NOT allocated, but are NULL instead. 111 | ParsedAmigaROMData GetInitializedAmigaROM(void) 112 | { 113 | ParsedAmigaROMData amiga_rom; 114 | 115 | amiga_rom.is_initialized = true; 116 | amiga_rom.parsed_rom = false; 117 | amiga_rom.rom_data = NULL; 118 | amiga_rom.rom_size = 0; 119 | amiga_rom.validated_size = false; 120 | amiga_rom.has_reset_vector = false; 121 | amiga_rom.is_encrypted = false; 122 | amiga_rom.can_decrypt = false; 123 | amiga_rom.successfully_decrypted = false; 124 | amiga_rom.is_byte_swapped = false; 125 | amiga_rom.has_valid_checksum = false; 126 | amiga_rom.header = 0; 127 | amiga_rom.type = 'U'; 128 | amiga_rom.version = NULL; 129 | amiga_rom.major_version = 0; 130 | amiga_rom.minor_version = 0xffff; 131 | amiga_rom.major_minor_version = NULL; 132 | amiga_rom.is_kickety_split = false; 133 | amiga_rom.valid_footer = false; 134 | 135 | return amiga_rom; 136 | } 137 | 138 | // Free all pointers which are expected to potentially be 139 | // allocated in a struct and sets the pointers to NULL, 140 | // and sets the rest of the struct to default values. 141 | void DestroyInitializedAmigaROM(ParsedAmigaROMData *amiga_rom) 142 | { 143 | amiga_rom->is_initialized = false; 144 | amiga_rom->parsed_rom = false; 145 | 146 | if(amiga_rom->rom_data) 147 | { 148 | free(amiga_rom->rom_data); 149 | amiga_rom->rom_data = NULL; 150 | } 151 | 152 | amiga_rom->rom_size = 0; 153 | amiga_rom->validated_size = false; 154 | amiga_rom->has_reset_vector = false; 155 | amiga_rom->is_encrypted = false; 156 | amiga_rom->can_decrypt = false; 157 | amiga_rom->successfully_decrypted = false; 158 | amiga_rom->is_byte_swapped = false; 159 | amiga_rom->has_valid_checksum = false; 160 | amiga_rom->header = 0; 161 | amiga_rom->type = 'U'; 162 | amiga_rom->version = NULL; 163 | amiga_rom->major_version = 0; 164 | amiga_rom->minor_version = 0xffff; 165 | amiga_rom->major_minor_version = NULL; 166 | amiga_rom->is_kickety_split = false; 167 | amiga_rom->valid_footer = false; 168 | } 169 | 170 | // Returns a parsed ROM data struct, with the ROM data and size included. 171 | // If anything files, parsed_rom will be false. If encrypted, the ROM 172 | // will be decrypted. 173 | ParsedAmigaROMData ReadAmigaROM(const char *rom_file_path, const char *keyfile_path) 174 | { 175 | FILE *fp; 176 | 177 | ParsedAmigaROMData amiga_rom = GetInitializedAmigaROM(); 178 | int seek_status; 179 | 180 | if(!rom_file_path) 181 | { 182 | return amiga_rom; 183 | } 184 | 185 | fp = fopen(rom_file_path, "rb"); 186 | if(!fp) 187 | { 188 | return amiga_rom; 189 | } 190 | 191 | seek_status = fseek(fp, 0, SEEK_END); 192 | 193 | if(seek_status < 0) 194 | { 195 | fclose(fp); 196 | return amiga_rom; 197 | } 198 | else 199 | { 200 | amiga_rom.rom_size = (size_t)ftell(fp); 201 | fseek(fp, 0, SEEK_SET); 202 | } 203 | 204 | amiga_rom.rom_data = (uint8_t*)malloc(amiga_rom.rom_size); 205 | 206 | if(!amiga_rom.rom_data) 207 | { 208 | fclose(fp); 209 | return amiga_rom; 210 | } 211 | 212 | fread(amiga_rom.rom_data, 1, amiga_rom.rom_size, fp); 213 | 214 | fclose(fp); 215 | 216 | ParseAmigaROMData(&amiga_rom, keyfile_path); 217 | 218 | if(amiga_rom.parsed_rom) 219 | { 220 | if(amiga_rom.is_encrypted && amiga_rom.can_decrypt) 221 | { 222 | if(CryptAmigaROM(&amiga_rom, false, keyfile_path)) 223 | { 224 | amiga_rom.successfully_decrypted = true; 225 | } 226 | } 227 | } 228 | 229 | return amiga_rom; 230 | } 231 | 232 | // Detect whether a ROM is an Amiga kickstart ROM based on size, header, reset vector, 233 | // magic, and footer. 234 | bool IsAmigaROM(const ParsedAmigaROMData *amiga_rom) 235 | { 236 | if(DetectAmigaKickstartROMTypeFromHeader(amiga_rom) == 0) 237 | { 238 | return false; 239 | } 240 | 241 | if(!ValidateAmigaROMResetVector(amiga_rom)) 242 | { 243 | return false; 244 | } 245 | 246 | if(!ValidateAmigaKickstartROMFooter(amiga_rom)) 247 | { 248 | return false; 249 | } 250 | 251 | return true; 252 | } 253 | 254 | // Puts ROM info data into output_string 255 | void PrintAmigaROMInfo(const ParsedAmigaROMData *amiga_rom, char *output_string, const size_t string_length) 256 | { 257 | char *successfully_parsed = NULL; 258 | char *rom_size_validated = NULL; 259 | char *has_reset_vector = NULL; 260 | char *rom_is_encrypted = NULL; 261 | char *can_decrypt_rom = NULL; 262 | char *successfully_decrypted_rom = NULL; 263 | char *rom_is_byte_swapped = NULL; 264 | char *rom_has_valid_checksum = NULL; 265 | char *rom_header_info = NULL; 266 | char *rom_type = NULL; 267 | char *rom_version = NULL; 268 | char *embedded_rom_major_version = NULL; 269 | char *embedded_rom_minor_version = NULL; 270 | char *detected_embedded_rom_version = NULL; 271 | char *is_kickety_split = NULL; 272 | char *has_valid_footer = NULL; 273 | 274 | if(!amiga_rom || !output_string) 275 | { 276 | return; 277 | } 278 | 279 | successfully_parsed = (char *)malloc(64); 280 | if(!successfully_parsed) 281 | { 282 | return; 283 | } 284 | snprintf(successfully_parsed, 64, "Successfully parsed:\t\t%d", amiga_rom->parsed_rom); 285 | 286 | rom_size_validated = (char *)malloc(64); 287 | if(!rom_size_validated) 288 | { 289 | free(successfully_parsed); 290 | successfully_parsed = NULL; 291 | return; 292 | } 293 | snprintf(rom_size_validated, 64, "ROM size validated:\t\t%d", amiga_rom->validated_size); 294 | 295 | has_reset_vector = (char *)malloc(64); 296 | if(!has_reset_vector) 297 | { 298 | free(successfully_parsed); 299 | successfully_parsed = NULL; 300 | free(rom_size_validated); 301 | rom_size_validated = NULL; 302 | return; 303 | } 304 | snprintf(has_reset_vector, 64, "Has reset vector:\t\t%d", amiga_rom->has_reset_vector); 305 | 306 | rom_is_encrypted = (char *)malloc(64); 307 | if(!rom_is_encrypted) 308 | { 309 | free(successfully_parsed); 310 | successfully_parsed = NULL; 311 | free(rom_size_validated); 312 | rom_size_validated = NULL; 313 | free(has_reset_vector); 314 | has_reset_vector = NULL; 315 | return; 316 | } 317 | snprintf(rom_is_encrypted, 64, "ROM is encrypted:\t\t%d", amiga_rom->is_encrypted); 318 | 319 | can_decrypt_rom = (char *)malloc(64); 320 | if(!can_decrypt_rom) 321 | { 322 | free(successfully_parsed); 323 | successfully_parsed = NULL; 324 | free(rom_size_validated); 325 | rom_size_validated = NULL; 326 | free(has_reset_vector); 327 | has_reset_vector = NULL; 328 | free(rom_is_encrypted); 329 | rom_is_encrypted = NULL; 330 | return; 331 | } 332 | snprintf(can_decrypt_rom, 64, "Can decrypt ROM:\t\t%d", amiga_rom->can_decrypt); 333 | 334 | successfully_decrypted_rom = (char *)malloc(64); 335 | if(!successfully_decrypted_rom) 336 | { 337 | free(successfully_parsed); 338 | successfully_parsed = NULL; 339 | free(rom_size_validated); 340 | rom_size_validated = NULL; 341 | free(has_reset_vector); 342 | has_reset_vector = NULL; 343 | free(rom_is_encrypted); 344 | rom_is_encrypted = NULL; 345 | free(can_decrypt_rom); 346 | can_decrypt_rom = NULL; 347 | return; 348 | } 349 | snprintf(successfully_decrypted_rom, 64, "Successfully decrypted ROM:\t%d", amiga_rom->successfully_decrypted); 350 | 351 | rom_is_byte_swapped = (char *)malloc(64); 352 | if(!rom_is_byte_swapped) 353 | { 354 | free(successfully_parsed); 355 | successfully_parsed = NULL; 356 | free(rom_size_validated); 357 | rom_size_validated = NULL; 358 | free(has_reset_vector); 359 | has_reset_vector = NULL; 360 | free(rom_is_encrypted); 361 | rom_is_encrypted = NULL; 362 | free(can_decrypt_rom); 363 | can_decrypt_rom = NULL; 364 | free(successfully_decrypted_rom); 365 | successfully_decrypted_rom = NULL; 366 | return; 367 | } 368 | snprintf(rom_is_byte_swapped, 64, "ROM is byte swapped:\t\t%d", amiga_rom->is_byte_swapped); 369 | 370 | rom_has_valid_checksum = (char *)malloc(64); 371 | if(!rom_has_valid_checksum) 372 | { 373 | free(successfully_parsed); 374 | successfully_parsed = NULL; 375 | free(rom_size_validated); 376 | rom_size_validated = NULL; 377 | free(has_reset_vector); 378 | has_reset_vector = NULL; 379 | free(rom_is_encrypted); 380 | rom_is_encrypted = NULL; 381 | free(can_decrypt_rom); 382 | can_decrypt_rom = NULL; 383 | free(successfully_decrypted_rom); 384 | successfully_decrypted_rom = NULL; 385 | free(rom_is_byte_swapped); 386 | rom_is_byte_swapped = NULL; 387 | return; 388 | } 389 | snprintf(rom_has_valid_checksum, 64, "ROM has a valid checksum:\t%d", amiga_rom->has_valid_checksum); 390 | 391 | rom_header_info = (char *)malloc(64); 392 | if(!rom_header_info) 393 | { 394 | free(successfully_parsed); 395 | successfully_parsed = NULL; 396 | free(rom_size_validated); 397 | rom_size_validated = NULL; 398 | free(has_reset_vector); 399 | has_reset_vector = NULL; 400 | free(rom_is_encrypted); 401 | rom_is_encrypted = NULL; 402 | free(can_decrypt_rom); 403 | can_decrypt_rom = NULL; 404 | free(successfully_decrypted_rom); 405 | successfully_decrypted_rom = NULL; 406 | free(rom_is_byte_swapped); 407 | rom_is_byte_swapped = NULL; 408 | free(rom_has_valid_checksum); 409 | rom_has_valid_checksum = NULL; 410 | return; 411 | } 412 | 413 | switch(amiga_rom->header) 414 | { 415 | case 0: 416 | snprintf(rom_header_info, 64, "ROM type indicated by header:\tNot an Amiga ROM"); 417 | break; 418 | case 1: 419 | snprintf(rom_header_info, 64, "ROM type indicated by header:\t256KB Kickstart ROM"); 420 | break; 421 | case 2: 422 | snprintf(rom_header_info, 64, "ROM type indicated by header:\t512KB Kickstart ROM"); 423 | break; 424 | case 3: 425 | snprintf(rom_header_info, 64, "ROM type indicated by header:\tExtended ROM"); 426 | break; 427 | case 4: 428 | snprintf(rom_header_info, 64, "ROM type indicated by header:\t\"ReKick\" ROM"); 429 | break; 430 | case 5: 431 | snprintf(rom_header_info, 64, "ROM type indicated by header:\tAmbiguous"); 432 | break; 433 | default: 434 | snprintf(rom_header_info, 64, "ROM type indicated by header:\tUnknown"); 435 | break; 436 | } 437 | 438 | rom_type = (char *)malloc(64); 439 | if(!rom_type) 440 | { 441 | free(successfully_parsed); 442 | successfully_parsed = NULL; 443 | free(rom_size_validated); 444 | rom_size_validated = NULL; 445 | free(has_reset_vector); 446 | has_reset_vector = NULL; 447 | free(rom_is_encrypted); 448 | rom_is_encrypted = NULL; 449 | free(can_decrypt_rom); 450 | can_decrypt_rom = NULL; 451 | free(successfully_decrypted_rom); 452 | successfully_decrypted_rom = NULL; 453 | free(rom_is_byte_swapped); 454 | rom_is_byte_swapped = NULL; 455 | free(rom_has_valid_checksum); 456 | rom_has_valid_checksum = NULL; 457 | free(rom_header_info); 458 | rom_header_info = NULL; 459 | return; 460 | } 461 | 462 | switch(amiga_rom->type) 463 | { 464 | case 'A': 465 | snprintf(rom_type, 64, "ROM type:\t\t\tKickstart Hi ROM"); 466 | break; 467 | case 'B': 468 | snprintf(rom_type, 64, "ROM type:\t\t\tKickstart Lo ROM"); 469 | break; 470 | case 'E': 471 | snprintf(rom_type, 64, "ROM type:\t\t\tExtended Amiga ROM"); 472 | break; 473 | case 'M': 474 | snprintf(rom_type, 64, "ROM type:\t\t\tMerged Kickstart ROM"); 475 | break; 476 | case 'O': 477 | snprintf(rom_type, 64, "ROM type:\t\t\tNon-Kickstart Amiga ROM"); 478 | break; 479 | case 'U': 480 | default: 481 | snprintf(rom_type, 64, "ROM type:\t\t\tUnknown ROM"); 482 | break; 483 | } 484 | 485 | rom_version = (char *)malloc(143); 486 | if(!rom_version) 487 | { 488 | free(successfully_parsed); 489 | successfully_parsed = NULL; 490 | free(rom_size_validated); 491 | rom_size_validated = NULL; 492 | free(has_reset_vector); 493 | has_reset_vector = NULL; 494 | free(rom_is_encrypted); 495 | rom_is_encrypted = NULL; 496 | free(can_decrypt_rom); 497 | can_decrypt_rom = NULL; 498 | free(successfully_decrypted_rom); 499 | successfully_decrypted_rom = NULL; 500 | free(rom_is_byte_swapped); 501 | rom_is_byte_swapped = NULL; 502 | free(rom_has_valid_checksum); 503 | rom_has_valid_checksum = NULL; 504 | free(rom_header_info); 505 | rom_header_info = NULL; 506 | free(rom_type); 507 | rom_type = NULL; 508 | return; 509 | } 510 | snprintf(rom_version, 143, "ROM version:\t\t\t%s", amiga_rom->version); 511 | 512 | embedded_rom_major_version = (char *)malloc(64); 513 | if(!embedded_rom_major_version) 514 | { 515 | free(successfully_parsed); 516 | successfully_parsed = NULL; 517 | free(rom_size_validated); 518 | rom_size_validated = NULL; 519 | free(has_reset_vector); 520 | has_reset_vector = NULL; 521 | free(rom_is_encrypted); 522 | rom_is_encrypted = NULL; 523 | free(can_decrypt_rom); 524 | can_decrypt_rom = NULL; 525 | free(successfully_decrypted_rom); 526 | successfully_decrypted_rom = NULL; 527 | free(rom_is_byte_swapped); 528 | rom_is_byte_swapped = NULL; 529 | free(rom_has_valid_checksum); 530 | rom_has_valid_checksum = NULL; 531 | free(rom_header_info); 532 | rom_header_info = NULL; 533 | free(rom_type); 534 | rom_type = NULL; 535 | free(rom_version); 536 | rom_version = NULL; 537 | return; 538 | } 539 | 540 | if(amiga_rom->major_version != 0xffff) 541 | { 542 | snprintf(embedded_rom_major_version, 64, "ROM major version number:\t%u", amiga_rom->major_version); 543 | } 544 | else 545 | { 546 | snprintf(embedded_rom_major_version, 64, "ROM major version number:\tUnknown"); 547 | } 548 | 549 | embedded_rom_minor_version = (char *)malloc(64); 550 | if(!embedded_rom_minor_version) 551 | { 552 | free(successfully_parsed); 553 | successfully_parsed = NULL; 554 | free(rom_size_validated); 555 | rom_size_validated = NULL; 556 | free(has_reset_vector); 557 | has_reset_vector = NULL; 558 | free(rom_is_encrypted); 559 | rom_is_encrypted = NULL; 560 | free(can_decrypt_rom); 561 | can_decrypt_rom = NULL; 562 | free(successfully_decrypted_rom); 563 | successfully_decrypted_rom = NULL; 564 | free(rom_is_byte_swapped); 565 | rom_is_byte_swapped = NULL; 566 | free(rom_has_valid_checksum); 567 | rom_has_valid_checksum = NULL; 568 | free(rom_header_info); 569 | rom_header_info = NULL; 570 | free(rom_type); 571 | rom_type = NULL; 572 | free(rom_version); 573 | rom_version = NULL; 574 | free(embedded_rom_major_version); 575 | embedded_rom_major_version = NULL; 576 | return; 577 | } 578 | 579 | if(amiga_rom->minor_version != 0xffff) 580 | { 581 | snprintf(embedded_rom_minor_version, 64, "ROM minor version number:\t%u", amiga_rom->minor_version); 582 | } 583 | else 584 | { 585 | snprintf(embedded_rom_minor_version, 64, "ROM minor version number:\tN/A"); 586 | } 587 | 588 | detected_embedded_rom_version = (char *)malloc(157); 589 | if(!detected_embedded_rom_version) 590 | { 591 | free(successfully_parsed); 592 | successfully_parsed = NULL; 593 | free(rom_size_validated); 594 | rom_size_validated = NULL; 595 | free(has_reset_vector); 596 | has_reset_vector = NULL; 597 | free(rom_is_encrypted); 598 | rom_is_encrypted = NULL; 599 | free(can_decrypt_rom); 600 | can_decrypt_rom = NULL; 601 | free(successfully_decrypted_rom); 602 | successfully_decrypted_rom = NULL; 603 | free(rom_is_byte_swapped); 604 | rom_is_byte_swapped = NULL; 605 | free(rom_has_valid_checksum); 606 | rom_has_valid_checksum = NULL; 607 | free(rom_header_info); 608 | rom_header_info = NULL; 609 | free(rom_type); 610 | rom_type = NULL; 611 | free(rom_version); 612 | rom_version = NULL; 613 | free(embedded_rom_major_version); 614 | embedded_rom_major_version = NULL; 615 | free(embedded_rom_minor_version); 616 | embedded_rom_minor_version = NULL; 617 | return; 618 | } 619 | 620 | snprintf(detected_embedded_rom_version, 157, "ROM detected version number:\t%s", amiga_rom->major_minor_version); 621 | 622 | is_kickety_split = (char *)malloc(64); 623 | if(!is_kickety_split) 624 | { 625 | free(successfully_parsed); 626 | successfully_parsed = NULL; 627 | free(rom_size_validated); 628 | rom_size_validated = NULL; 629 | free(has_reset_vector); 630 | has_reset_vector = NULL; 631 | free(rom_is_encrypted); 632 | rom_is_encrypted = NULL; 633 | free(can_decrypt_rom); 634 | can_decrypt_rom = NULL; 635 | free(successfully_decrypted_rom); 636 | successfully_decrypted_rom = NULL; 637 | free(rom_is_byte_swapped); 638 | rom_is_byte_swapped = NULL; 639 | free(rom_has_valid_checksum); 640 | rom_has_valid_checksum = NULL; 641 | free(rom_header_info); 642 | rom_header_info = NULL; 643 | free(rom_type); 644 | rom_type = NULL; 645 | free(rom_version); 646 | rom_version = NULL; 647 | free(embedded_rom_major_version); 648 | embedded_rom_major_version = NULL; 649 | free(embedded_rom_minor_version); 650 | embedded_rom_minor_version = NULL; 651 | free(detected_embedded_rom_version); 652 | detected_embedded_rom_version = NULL; 653 | return; 654 | } 655 | 656 | snprintf(is_kickety_split, 64, "ROM kickety split status:\t%d", amiga_rom->is_kickety_split); 657 | 658 | has_valid_footer = (char *)malloc(64); 659 | if(!has_valid_footer) 660 | { 661 | free(successfully_parsed); 662 | successfully_parsed = NULL; 663 | free(rom_size_validated); 664 | rom_size_validated = NULL; 665 | free(has_reset_vector); 666 | has_reset_vector = NULL; 667 | free(rom_is_encrypted); 668 | rom_is_encrypted = NULL; 669 | free(can_decrypt_rom); 670 | can_decrypt_rom = NULL; 671 | free(successfully_decrypted_rom); 672 | successfully_decrypted_rom = NULL; 673 | free(rom_is_byte_swapped); 674 | rom_is_byte_swapped = NULL; 675 | free(rom_has_valid_checksum); 676 | rom_has_valid_checksum = NULL; 677 | free(rom_header_info); 678 | rom_header_info = NULL; 679 | free(rom_type); 680 | rom_type = NULL; 681 | free(rom_version); 682 | rom_version = NULL; 683 | free(embedded_rom_major_version); 684 | embedded_rom_major_version = NULL; 685 | free(embedded_rom_minor_version); 686 | embedded_rom_minor_version = NULL; 687 | free(detected_embedded_rom_version); 688 | detected_embedded_rom_version = NULL; 689 | free(is_kickety_split); 690 | is_kickety_split = NULL; 691 | return; 692 | } 693 | 694 | snprintf(has_valid_footer, 64, "ROM has valid footer:\t\t%d", amiga_rom->valid_footer); 695 | 696 | snprintf(output_string, string_length, "ROM Info:\n\n"); 697 | snprintf(output_string, string_length, "%s%s\n", output_string, successfully_parsed); 698 | snprintf(output_string, string_length, "%s%s\n", output_string, rom_size_validated); 699 | snprintf(output_string, string_length, "%s%s\n", output_string, has_reset_vector); 700 | snprintf(output_string, string_length, "%s%s\n", output_string, rom_is_encrypted); 701 | snprintf(output_string, string_length, "%s%s\n", output_string, can_decrypt_rom); 702 | snprintf(output_string, string_length, "%s%s\n", output_string, successfully_decrypted_rom); 703 | snprintf(output_string, string_length, "%s%s\n", output_string, rom_is_byte_swapped); 704 | snprintf(output_string, string_length, "%s%s\n", output_string, rom_has_valid_checksum); 705 | snprintf(output_string, string_length, "%s%s\n", output_string, rom_header_info); 706 | snprintf(output_string, string_length, "%s%s\n", output_string, rom_type); 707 | snprintf(output_string, string_length, "%s%s\n", output_string, rom_version); 708 | snprintf(output_string, string_length, "%s%s\n", output_string, embedded_rom_major_version); 709 | snprintf(output_string, string_length, "%s%s\n", output_string, embedded_rom_minor_version); 710 | snprintf(output_string, string_length, "%s%s\n", output_string, detected_embedded_rom_version); 711 | snprintf(output_string, string_length, "%s%s\n", output_string, is_kickety_split); 712 | snprintf(output_string, string_length, "%s%s\n", output_string, has_valid_footer); 713 | 714 | free(successfully_parsed); 715 | successfully_parsed = NULL; 716 | free(rom_size_validated); 717 | rom_size_validated = NULL; 718 | free(has_reset_vector); 719 | has_reset_vector = NULL; 720 | free(rom_is_encrypted); 721 | rom_is_encrypted = NULL; 722 | free(can_decrypt_rom); 723 | can_decrypt_rom = NULL; 724 | free(successfully_decrypted_rom); 725 | successfully_decrypted_rom = NULL; 726 | free(rom_is_byte_swapped); 727 | rom_is_byte_swapped = NULL; 728 | free(rom_has_valid_checksum); 729 | rom_has_valid_checksum = NULL; 730 | free(rom_header_info); 731 | rom_header_info = NULL; 732 | free(rom_type); 733 | rom_type = NULL; 734 | free(rom_version); 735 | rom_version = NULL; 736 | free(embedded_rom_major_version); 737 | embedded_rom_major_version = NULL; 738 | free(embedded_rom_minor_version); 739 | embedded_rom_minor_version = NULL; 740 | free(detected_embedded_rom_version); 741 | detected_embedded_rom_version = NULL; 742 | free(is_kickety_split); 743 | is_kickety_split = NULL; 744 | free(has_valid_footer); 745 | has_valid_footer = NULL; 746 | } 747 | 748 | // Parses and validates the data in the Amiga ROM updates the struct 749 | // passed in with that data. 750 | void ParseAmigaROMData(ParsedAmigaROMData *amiga_rom, const char* keyfile_path) 751 | { 752 | int rom_encryption_result = 0; 753 | 754 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 755 | { 756 | return; 757 | } 758 | 759 | amiga_rom->parsed_rom = false; 760 | amiga_rom->validated_size = false; 761 | amiga_rom->has_reset_vector = false; 762 | amiga_rom->is_byte_swapped = false; 763 | amiga_rom->has_valid_checksum = false; 764 | amiga_rom->header = 0; 765 | amiga_rom->type = 'U'; 766 | amiga_rom->version = NULL; 767 | amiga_rom->major_version = 0; 768 | amiga_rom->minor_version = 0xffff; 769 | amiga_rom->major_minor_version = NULL; 770 | amiga_rom->is_kickety_split = false; 771 | amiga_rom->valid_footer = false; 772 | 773 | if(!ValidateAmigaROMSize(amiga_rom)) 774 | { 775 | return; 776 | } 777 | 778 | rom_encryption_result = DetectAmigaROMEncryption(amiga_rom); 779 | 780 | if(rom_encryption_result == -1) 781 | { 782 | return; 783 | } 784 | else 785 | { 786 | amiga_rom->is_encrypted = rom_encryption_result; 787 | } 788 | 789 | if(amiga_rom->is_encrypted) 790 | { 791 | if(!CryptAmigaROM(amiga_rom, false, keyfile_path)) 792 | { 793 | amiga_rom->is_encrypted = true; 794 | amiga_rom->can_decrypt = false; 795 | amiga_rom->successfully_decrypted = false; 796 | } 797 | else 798 | { 799 | amiga_rom->is_encrypted = false; 800 | amiga_rom->can_decrypt = false; 801 | amiga_rom->successfully_decrypted = true; 802 | } 803 | } 804 | 805 | if(!amiga_rom->is_encrypted) 806 | { 807 | amiga_rom->parsed_rom = true; 808 | amiga_rom->validated_size = ValidateEmbeddedAmigaROMSize(amiga_rom); 809 | amiga_rom->has_reset_vector = ValidateAmigaROMResetVector(amiga_rom); 810 | amiga_rom->is_byte_swapped = (DetectAmigaROMByteSwap(amiga_rom) == 1); 811 | amiga_rom->has_valid_checksum = ValidateAmigaROMChecksum(amiga_rom); 812 | amiga_rom->header = DetectAmigaKickstartROMTypeFromHeader(amiga_rom); 813 | amiga_rom->type = DetectAmigaROMType(amiga_rom); 814 | amiga_rom->version = DetectAmigaROMVersion(amiga_rom); 815 | amiga_rom->major_version = DetectAmigaMajorROMVersion(amiga_rom); 816 | amiga_rom->minor_version = DetectAmigaMinorROMVersion(amiga_rom); 817 | amiga_rom->major_minor_version = DetectAmigaMajorMinorROMVersion(amiga_rom); 818 | amiga_rom->is_kickety_split = DetectKicketySplitAmigaROM(amiga_rom); 819 | amiga_rom->valid_footer = ValidateAmigaKickstartROMFooter(amiga_rom); 820 | } 821 | } 822 | 823 | // Return whether an Amiga ROM is a valid size, accounting for 824 | // encryption, if it's there. 825 | bool ValidateAmigaROMSize(const ParsedAmigaROMData *amiga_rom) 826 | { 827 | size_t actual_rom_size = DetectUnencryptedAmigaROMSize(amiga_rom); 828 | 829 | return ((actual_rom_size > 10) && ((actual_rom_size & actual_rom_size - 1) == 0)); 830 | } 831 | 832 | // Validate that there is a reset vector (0x0x4E70) at 0x000000D0. 833 | // Returns true if there is, or false if there isn't. 834 | bool ValidateAmigaROMResetVector(const ParsedAmigaROMData *amiga_rom) 835 | { 836 | const uint16_t *rom_data_16; 837 | 838 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 839 | { 840 | return false; 841 | } 842 | 843 | rom_data_16 = (const uint16_t*)(amiga_rom->rom_data); 844 | 845 | return (be16toh(rom_data_16[104]) == 0x4E70); 846 | } 847 | 848 | // Detects the version of the ROM by SHA1 hash 849 | // Returns NULL for failure, else a string indicating the ROM version 850 | const char* DetectAmigaROMVersion(const ParsedAmigaROMData *amiga_rom) 851 | { 852 | uint8_t *digest; 853 | char *hexdigest; 854 | 855 | size_t i; 856 | size_t rom_quantity = sizeof(AMIGA_ROM_INFO) / sizeof(AmigaROMInfo); 857 | 858 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 859 | { 860 | return NULL; 861 | } 862 | 863 | digest = (uint8_t*)malloc(20); 864 | if(!digest) 865 | { 866 | return NULL; 867 | } 868 | 869 | hexdigest = (char*)malloc(41); 870 | if(!hexdigest) 871 | { 872 | free(digest); 873 | digest = NULL; 874 | return NULL; 875 | } 876 | 877 | if (sha1digest(digest, hexdigest, amiga_rom->rom_data, amiga_rom->rom_size)) 878 | { 879 | free(digest); 880 | digest = NULL; 881 | free(hexdigest); 882 | hexdigest = NULL; 883 | return NULL; 884 | } 885 | 886 | for (i = 0; i < rom_quantity; i++) 887 | { 888 | if (strncmp(hexdigest, AMIGA_ROM_INFO[i].sha1hash, 40) == 0) 889 | { 890 | free(digest); 891 | digest = NULL; 892 | free(hexdigest); 893 | hexdigest = NULL; 894 | return AMIGA_ROM_INFO[i].version; 895 | } 896 | } 897 | 898 | free(digest); 899 | digest = NULL; 900 | free(hexdigest); 901 | hexdigest = NULL; 902 | return NULL; 903 | } 904 | 905 | // Detects the major version in the Amiga ROM header 906 | // Returns 0 if the ROM is not detects as an Amiga ROM 907 | uint16_t DetectAmigaMajorROMVersion(const ParsedAmigaROMData *amiga_rom) 908 | { 909 | const uint16_t *rom_data_16; 910 | 911 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size < 16) 912 | { 913 | return 0xffff; 914 | } 915 | 916 | if(!IsAmigaROM(amiga_rom)) 917 | { 918 | return 0xffff; 919 | } 920 | 921 | rom_data_16 = (const uint16_t*)(amiga_rom->rom_data); 922 | 923 | return be16toh(rom_data_16[6]); 924 | } 925 | 926 | // Detects the minor version in the Amiga ROM header 927 | // Returns 0 if the ROM is not detects as an Amiga ROM 928 | uint16_t DetectAmigaMinorROMVersion(const ParsedAmigaROMData *amiga_rom) 929 | { 930 | const uint16_t *rom_data_16; 931 | 932 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size < 16) 933 | { 934 | return 0xffff; 935 | } 936 | 937 | if(!IsAmigaROM(amiga_rom)) 938 | { 939 | return 0xffff; 940 | } 941 | 942 | rom_data_16 = (const uint16_t*)(amiga_rom->rom_data); 943 | 944 | return be16toh(rom_data_16[7]); 945 | } 946 | 947 | // Returns a version string based on the major and minor versions in the Amiga ROM header 948 | // Returns NULL if the ROM is not detects as an Amiga ROM or the version is unknown 949 | const char* DetectAmigaMajorMinorROMVersion(const ParsedAmigaROMData *amiga_rom) 950 | { 951 | size_t i, number_of_versions; 952 | 953 | number_of_versions = sizeof(AMIGA_ROM_MAJOR_MINOR_VERSIONS) / sizeof(AmigaROMMajorMinorVersions); 954 | 955 | for(i = 0; i < number_of_versions; i++) 956 | { 957 | if(AMIGA_ROM_MAJOR_MINOR_VERSIONS[i].major_version == DetectAmigaMajorROMVersion(amiga_rom)) 958 | { 959 | if((AMIGA_ROM_MAJOR_MINOR_VERSIONS[i].minor_version == 0xffff) || (AMIGA_ROM_MAJOR_MINOR_VERSIONS[i].minor_version == DetectAmigaMinorROMVersion(amiga_rom))) 960 | { 961 | return AMIGA_ROM_MAJOR_MINOR_VERSIONS[i].version; 962 | } 963 | } 964 | } 965 | 966 | return NULL; 967 | } 968 | 969 | // Returns a character indicating the type of ROM detected based on the SHA1 hash 970 | // Valid return values are: 971 | // A - Kickstart Hi/U34 ROM 972 | // B - Kickstart Lo/U35 ROM 973 | // E - Extended Amiga ROM 974 | // M - Kickstart merged ROM 975 | // O - Other (non-Kickstart) ROM 976 | // U - Unknown ROM 977 | char DetectAmigaROMType(const ParsedAmigaROMData *amiga_rom) 978 | { 979 | uint8_t *digest; 980 | char *hexdigest; 981 | 982 | size_t i; 983 | size_t rom_quantity = sizeof(AMIGA_ROM_INFO) / sizeof(AmigaROMInfo); 984 | 985 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 986 | { 987 | return 'U'; 988 | } 989 | 990 | digest = (uint8_t*)malloc(20); 991 | if(!digest) 992 | { 993 | return 'U'; 994 | } 995 | 996 | hexdigest = (char*)malloc(41); 997 | if(!hexdigest) 998 | { 999 | free(digest); 1000 | digest = NULL; 1001 | return 'U'; 1002 | } 1003 | 1004 | if (sha1digest(digest, hexdigest, amiga_rom->rom_data, amiga_rom->rom_size)) 1005 | { 1006 | free(digest); 1007 | digest = NULL; 1008 | free(hexdigest); 1009 | hexdigest = NULL; 1010 | return 'U'; 1011 | } 1012 | 1013 | for (i = 0; i < rom_quantity; i++) 1014 | { 1015 | if (strncmp(hexdigest, AMIGA_ROM_INFO[i].sha1hash, 40) == 0) 1016 | { 1017 | free(digest); 1018 | digest = NULL; 1019 | free(hexdigest); 1020 | hexdigest = NULL; 1021 | return AMIGA_ROM_INFO[i].type; 1022 | } 1023 | } 1024 | 1025 | free(digest); 1026 | digest = NULL; 1027 | free(hexdigest); 1028 | hexdigest = NULL; 1029 | return 'U'; 1030 | } 1031 | 1032 | // Detect whether a ROM is a "Kickety-Split ROM" 1033 | // Returns true if it is, and false if it isn't. 1034 | bool DetectKicketySplitAmigaROM(const ParsedAmigaROMData *amiga_rom) 1035 | { 1036 | const uint32_t *rom_data_32; 1037 | 1038 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1039 | { 1040 | return false; 1041 | } 1042 | 1043 | rom_data_32 = (const uint32_t*)(amiga_rom->rom_data); 1044 | 1045 | if(amiga_rom->rom_size != 524288) 1046 | { 1047 | return false; 1048 | } 1049 | 1050 | return ((be32toh(rom_data_32[131072]) == AMIGA_256_ROM_HEADER) || (be32toh(rom_data_32[131072]) == AMIGA_256_ROM_HEADER_BYTESWAP)); 1051 | } 1052 | 1053 | // Detect which type of kickstart ROM a purported Kickstart ROM claims to be 1054 | // based on its header and size. If this data is not consistent, or is unknown, 1055 | // the method returns 0x00. Otherwise, the lower seven bits will determine what 1056 | // type of Kickstart ROM this is, according to the following table: 1057 | // 1058 | // 0x00: Not an Amiga ROM 1059 | // 0x01: 256KB ROM 1060 | // 0x02: 512KB ROM 1061 | // 0x03: Extended ROM 1062 | // 0x04: "ReKick" ROM 1063 | // 0x05: Ambiguous (may or may not be an Amiga ROM of another type) 1064 | // 1065 | // If the ROM is byte-swapped, then the topmost bit will be a 1, with the rest 1066 | // of the seven bits as the table above. 1067 | uint8_t DetectAmigaKickstartROMTypeFromHeader(const ParsedAmigaROMData *amiga_rom) 1068 | { 1069 | const uint32_t *rom_data_32; 1070 | 1071 | uint32_t amiga_256_header = AMIGA_256_ROM_HEADER; 1072 | uint32_t amiga_256_header_byteswap = AMIGA_256_ROM_HEADER_BYTESWAP; 1073 | uint32_t amiga_512_header = AMIGA_512_ROM_HEADER; 1074 | uint32_t amiga_512_header_byteswap = AMIGA_512_ROM_HEADER_BYTESWAP; 1075 | uint32_t amiga_ext_header = AMIGA_EXT_ROM_HEADER; 1076 | uint32_t amiga_ext_header_byteswap = AMIGA_EXT_ROM_HEADER_BYTESWAP; 1077 | uint32_t amiga_rekick_rom_header = AMIGA_512_REKICK_ROM_HEADER; 1078 | uint32_t amiga_rekick_rom_header_byteswap = AMIGA_512_REKICK_ROM_HEADER_BYTESWAP; 1079 | uint32_t rom_header; 1080 | 1081 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1082 | { 1083 | return 0x00; 1084 | } 1085 | 1086 | rom_data_32 = (const uint32_t*)(amiga_rom->rom_data); 1087 | 1088 | if(amiga_rom->rom_size < 4) 1089 | { 1090 | return 0x00; 1091 | } 1092 | 1093 | rom_header = be32toh(rom_data_32[0]); 1094 | 1095 | if(amiga_rom->rom_size == 524288) 1096 | { 1097 | if((rom_header == amiga_512_header) || (rom_header == amiga_512_header_byteswap)) 1098 | { 1099 | if(rom_header == amiga_512_header) 1100 | { 1101 | return 0x02; 1102 | } 1103 | else 1104 | { 1105 | return 0x02 | 0x80; 1106 | } 1107 | } 1108 | } 1109 | else if(amiga_rom->rom_size == 262144) 1110 | { 1111 | if((rom_header == amiga_256_header) || (rom_header == amiga_256_header_byteswap)) 1112 | { 1113 | if(rom_header == amiga_256_header) 1114 | { 1115 | return 0x01; 1116 | } 1117 | else 1118 | { 1119 | return 0x01 | 0x80; 1120 | } 1121 | } 1122 | else if((rom_header == amiga_ext_header) || (rom_header == amiga_ext_header_byteswap)) 1123 | { 1124 | if(rom_header == amiga_ext_header) 1125 | { 1126 | return 0x03; 1127 | } 1128 | else 1129 | { 1130 | return 0x03 | 0x80; 1131 | } 1132 | } 1133 | else if((rom_header == amiga_rekick_rom_header) || (rom_header == amiga_rekick_rom_header_byteswap)) 1134 | { 1135 | if(rom_header == amiga_rekick_rom_header) 1136 | { 1137 | return 0x04; 1138 | } 1139 | else 1140 | { 1141 | return 0x04 | 0x80; 1142 | } 1143 | } 1144 | } 1145 | else if(amiga_rom->rom_size == 8192 || amiga_rom->rom_size == 16384 || amiga_rom->rom_size == 32768 || amiga_rom->rom_size == 131072) 1146 | { 1147 | return 0x05; 1148 | } 1149 | 1150 | return 0x00; 1151 | } 1152 | 1153 | // Returns an unsigned 32-bit integer with the checksum for the ROM. 1154 | // This checksum is used by Amigas to validate whether a ROM is undamaged, 1155 | // and is located 24 bytes from the end of the ROM. 1156 | // If calc_new_sum is true, then the function will return a checksum value which 1157 | // will be accepted for use by an Amiga system. 1158 | uint32_t CalculateAmigaROMChecksum(const ParsedAmigaROMData *amiga_rom, const bool calc_new_sum) 1159 | { 1160 | const uint32_t *rom_data_32; 1161 | 1162 | uint32_t sum = 0; 1163 | uint32_t temp = 0; 1164 | size_t i = 0; 1165 | 1166 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1167 | { 1168 | return 0xFFFFFFFF; 1169 | } 1170 | 1171 | rom_data_32 = (const uint32_t*)(amiga_rom->rom_data); 1172 | 1173 | if(amiga_rom->rom_size < 24) 1174 | { 1175 | return 0xFFFFFFFF; 1176 | } 1177 | 1178 | for(i = 0; i < amiga_rom->rom_size / 4; i++) 1179 | { 1180 | if(calc_new_sum) 1181 | { 1182 | if(i != (amiga_rom->rom_size - 24) / 4) 1183 | { 1184 | temp = be32toh(rom_data_32[i]); 1185 | } 1186 | else 1187 | { 1188 | temp = 0; 1189 | } 1190 | } 1191 | else 1192 | { 1193 | temp = be32toh(rom_data_32[i]); 1194 | } 1195 | 1196 | if(sum + temp < sum) 1197 | { 1198 | sum++; 1199 | } 1200 | 1201 | sum += temp; 1202 | } 1203 | 1204 | return ~sum; 1205 | } 1206 | 1207 | // Returns the checksum embedded in the ROM, or 0 if it fails. 1208 | // Technically a ROM could have a valid checksum of zero, but 1209 | // this is exceedingly unlikely. 1210 | uint32_t GetEmbeddedAmigaROMChecksum(const ParsedAmigaROMData *amiga_rom) 1211 | { 1212 | const uint32_t *rom_data_32 = (const uint32_t*)(amiga_rom->rom_data); 1213 | 1214 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1215 | { 1216 | return 0; 1217 | } 1218 | 1219 | if(amiga_rom->rom_size < 24) 1220 | { 1221 | return 0; 1222 | } 1223 | 1224 | return be32toh(rom_data_32[(amiga_rom->rom_size - 24) / 4]); 1225 | } 1226 | 1227 | // Returns a boolean indicating whether the calculated checksum in the ROM 1228 | // matches the calculated checksum for the ROM. 1229 | bool ValidateAmigaROMChecksum(const ParsedAmigaROMData *amiga_rom) 1230 | { 1231 | uint32_t calculated_sum; 1232 | 1233 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1234 | { 1235 | return false; 1236 | } 1237 | 1238 | calculated_sum = CalculateAmigaROMChecksum(amiga_rom, false); 1239 | 1240 | return (calculated_sum == 0); 1241 | } 1242 | 1243 | // Calculates and embeds a correct checksum in the ROM. 1244 | // Returns true if it succeeds, or false if it fails. 1245 | bool CorrectAmigaROMChecksum(ParsedAmigaROMData *amiga_rom) 1246 | { 1247 | uint32_t *rom_data_32; 1248 | uint8_t *temp_rom_data; 1249 | 1250 | uint32_t old_sum = 0; 1251 | uint32_t new_sum = 0; 1252 | 1253 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1254 | { 1255 | return false; 1256 | } 1257 | 1258 | temp_rom_data = (uint8_t*)malloc(amiga_rom->rom_size); 1259 | if(!temp_rom_data) 1260 | { 1261 | return false; 1262 | } 1263 | 1264 | memcpy(temp_rom_data, amiga_rom->rom_data, amiga_rom->rom_size); 1265 | 1266 | rom_data_32 = (uint32_t*)temp_rom_data; 1267 | old_sum = be32toh(amiga_rom->rom_data[(amiga_rom->rom_size - 24) / 4]); 1268 | new_sum = CalculateAmigaROMChecksum(amiga_rom, true); 1269 | 1270 | if(old_sum == new_sum) 1271 | { 1272 | free(temp_rom_data); 1273 | temp_rom_data = NULL; 1274 | return true; 1275 | } 1276 | 1277 | if(new_sum == 0) 1278 | { 1279 | free(temp_rom_data); 1280 | temp_rom_data = NULL; 1281 | return false; 1282 | } 1283 | 1284 | rom_data_32[(amiga_rom->rom_size - 24) / 4] = htobe32(new_sum); 1285 | 1286 | if(!ValidateAmigaROMChecksum(amiga_rom)) 1287 | { 1288 | free(temp_rom_data); 1289 | temp_rom_data = NULL; 1290 | return false; 1291 | } 1292 | 1293 | memcpy(amiga_rom->rom_data, temp_rom_data, amiga_rom->rom_size); 1294 | 1295 | amiga_rom->has_valid_checksum = true; 1296 | 1297 | free(temp_rom_data); 1298 | temp_rom_data = NULL; 1299 | return true; 1300 | } 1301 | 1302 | // Validates whether an Amiga kickstart ROM as a valid footer. 1303 | // Returns true if it does, or false if it doesn't. 1304 | bool ValidateAmigaKickstartROMFooter(const ParsedAmigaROMData *amiga_rom) 1305 | { 1306 | const uint16_t *rom_data_16; 1307 | 1308 | uint16_t footer_value = 0x19; 1309 | size_t i; 1310 | 1311 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1312 | { 1313 | return false; 1314 | } 1315 | 1316 | rom_data_16 = (const uint16_t*)(amiga_rom->rom_data); 1317 | 1318 | for(i = (amiga_rom->rom_size / 2) - 7; i < (amiga_rom->rom_size / 2); i++) 1319 | { 1320 | if(be16toh(rom_data_16[i]) != footer_value) 1321 | { 1322 | return false; 1323 | } 1324 | 1325 | footer_value++; 1326 | } 1327 | 1328 | return true; 1329 | } 1330 | 1331 | // Validate the ROM size matches the size embedded in the ROM. 1332 | // Returns true if it does, or false if it doesn't. 1333 | bool ValidateEmbeddedAmigaROMSize(const ParsedAmigaROMData *amiga_rom) 1334 | { 1335 | const uint32_t *rom_data_32; 1336 | 1337 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1338 | { 1339 | return false; 1340 | } 1341 | 1342 | rom_data_32 = (const uint32_t*)(amiga_rom->rom_data); 1343 | return (be32toh(rom_data_32[(amiga_rom->rom_size / 4) - 5]) == amiga_rom->rom_size); 1344 | } 1345 | 1346 | // Detects whether an Amiga ROM is encrypted. 1347 | // Returns 1 if it is, 0 if it isn't, or -1 if it has an invalid size. 1348 | int DetectAmigaROMEncryption(const ParsedAmigaROMData *amiga_rom) 1349 | { 1350 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1351 | { 1352 | return -1; 1353 | } 1354 | 1355 | if(amiga_rom->rom_size < 11) 1356 | { 1357 | return -1; 1358 | } 1359 | return (strncmp((char*)(amiga_rom->rom_data), "AMIROMTYPE1", 11) == 0); 1360 | } 1361 | 1362 | // Encrypts or decrypts Amiga ROMs according to whether crypt_operation is true or false. 1363 | // If true, it will encrypt the ROMs. If false, it will decrypt them. 1364 | // The function returns true if the method succeeds, and false if it fails. 1365 | // For safety, make sure that rom_contents has space for 11 more bytes than the original 1366 | // ROM had if an encrypt operation is performed. 1367 | bool CryptAmigaROM(ParsedAmigaROMData *amiga_rom, const bool crypt_operation, const char *keyfile_path) 1368 | { 1369 | FILE *fp; 1370 | uint8_t *keyfile_buffer; 1371 | uint8_t *result_buffer; 1372 | 1373 | int is_encrypted = 0; 1374 | size_t keyfile_size = 0; 1375 | size_t result_size = amiga_rom->rom_size; 1376 | int seek_status; 1377 | 1378 | if(!amiga_rom || !keyfile_path || !(amiga_rom->rom_data) || (amiga_rom->rom_size == 0 && crypt_operation) || (amiga_rom->rom_size < 11 && !crypt_operation)) 1379 | { 1380 | return false; 1381 | } 1382 | 1383 | is_encrypted = DetectAmigaROMEncryption(amiga_rom); 1384 | if(is_encrypted == -1) 1385 | { 1386 | return false; 1387 | } 1388 | 1389 | if(is_encrypted == crypt_operation) 1390 | { 1391 | return false; 1392 | } 1393 | 1394 | if(crypt_operation) 1395 | { 1396 | result_buffer = (uint8_t*)malloc((amiga_rom->rom_size + 11)); 1397 | } 1398 | else 1399 | { 1400 | result_buffer = (uint8_t*)malloc((amiga_rom->rom_size - 11)); 1401 | } 1402 | 1403 | if(!result_buffer) 1404 | { 1405 | return false; 1406 | } 1407 | 1408 | fp = fopen(keyfile_path, "rb"); 1409 | if(!fp) 1410 | { 1411 | free(result_buffer); 1412 | result_buffer = NULL; 1413 | return false; 1414 | } 1415 | 1416 | seek_status = fseek(fp, 0, SEEK_END); 1417 | 1418 | if(seek_status < 0) 1419 | { 1420 | free(result_buffer); 1421 | result_buffer = NULL; 1422 | return false; 1423 | } 1424 | else 1425 | { 1426 | keyfile_size = (size_t)ftell(fp); 1427 | fseek(fp, 0, SEEK_SET); 1428 | } 1429 | 1430 | keyfile_buffer = (uint8_t*)malloc(keyfile_size); 1431 | if(!keyfile_buffer) 1432 | { 1433 | free(result_buffer); 1434 | result_buffer = NULL; 1435 | return false; 1436 | } 1437 | 1438 | fread(keyfile_buffer, 1, keyfile_size, fp); 1439 | 1440 | fclose(fp); 1441 | 1442 | if(keyfile_size < 1) 1443 | { 1444 | free(keyfile_buffer); 1445 | keyfile_buffer = NULL; 1446 | free(result_buffer); 1447 | result_buffer = NULL; 1448 | return false; 1449 | } 1450 | 1451 | if(is_encrypted) 1452 | { 1453 | result_size = result_size - 11; 1454 | memcpy(result_buffer, &(amiga_rom->rom_data)[11], result_size); 1455 | } 1456 | else 1457 | { 1458 | memcpy(result_buffer, amiga_rom->rom_data, result_size); 1459 | } 1460 | 1461 | if(!DoAmigaROMCryptOperation(result_buffer, result_size, keyfile_buffer, keyfile_size)) 1462 | { 1463 | free(keyfile_buffer); 1464 | keyfile_buffer = NULL; 1465 | free(result_buffer); 1466 | result_buffer = NULL; 1467 | return false; 1468 | } 1469 | 1470 | if(is_encrypted) 1471 | { 1472 | amiga_rom->rom_data = realloc(amiga_rom->rom_data, result_size); 1473 | if(!amiga_rom->rom_data) 1474 | { 1475 | free(keyfile_buffer); 1476 | keyfile_buffer = NULL; 1477 | free(result_buffer); 1478 | result_buffer = NULL; 1479 | return false; 1480 | } 1481 | 1482 | memcpy(amiga_rom->rom_data, result_buffer, result_size); 1483 | amiga_rom->rom_size = result_size; 1484 | } 1485 | else 1486 | { 1487 | amiga_rom->rom_data = realloc(amiga_rom->rom_data, (result_size + 11)); 1488 | if(!amiga_rom->rom_data) 1489 | { 1490 | free(keyfile_buffer); 1491 | keyfile_buffer = NULL; 1492 | free(result_buffer); 1493 | result_buffer = NULL; 1494 | return false; 1495 | } 1496 | 1497 | snprintf((char*)(amiga_rom->rom_data), 12, "AMIROMTYPE1"); 1498 | memcpy(&(amiga_rom->rom_data)[11], result_buffer, result_size); 1499 | amiga_rom->rom_size = result_size + 11; 1500 | 1501 | ParseAmigaROMData(amiga_rom, NULL); 1502 | } 1503 | 1504 | free(keyfile_buffer); 1505 | keyfile_buffer = NULL; 1506 | free(result_buffer); 1507 | result_buffer = NULL; 1508 | 1509 | return true; 1510 | } 1511 | 1512 | // Run the actual crypt operation, using the ROM data and keyfile data 1513 | bool DoAmigaROMCryptOperation(uint8_t *rom_data_without_crypt_header, const size_t rom_size, const uint8_t *keyfile_data, const size_t keyfile_size) 1514 | { 1515 | size_t i = 0; 1516 | size_t key_idx = 0; 1517 | 1518 | if(!rom_data_without_crypt_header || rom_size == 0 || !keyfile_data || keyfile_size == 0) 1519 | { 1520 | return false; 1521 | } 1522 | 1523 | for(i = 0; i < rom_size; i++) 1524 | { 1525 | rom_data_without_crypt_header[i] ^= keyfile_data[key_idx]; 1526 | key_idx = (key_idx + 1) % keyfile_size; 1527 | } 1528 | 1529 | return true; 1530 | } 1531 | 1532 | // 0 indicates the ROM is not byte swapped (the ROM is for emulators) 1533 | // 1 indicates the ROM is byte swapped (the ROM is for physical ICs) 1534 | // -1 indicates the ROM is not an Amiga ROM known to this library, 1535 | // and the header is not indicative of its byte swappiness. 1536 | int DetectAmigaROMByteSwap(const ParsedAmigaROMData *amiga_rom) 1537 | { 1538 | uint8_t *digest; 1539 | char *hexdigest; 1540 | 1541 | uint8_t rom_type = 0; 1542 | size_t i; 1543 | size_t rom_quantity = sizeof(AMIGA_ROM_INFO) / sizeof(AmigaROMInfo); 1544 | 1545 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1546 | { 1547 | return -1; 1548 | } 1549 | 1550 | digest = (uint8_t*)malloc(20); 1551 | if(!digest) 1552 | { 1553 | return -1; 1554 | } 1555 | 1556 | hexdigest = (char*)malloc(41); 1557 | if(!hexdigest) 1558 | { 1559 | free(digest); 1560 | digest = NULL; 1561 | return -1; 1562 | } 1563 | 1564 | if (sha1digest(digest, hexdigest, amiga_rom->rom_data, amiga_rom->rom_size)) 1565 | { 1566 | free(digest); 1567 | digest = NULL; 1568 | free(hexdigest); 1569 | hexdigest = NULL; 1570 | return -1; 1571 | } 1572 | 1573 | for (i = 0; i < rom_quantity; i++) 1574 | { 1575 | if (strncmp(hexdigest, AMIGA_ROM_INFO[i].sha1hash, 40) == 0) 1576 | { 1577 | free(digest); 1578 | digest = NULL; 1579 | free(hexdigest); 1580 | hexdigest = NULL; 1581 | return AMIGA_ROM_INFO[i].byte_swap; 1582 | } 1583 | } 1584 | 1585 | free(digest); 1586 | digest = NULL; 1587 | free(hexdigest); 1588 | hexdigest = NULL; 1589 | 1590 | rom_type = DetectAmigaKickstartROMTypeFromHeader(amiga_rom); 1591 | 1592 | if((rom_type & 0x80) == 0x80) 1593 | { 1594 | return 1; 1595 | } 1596 | else if(rom_type != 0) 1597 | { 1598 | return 0; 1599 | } 1600 | 1601 | return -1; 1602 | } 1603 | 1604 | // Get the unencrypted size of the Amiga ROM in bytes, based on the 1605 | // data passed in. 1606 | size_t DetectUnencryptedAmigaROMSize(const ParsedAmigaROMData *amiga_rom) 1607 | { 1608 | size_t actual_rom_size; 1609 | 1610 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1611 | { 1612 | return false; 1613 | } 1614 | 1615 | actual_rom_size = amiga_rom->rom_size; 1616 | 1617 | if(DetectAmigaROMEncryption(amiga_rom)) 1618 | { 1619 | actual_rom_size = amiga_rom->rom_size - 11; 1620 | } 1621 | 1622 | return actual_rom_size; 1623 | } 1624 | 1625 | // If swap_unconditionally is true, the method will swap the ROM's bytes regardless of whether 1626 | // or not it is a known ROM. 1627 | // Returns true for success or false for failure. 1628 | bool SetAmigaROMByteSwap(ParsedAmigaROMData *amiga_rom, const bool swap_bytes, const bool unswap_bytes, const bool swap_unconditionally) 1629 | { 1630 | size_t i; 1631 | int is_swapped = 0; 1632 | 1633 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0) 1634 | { 1635 | return false; 1636 | } 1637 | 1638 | if(swap_bytes && unswap_bytes && !swap_unconditionally) 1639 | { 1640 | return false; 1641 | } 1642 | 1643 | if(!swap_unconditionally) 1644 | { 1645 | is_swapped = DetectAmigaROMByteSwap(amiga_rom); 1646 | if (is_swapped < 0) 1647 | { 1648 | return false; 1649 | } 1650 | } 1651 | 1652 | if (swap_unconditionally || (is_swapped == 0 && swap_bytes) || (is_swapped == 1 && unswap_bytes)) 1653 | { 1654 | for (i = 0; i < amiga_rom->rom_size; i += 2) 1655 | { 1656 | // In-place XOR swap of two bytes 1657 | (amiga_rom->rom_data)[i] ^= (amiga_rom->rom_data)[i + 1]; 1658 | (amiga_rom->rom_data)[i + 1] ^= (amiga_rom->rom_data)[i]; 1659 | (amiga_rom->rom_data)[i] ^= (amiga_rom->rom_data)[i + 1]; 1660 | } 1661 | 1662 | amiga_rom->is_byte_swapped = !(amiga_rom->is_byte_swapped); 1663 | return true; 1664 | } 1665 | 1666 | return false; 1667 | } 1668 | 1669 | // For this method, ROM A and ROM B should each be the same size as the merged ROM. 1670 | // Each A and B ROM gets the same contents repeated twice. 1671 | // Returns true if it succeeds, or false if it doesn't. 1672 | bool SplitAmigaROM(const ParsedAmigaROMData *amiga_rom, ParsedAmigaROMData *rom_high, ParsedAmigaROMData *rom_low) 1673 | { 1674 | uint8_t *test_ptr; 1675 | 1676 | size_t i; 1677 | 1678 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0 || amiga_rom->rom_size % 2 != 0 || !rom_high || !rom_low) 1679 | { 1680 | return false; 1681 | } 1682 | 1683 | ParsedAmigaROMData *temp_rom_data = (ParsedAmigaROMData*)malloc(sizeof(*amiga_rom)); 1684 | 1685 | memcpy(temp_rom_data, amiga_rom, sizeof(*amiga_rom)); 1686 | 1687 | if(temp_rom_data->parsed_rom) 1688 | { 1689 | SetAmigaROMByteSwap(temp_rom_data, !(temp_rom_data->is_byte_swapped), temp_rom_data->is_byte_swapped, false); 1690 | } 1691 | 1692 | if(rom_high->rom_data) 1693 | { 1694 | test_ptr = realloc(rom_high->rom_data, amiga_rom->rom_size); 1695 | printf("fdsa\n"); 1696 | if(!test_ptr) 1697 | { 1698 | free(temp_rom_data); 1699 | return false; 1700 | } 1701 | else 1702 | { 1703 | rom_high->rom_data = test_ptr; 1704 | rom_high->rom_size = amiga_rom->rom_size; 1705 | test_ptr = NULL; 1706 | } 1707 | } 1708 | else 1709 | { 1710 | test_ptr = (uint8_t*)malloc(amiga_rom->rom_size); 1711 | if(!test_ptr) 1712 | { 1713 | free(temp_rom_data); 1714 | return false; 1715 | } 1716 | else 1717 | { 1718 | rom_high->rom_data = test_ptr; 1719 | rom_high->rom_size = amiga_rom->rom_size; 1720 | test_ptr = NULL; 1721 | } 1722 | } 1723 | 1724 | if(rom_low->rom_data) 1725 | { 1726 | printf("dddd\n"); 1727 | printf("Low ROM: %p\n", (void*)rom_low); 1728 | printf("Low ROM data: %p\n", (void*)rom_low->rom_data); 1729 | test_ptr = realloc(rom_low->rom_data, amiga_rom->rom_size); 1730 | printf("asdf\n"); 1731 | if(!test_ptr) 1732 | { 1733 | free(temp_rom_data); 1734 | return false; 1735 | } 1736 | else 1737 | { 1738 | rom_low->rom_data = test_ptr; 1739 | rom_low->rom_size = amiga_rom->rom_size; 1740 | test_ptr = NULL; 1741 | } 1742 | } 1743 | else 1744 | { 1745 | test_ptr = (uint8_t*)malloc(amiga_rom->rom_size); 1746 | if(!test_ptr) 1747 | { 1748 | free(temp_rom_data); 1749 | return false; 1750 | } 1751 | else 1752 | { 1753 | rom_low->rom_data = test_ptr; 1754 | rom_low->rom_size = amiga_rom->rom_size; 1755 | test_ptr = NULL; 1756 | } 1757 | } 1758 | 1759 | for(i = 0; i < amiga_rom->rom_size; i = i + 4) 1760 | { 1761 | memcpy(&(rom_high->rom_data)[i / 2], &(amiga_rom->rom_data)[i], 2); 1762 | memcpy(&(rom_low->rom_data)[i / 2], &(amiga_rom->rom_data)[i + 2], 2); 1763 | } 1764 | 1765 | memcpy(&(rom_high->rom_data)[amiga_rom->rom_size / 2], &(rom_high->rom_data)[0], amiga_rom->rom_size / 2); 1766 | memcpy(&(rom_low->rom_data)[amiga_rom->rom_size / 2], &(rom_low->rom_data)[0], amiga_rom->rom_size / 2); 1767 | 1768 | ParseAmigaROMData(rom_high, NULL); 1769 | ParseAmigaROMData(rom_low, NULL); 1770 | 1771 | free(temp_rom_data); 1772 | 1773 | return true; 1774 | } 1775 | 1776 | // For this method, ROM A and ROM B should each be the same size as the merged ROM. 1777 | // Each A and B ROM gets the same contents repeated twice. 1778 | // Returns true if it succeeds, or false if it doesn't. 1779 | bool MergeAmigaROM(const ParsedAmigaROMData *rom_high, const ParsedAmigaROMData *rom_low, ParsedAmigaROMData *amiga_rom) 1780 | { 1781 | uint8_t *test_ptr; 1782 | 1783 | size_t i; 1784 | 1785 | if(!amiga_rom || !rom_high || !(rom_high->rom_data) || !rom_low || !(rom_low->rom_data) || rom_high->rom_size != rom_low->rom_size || rom_high->rom_size == 0 || rom_high->rom_size % 4 != 0) 1786 | { 1787 | return false; 1788 | } 1789 | 1790 | if(amiga_rom->rom_data) 1791 | { 1792 | test_ptr = realloc(amiga_rom->rom_data, rom_high->rom_size); 1793 | if(!test_ptr) 1794 | { 1795 | return false; 1796 | } 1797 | else 1798 | { 1799 | amiga_rom->rom_data = test_ptr; 1800 | amiga_rom->rom_size = rom_high->rom_size; 1801 | } 1802 | } 1803 | else 1804 | { 1805 | test_ptr = (uint8_t*)malloc(rom_high->rom_size); 1806 | if(!test_ptr) 1807 | { 1808 | return false; 1809 | } 1810 | else 1811 | { 1812 | amiga_rom->rom_data = test_ptr; 1813 | amiga_rom->rom_size = rom_high->rom_size; 1814 | test_ptr = NULL; 1815 | } 1816 | } 1817 | 1818 | for(i = 0; i < rom_high->rom_size / 4; i++) 1819 | { 1820 | memcpy(&(amiga_rom->rom_data)[i * 4], &(rom_high->rom_data)[i * 2], 2); 1821 | memcpy(&(amiga_rom->rom_data)[(i * 4) + 2], &(rom_low->rom_data)[i * 2], 2); 1822 | } 1823 | 1824 | amiga_rom->rom_size = rom_high->rom_size; 1825 | 1826 | ParseAmigaROMData(amiga_rom, NULL); 1827 | 1828 | return true; 1829 | } 1830 | 1831 | // Write a ROM to disk and return a bool indicating whether the write 1832 | // was successful or not. 1833 | bool WriteAmigaROM(const ParsedAmigaROMData *amiga_rom, const char *rom_file_path) 1834 | { 1835 | FILE *fp; 1836 | 1837 | size_t bytes_written = 0; 1838 | 1839 | if(!amiga_rom || !(amiga_rom->rom_data) || amiga_rom->rom_size == 0 || !rom_file_path) 1840 | { 1841 | return false; 1842 | } 1843 | 1844 | fp = fopen(rom_file_path, "wb"); 1845 | if(!fp) 1846 | { 1847 | return false; 1848 | } 1849 | 1850 | bytes_written = fwrite(amiga_rom->rom_data, 1, amiga_rom->rom_size, fp); 1851 | fclose(fp); 1852 | 1853 | if(bytes_written != amiga_rom->rom_size) 1854 | { 1855 | #if defined(_MSC_VER) 1856 | #pragma warning(push) 1857 | #pragma warning(disable: 4996) 1858 | #endif 1859 | unlink(rom_file_path); 1860 | #if defined(_MSC_VER) 1861 | #pragma warning(pop) 1862 | #endif 1863 | return false; 1864 | } 1865 | 1866 | return true; 1867 | } 1868 | -------------------------------------------------------------------------------- /AmigaROMUtil.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 Christopher Gelatt 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #ifndef AMIGAROMUTIL_H 26 | #define AMIGAROMUTIL_H 27 | 28 | #include "AmigaROMHashes.h" 29 | 30 | #include 31 | #include 32 | 33 | typedef struct { 34 | bool is_initialized; 35 | bool parsed_rom; 36 | uint8_t *rom_data; 37 | size_t rom_size; 38 | bool validated_size; 39 | bool has_reset_vector; 40 | bool is_encrypted; 41 | bool can_decrypt; 42 | bool successfully_decrypted; 43 | bool is_byte_swapped; 44 | bool has_valid_checksum; 45 | uint8_t header; 46 | char type; 47 | const char *version; 48 | uint16_t major_version; 49 | uint16_t minor_version; 50 | const char *major_minor_version; 51 | bool is_kickety_split; 52 | bool valid_footer; 53 | } ParsedAmigaROMData; 54 | 55 | // Create and return a new and initialized struct. 56 | // Pointers are NOT allocated, but are NULL instead. 57 | ParsedAmigaROMData GetInitializedAmigaROM(void); 58 | 59 | // Free all pointers which are expected to potentially be 60 | // allocated in a struct and sets the pointers to NULL, 61 | // and sets the rest of the struct to default values. 62 | void DestroyInitializedAmigaROM(ParsedAmigaROMData *amiga_rom); 63 | 64 | // Returns a parsed ROM data struct, with the ROM data and size included. 65 | // If anything files, parsed_rom will be false. If encrypted, the ROM 66 | // will be decrypted. 67 | ParsedAmigaROMData ReadAmigaROM(const char *rom_file_path, const char *keyfile_path); 68 | 69 | // Detect whether a ROM is an Amiga kickstart ROM based on size, header, reset vector, 70 | // magic, and footer. 71 | bool IsAmigaROM(const ParsedAmigaROMData *amiga_rom); 72 | 73 | // Puts ROM info data into output_string 74 | void PrintAmigaROMInfo(const ParsedAmigaROMData *amiga_rom, char *output_string, const size_t string_length); 75 | 76 | // Parses and validates the data in the Amiga ROM updates the struct 77 | // passed in with that data. 78 | void ParseAmigaROMData(ParsedAmigaROMData *amiga_rom, const char* keyfile_path); 79 | 80 | // Return whether an Amiga ROM is a valid size, accounting for 81 | // encryption, if it's there. 82 | bool ValidateAmigaROMSize(const ParsedAmigaROMData *amiga_rom); 83 | 84 | // Validate that there is a reset vector (0x0x4E70) at 0x000000D0. 85 | // Returns true if there is, or false if there isn't. 86 | bool ValidateAmigaROMResetVector(const ParsedAmigaROMData *amiga_rom); 87 | 88 | // Detects the version of the ROM by SHA1 hash 89 | // Returns NULL for failure, else a string indicating the ROM version 90 | const char* DetectAmigaROMVersion(const ParsedAmigaROMData *amiga_rom); 91 | 92 | // Detects the major version in the Amiga ROM header 93 | // Returns 0 if the ROM is not detects as an Amiga ROM 94 | uint16_t DetectAmigaMajorROMVersion(const ParsedAmigaROMData *amiga_rom); 95 | 96 | // Detects the minor version in the Amiga ROM header 97 | // Returns 0 if the ROM is not detects as an Amiga ROM 98 | uint16_t DetectAmigaMinorROMVersion(const ParsedAmigaROMData *amiga_rom); 99 | 100 | // Returns a version string based on the major and minor versions in the Amiga ROM header 101 | // Returns NULL if the ROM is not detects as an Amiga ROM or the version is unknown 102 | const char* DetectAmigaMajorMinorROMVersion(const ParsedAmigaROMData *amiga_rom); 103 | 104 | // Returns a character indicating the type of ROM detected based on the SHA1 hash 105 | // Valid return values are: 106 | // A - Kickstart Hi/U34 ROM 107 | // B - Kickstart Lo/U35 ROM 108 | // E - Extended Amiga ROM 109 | // M - Kickstart merged ROM 110 | // O - Other (non-Kickstart) ROM 111 | // U - Unknown ROM 112 | char DetectAmigaROMType(const ParsedAmigaROMData *amiga_rom); 113 | 114 | // Detect whether a ROM is a "Kickety-Split ROM" 115 | // Returns true if it is, and false if it isn't. 116 | bool DetectKicketySplitAmigaROM(const ParsedAmigaROMData *amiga_rom); 117 | 118 | // Detect which type of kickstart ROM a purported Kickstart ROM claims to be 119 | // based on its header and size. If this data is not consistent, or is unknown, 120 | // the method returns 0x00. Otherwise, the lower seven bits will determine what 121 | // type of Kickstart ROM this is, according to the following table: 122 | // 123 | // 0x00: Not an Amiga ROM 124 | // 0x01: 256KB ROM 125 | // 0x02: 512KB ROM 126 | // 0x03: Extended ROM 127 | // 0x04: "ReKick" ROM 128 | // 0x05: Ambiguous (may or may not be an Amiga ROM of another type) 129 | // 130 | // If the ROM is byte-swapped, then the topmost bit will be a 1, with the rest 131 | // of the seven bits as the table above. 132 | uint8_t DetectAmigaKickstartROMTypeFromHeader(const ParsedAmigaROMData *amiga_rom); 133 | 134 | // Returns an unsigned 32-bit integer with the checksum for the ROM. 135 | // This checksum is used by Amigas to validate whether a ROM is undamaged, 136 | // and is located 24 bytes from the end of the ROM. 137 | // If calc_new_sum is true, then the function will return a checksum value which 138 | // will be accepted for use by an Amiga system. 139 | uint32_t CalculateAmigaROMChecksum(const ParsedAmigaROMData *amiga_rom, const bool calc_new_sum); 140 | 141 | // Returns the checksum embedded in the ROM, or 0 if it fails. 142 | // Technically a ROM could have a valid checksum of zero, but 143 | // this is exceedingly unlikely. 144 | uint32_t GetEmbeddedAmigaROMChecksum(const ParsedAmigaROMData *amiga_rom); 145 | 146 | // Returns a boolean indicating whether the calculated checksum in the ROM 147 | // matches the calculated checksum for the ROM. 148 | bool ValidateAmigaROMChecksum(const ParsedAmigaROMData *amiga_rom); 149 | 150 | // Calculates and embeds a correct checksum in the ROM. 151 | // Returns true if it succeeds, or false if it fails. 152 | bool CorrectAmigaROMChecksum(ParsedAmigaROMData *amiga_rom); 153 | 154 | // Validates whether an Amiga kickstart ROM as a valid footer. 155 | // Returns true if it does, or false if it doesn't. 156 | bool ValidateAmigaKickstartROMFooter(const ParsedAmigaROMData *amiga_rom); 157 | 158 | // Validate the ROM size matches the size embedded in the ROM. 159 | // Returns true if it does, or false if it doesn't. 160 | bool ValidateEmbeddedAmigaROMSize(const ParsedAmigaROMData *amiga_rom); 161 | 162 | // Detects whether an Amiga ROM is encrypted. 163 | // Returns 1 if it is, 0 if it isn't, or -1 if it has an invalid size. 164 | int DetectAmigaROMEncryption(const ParsedAmigaROMData *amiga_rom); 165 | 166 | // Encrypts or decrypts Amiga ROMs according to whether crypt_operation is true or false. 167 | // If true, it will encrypt the ROMs. If false, it will decrypt them. 168 | // The function returns true if the method succeeds, and false if it fails. 169 | // For safety, make sure that rom_contents has space for 11 more bytes than the original 170 | // ROM had if an encrypt operation is performed. 171 | bool CryptAmigaROM(ParsedAmigaROMData *amiga_rom, const bool crypt_operation, const char *keyfile_path); 172 | 173 | // Run the actual crypt operation, using the ROM data and keyfile data 174 | bool DoAmigaROMCryptOperation(uint8_t *rom_data_without_crypt_header, const size_t rom_size, const uint8_t *keyfile_data, const size_t keyfile_size); 175 | 176 | // 0 indicates the ROM is not byte swapped (the ROM is for emulators) 177 | // 1 indicates the ROM is byte swapped (the ROM is for physical ICs) 178 | // -1 indicates the ROM is not an Amiga ROM known to this library, 179 | // and the header is not indicative of its byte swappiness. 180 | int DetectAmigaROMByteSwap(const ParsedAmigaROMData *amiga_rom); 181 | 182 | // Get the unencrypted size of the Amiga ROM in bytes, based on the 183 | // data passed in. 184 | size_t DetectUnencryptedAmigaROMSize(const ParsedAmigaROMData *amiga_rom); 185 | 186 | // If swap_unconditionally is true, the method will swap the ROM's bytes regardless of whether 187 | // or not it is a known ROM. 188 | // Returns true for success or false for failure. 189 | bool SetAmigaROMByteSwap(ParsedAmigaROMData *amiga_rom, const bool swap_bytes, const bool unswap_bytes, const bool swap_unconditionally); 190 | 191 | // For this method, ROM A and ROM B should each be the same size as the merged ROM. 192 | // Each A and B ROM gets the same contents repeated twice. 193 | bool SplitAmigaROM(const ParsedAmigaROMData *amiga_rom, ParsedAmigaROMData *rom_high, ParsedAmigaROMData *rom_low); 194 | 195 | // For this method, ROM A and ROM B should each be the same size as the merged ROM. 196 | // Each A and B ROM gets the same contents repeated twice. 197 | bool MergeAmigaROM(const ParsedAmigaROMData *rom_high, const ParsedAmigaROMData *rom_low, ParsedAmigaROMData *amiga_rom); 198 | 199 | // Write a ROM to disk and return a bool indicating whether the write 200 | // was successful or not. 201 | bool WriteAmigaROM(const ParsedAmigaROMData *amiga_rom, const char *rom_file_path); 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Christopher Gelatt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2021 Christopher Gelatt 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | CFLAGS = -O2 -std=c17 -Wall -Wextra -Werror -pedantic-errors 24 | LIB_SRCS = AmigaROMUtil.c teeny-sha1.c 25 | MAIN_SRC = main.c 26 | LIB_OBJS = $(LIB_SRCS:.c=.o) 27 | MAIN_OBJ = $(MAIN_SRC:.c=.o) 28 | ifneq ($(OS),Windows_NT) 29 | MAIN = AmigaROMUtil 30 | UNAME_S := $(shell uname -s) 31 | ifeq ($(UNAME_S),Darwin) 32 | SHARED_LIB = libamigarom.dylib 33 | SO_LIB_CMD = $(CC) $(CFLAGS) -dynamiclib -o $(SHARED_LIB) $(LIB_OBJS) 34 | else 35 | SHARED_LIB = libamigarom.so 36 | SO_LIB_CMD = $(CC) $(CFLAGS) -o $(SHARED_LIB) $(LIB_OBJS) -shared 37 | endif 38 | STATIC_LIB = libamigarom.a 39 | else 40 | MAIN = AmigaROMUtil.exe 41 | SHARED_LIB = amigarom.dll 42 | STATIC_LIB = amigarom.lib 43 | SO_LIB_CMD = $(CC) $(CFLAGS) -o $(SHARED_LIB) $(LIB_OBJS) -shared 44 | endif 45 | 46 | all: $(SHARED_LIB) $(STATIC_LIB) $(MAIN) 47 | 48 | libs: $(SHARED_LIB) $(STATIC_LIB) 49 | 50 | shared: $(SHARED_LIB) 51 | 52 | $(SHARED_LIB): $(LIB_OBJS) 53 | $(SO_LIB_CMD) 54 | 55 | static: $(STATIC_LIB) 56 | 57 | $(STATIC_LIB): $(LIB_OBJS) 58 | $(AR) -rv $(STATIC_LIB) $(LIB_OBJS) 59 | 60 | app: $(MAIN) 61 | 62 | $(MAIN): $(LIB_OBJS) $(MAIN_OBJ) 63 | $(CC) $(CFLAGS) -o $(MAIN) $(LIB_OBJS) $(MAIN_OBJ) 64 | 65 | clean: 66 | $(RM) $(LIB_OBJS) $(MAIN_OBJ) $(SHARED_LIB) $(STATIC_LIB) *~ $(MAIN) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AmigaROMUtil 2 | A utility for splitting, merging, encrypting, decrypting, byte swapping/unswapping, and checksumming Amiga Kickstart ROMs with a database of known ROMs 3 | 4 | This is intended to be both a standalone application as well as a set of files (everything but main.c and the Makefile) which can easily be used in other applications in order to easily provide similar functionality. 5 | 6 | For the known ROMs, I pulled the ones from my copy of Amiga Forever 9, but I'm sure there are quite a few I'm missing as a result. Any additions or corrections to that data would be very welcome. 7 | 8 | To build, just run `make`. -------------------------------------------------------------------------------- /RemusTools.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 Christopher Gelatt 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #ifndef REMUSTOOLS_H 26 | #define REMUSTOOLS_H 27 | 28 | #include 29 | 30 | #define REMUS_SPLIT_FILE_HEADER 0x524D5346 31 | #define REMUS_SPLIT_FILE_VERSION_5 0x00020005 32 | #define REMUS_SPLIT_FILE_VERSION_7 0x00020007 33 | 34 | typedef struct RemusFile { 35 | uint32_t header; 36 | uint32_t version; 37 | uint8_t *file_data; 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2021 Christopher Gelatt 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #include "AmigaROMUtil.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | void print_help(void); 36 | int print_rom_info(const char* encryption_key_path, const char* rom_input_path); 37 | int split_rom(const bool swap, const bool unswap, const bool unconditional_swap, const char* encryption_key_path, const bool correct_checksum, const char* rom_high_path, const char* rom_low_path, const char* rom_input_path); 38 | int merge_rom(const bool swap, const bool unswap, const bool unconditional_swap, const bool encrypt_rom, const char* encryption_key_path, const bool correct_checksum, const char* rom_high_path, const char* rom_low_path, const char* rom_output_path); 39 | int swap_rom(const bool swap_state, const bool unconditional_swap, const bool encrypt_rom, const char* encryption_key_path, const bool correct_checksum, const char* rom_input_path, const char* rom_output_path); 40 | int crypt_rom(const bool encryption_state, const char* encryption_key_path, const char* rom_input_path, const char* rom_output_path); 41 | int checksum_rom(const bool correct_checksum, const char* encryption_key_path, const char* rom_input_path, const char* rom_output_path); 42 | 43 | int main(int argc, char** argv) 44 | { 45 | char* rom_input_path = NULL; 46 | char* rom_output_path = NULL; 47 | char* rom_high_path = NULL; 48 | char* rom_low_path = NULL; 49 | char* encryption_key_path = NULL; 50 | bool rom_info = false; 51 | bool split = false; 52 | bool merge = false; 53 | bool swap = false; 54 | bool unswap = false; 55 | bool unconditional_swap = false; 56 | bool validate_checksum = false; 57 | bool correct_checksum = false; 58 | bool encrypt_rom = false; 59 | bool decrypt_rom = false; 60 | int c; 61 | int operation_result = 0; 62 | 63 | while((c = getopt(argc, argv, "i:o:a:b:k:fsgpunvcedh")) != -1) 64 | { 65 | switch(c) 66 | { 67 | case 'i': 68 | rom_input_path = strdup(optarg); 69 | break; 70 | case 'o': 71 | rom_output_path = strdup(optarg); 72 | break; 73 | case 'a': 74 | rom_high_path = strdup(optarg); 75 | break; 76 | case 'b': 77 | rom_low_path = strdup(optarg); 78 | break; 79 | case 'k': 80 | encryption_key_path = strdup(optarg); 81 | break; 82 | case 'f': 83 | rom_info = true; 84 | break; 85 | case 's': 86 | split = true; 87 | break; 88 | case 'g': 89 | merge = true; 90 | break; 91 | case 'p': 92 | swap = true; 93 | break; 94 | case 'u': 95 | unswap = true; 96 | break; 97 | case 'n': 98 | unconditional_swap = true; 99 | break; 100 | case 'v': 101 | validate_checksum = true; 102 | break; 103 | case 'c': 104 | correct_checksum = true; 105 | break; 106 | case 'e': 107 | encrypt_rom = true; 108 | break; 109 | case 'd': 110 | decrypt_rom = true; 111 | break; 112 | case 'h': 113 | default: 114 | print_help(); 115 | exit(0); 116 | } 117 | } 118 | 119 | if(unconditional_swap) 120 | { 121 | swap = true; 122 | unswap = false; 123 | } 124 | 125 | if(!rom_info && !split && !merge && !swap && !unswap && !encrypt_rom && !decrypt_rom && !validate_checksum && !correct_checksum) 126 | { 127 | print_help(); 128 | exit(1); 129 | } 130 | 131 | if(rom_info && !rom_input_path) 132 | { 133 | print_help(); 134 | exit(1); 135 | } 136 | 137 | if(split && merge) 138 | { 139 | print_help(); 140 | exit(1); 141 | } 142 | 143 | if(encrypt_rom && decrypt_rom) 144 | { 145 | print_help(); 146 | exit(1); 147 | } 148 | 149 | if(split && (!rom_input_path || !rom_high_path || !rom_low_path)) 150 | { 151 | print_help(); 152 | exit(1); 153 | } 154 | 155 | if(merge && (!rom_output_path || !rom_high_path || !rom_low_path)) 156 | { 157 | print_help(); 158 | exit(1); 159 | } 160 | 161 | if(swap && (!rom_input_path || !rom_output_path)) 162 | { 163 | print_help(); 164 | exit(1); 165 | } 166 | 167 | if(unswap && (!rom_input_path || !rom_output_path)) 168 | { 169 | print_help(); 170 | exit(1); 171 | } 172 | 173 | if((encrypt_rom || decrypt_rom || correct_checksum) && (!rom_input_path || !rom_output_path)) 174 | { 175 | print_help(); 176 | exit(1); 177 | } 178 | 179 | if(validate_checksum && (!rom_input_path && !merge)) 180 | { 181 | print_help(); 182 | exit(1); 183 | } 184 | 185 | if((encrypt_rom || decrypt_rom) && !encryption_key_path) 186 | { 187 | print_help(); 188 | exit(1); 189 | } 190 | 191 | if(rom_info) 192 | { 193 | operation_result = print_rom_info(encryption_key_path, rom_input_path); 194 | } 195 | else if(split) 196 | { 197 | operation_result = split_rom(swap, unswap, unconditional_swap, encryption_key_path, correct_checksum, rom_high_path, rom_low_path, rom_input_path); 198 | } 199 | else if(merge) 200 | { 201 | operation_result = merge_rom(swap, unswap, unconditional_swap, encrypt_rom, encryption_key_path, correct_checksum, rom_high_path, rom_low_path, rom_output_path); 202 | } 203 | else if(swap) 204 | { 205 | operation_result = swap_rom(true, unconditional_swap, encrypt_rom, encryption_key_path, correct_checksum, rom_input_path, rom_output_path); 206 | } 207 | else if(unswap) 208 | { 209 | operation_result = swap_rom(false, unconditional_swap, encrypt_rom, encryption_key_path, correct_checksum, rom_input_path, rom_output_path); 210 | } 211 | else if(encrypt_rom) 212 | { 213 | operation_result = crypt_rom(true, encryption_key_path, rom_input_path, rom_output_path); 214 | } 215 | else if(decrypt_rom) 216 | { 217 | operation_result = crypt_rom(false, encryption_key_path, rom_input_path, rom_output_path); 218 | } 219 | else if(correct_checksum) 220 | { 221 | operation_result = checksum_rom(true, encryption_key_path, rom_input_path, rom_output_path); 222 | } 223 | else if(validate_checksum) 224 | { 225 | operation_result = checksum_rom(false, encryption_key_path, rom_input_path, NULL); 226 | } 227 | 228 | free(rom_high_path); 229 | free(rom_low_path); 230 | free(rom_input_path); 231 | free(rom_output_path); 232 | free(encryption_key_path); 233 | 234 | exit(operation_result); 235 | } 236 | 237 | void print_help(void) 238 | { 239 | printf("Usage: AmigaROMUtil [options]\n"); 240 | printf("Options:\n"); 241 | printf(" -i FILE Path to input ROM (except for merging)\n"); 242 | printf(" -o FILE Path to output ROM (except for splitting)\n"); 243 | printf(" -a FILE Path to High ROM for merging or splitting\n"); 244 | printf(" -b FILE Path to Low ROM for merging or splitting\n"); 245 | printf(" -k FILE Path to ROM encryption/decryption key\n"); 246 | printf(" -f Print ROM info and quit (requires -i)\n"); 247 | printf(" -s Split ROM (requires -i, -a, -b)\n"); 248 | printf(" -g Merge ROM (requires -a, -b, -o)\n"); 249 | printf(" -p Byte swap ROM for burning to an IC (requires -i, -o)\n"); 250 | printf(" -u Unbyte swap ROM for use with emulators (requires -i, -o)\n"); 251 | printf(" -n Unconditional byte swap for ROMs which are unknown to this program\n"); 252 | printf(" -v Validate checksum (requires -i)\n"); 253 | printf(" -c Correct checksum (requires -i, -o)\n"); 254 | printf(" -e Encrypt ROM (requires -i, -o, -k)\n"); 255 | printf(" -d Decrypt ROM (requires -i, -o, -k)\n"); 256 | printf(" -h Display this information\n"); 257 | printf("\n"); 258 | printf("Notes:\n"); 259 | printf("-n implies -u and not -n, and will override those if set\n"); 260 | printf("-s and -m, -p and -u, -e and -d are each mutually exclusive\n"); 261 | return; 262 | } 263 | 264 | int print_rom_info(const char* encryption_key_path, const char* rom_input_path) 265 | { 266 | char *info_string = NULL; 267 | ParsedAmigaROMData input_rom = GetInitializedAmigaROM(); 268 | 269 | info_string = (char *)malloc(4096); 270 | if(!info_string) 271 | { 272 | return 1; 273 | } 274 | 275 | input_rom = ReadAmigaROM(rom_input_path, encryption_key_path); 276 | PrintAmigaROMInfo(&input_rom, info_string, 4096); 277 | 278 | printf("%s\n", info_string); 279 | 280 | free(info_string); 281 | 282 | return 0; 283 | } 284 | 285 | int split_rom(const bool swap, const bool unswap, const bool unconditional_swap, const char* encryption_key_path, const bool correct_checksum, const char* rom_high_path, const char* rom_low_path, const char* rom_input_path) 286 | { 287 | ParsedAmigaROMData high_rom = GetInitializedAmigaROM(); 288 | ParsedAmigaROMData input_rom = GetInitializedAmigaROM(); 289 | ParsedAmigaROMData low_rom = GetInitializedAmigaROM(); 290 | 291 | input_rom = ReadAmigaROM(rom_input_path, encryption_key_path); 292 | if(!input_rom.parsed_rom) 293 | { 294 | if(input_rom.is_encrypted && !input_rom.can_decrypt) 295 | { 296 | printf("ERROR: Source ROM is encrypted. Please provide a valid key to decrypt."); 297 | } 298 | else 299 | { 300 | printf("ERROR: Unable to load source ROM at: %s\n", rom_high_path); 301 | printf("Is it a valid ROM?\n"); 302 | } 303 | 304 | if(input_rom.rom_data) 305 | { 306 | DestroyInitializedAmigaROM(&input_rom); 307 | } 308 | 309 | return 1; 310 | } 311 | 312 | if(input_rom.version == NULL) 313 | { 314 | printf("WARNING: Unknown source ROM loaded.\n"); 315 | } 316 | else 317 | { 318 | printf("Detected source ROM: %s\n", input_rom.version); 319 | } 320 | 321 | if(input_rom.type != 'M') 322 | { 323 | printf("ROM type: %c\n", input_rom.type); 324 | printf("WARNING: ROM is not detected as a known merged ROM.\n"); 325 | } 326 | 327 | if(input_rom.has_valid_checksum) 328 | { 329 | printf("Source ROM checksum is valid.\n"); 330 | } 331 | else 332 | { 333 | if(correct_checksum) 334 | { 335 | if(CorrectAmigaROMChecksum(&input_rom)) 336 | { 337 | printf("Corrected source ROM checksum.\n"); 338 | } 339 | else 340 | { 341 | DestroyInitializedAmigaROM(&input_rom); 342 | printf("ERROR: Unable to correct source ROM checksum.\n"); 343 | return 1; 344 | } 345 | } 346 | else 347 | { 348 | printf("WARNING: Source ROM checksum is invalid.\n"); 349 | } 350 | } 351 | 352 | if((swap || unswap) && ((input_rom.type != 'U' || unconditional_swap) || SetAmigaROMByteSwap(&input_rom, swap, unswap, unconditional_swap) == 0)) 353 | { 354 | DestroyInitializedAmigaROM(&input_rom); 355 | printf("ERROR: Unable to perform conditional swap operation. Aborting.\n"); 356 | return 1; 357 | } 358 | 359 | if(!SplitAmigaROM(&input_rom, &high_rom, &low_rom)) 360 | { 361 | DestroyInitializedAmigaROM(&input_rom); 362 | 363 | if(high_rom.rom_data) 364 | { 365 | DestroyInitializedAmigaROM(&high_rom); 366 | } 367 | 368 | if(low_rom.rom_data) 369 | { 370 | DestroyInitializedAmigaROM(&low_rom); 371 | } 372 | 373 | printf("ERROR: ROM split operation failed. Aborting.\n"); 374 | return 1; 375 | } 376 | 377 | if(!WriteAmigaROM(&high_rom, rom_high_path)) 378 | { 379 | DestroyInitializedAmigaROM(&input_rom); 380 | DestroyInitializedAmigaROM(&high_rom); 381 | DestroyInitializedAmigaROM(&low_rom); 382 | printf("ERROR: Unable to write High ROM to disk. Aborting.\n"); 383 | return 1; 384 | } 385 | 386 | if(!WriteAmigaROM(&low_rom, rom_low_path)) 387 | { 388 | DestroyInitializedAmigaROM(&input_rom); 389 | DestroyInitializedAmigaROM(&high_rom); 390 | DestroyInitializedAmigaROM(&low_rom); 391 | printf("ERROR: Unable to write Low ROM to disk. Aborting.\n"); 392 | return 1; 393 | } 394 | 395 | DestroyInitializedAmigaROM(&input_rom); 396 | DestroyInitializedAmigaROM(&high_rom); 397 | DestroyInitializedAmigaROM(&low_rom); 398 | printf("Successfully wrote High and Low ROMs.\n"); 399 | 400 | return 0; 401 | } 402 | 403 | int merge_rom(const bool swap, const bool unswap, const bool unconditional_swap, const bool encrypt_rom, const char* encryption_key_path, const bool correct_checksum, const char* rom_high_path, const char* rom_low_path, const char* rom_output_path) 404 | { 405 | ParsedAmigaROMData high_rom = GetInitializedAmigaROM(); 406 | ParsedAmigaROMData low_rom = GetInitializedAmigaROM(); 407 | ParsedAmigaROMData output_rom = GetInitializedAmigaROM(); 408 | 409 | high_rom = ReadAmigaROM(rom_high_path, encryption_key_path); 410 | if(!high_rom.parsed_rom) 411 | { 412 | if(high_rom.is_encrypted && !high_rom.can_decrypt) 413 | { 414 | printf("ERROR: High ROM is encrypted. Please provide a valid key to decrypt."); 415 | } 416 | else 417 | { 418 | printf("ERROR: Unable to load High ROM at: %s\n", rom_high_path); 419 | printf("Is it a valid ROM?\n"); 420 | } 421 | 422 | if(high_rom.rom_data) 423 | { 424 | DestroyInitializedAmigaROM(&high_rom); 425 | } 426 | 427 | return 1; 428 | } 429 | 430 | low_rom = ReadAmigaROM(rom_low_path, encryption_key_path); 431 | if(!low_rom.parsed_rom) 432 | { 433 | if(low_rom.is_encrypted && !low_rom.can_decrypt) 434 | { 435 | printf("ERROR: Low ROM is encrypted. Please provide a valid key to decrypt."); 436 | } 437 | else 438 | { 439 | printf("ERROR: Unable to load Low ROM at: %s\n", rom_low_path); 440 | printf("Is it a valid ROM?\n"); 441 | } 442 | 443 | if(low_rom.rom_data) 444 | { 445 | DestroyInitializedAmigaROM(&low_rom); 446 | } 447 | 448 | DestroyInitializedAmigaROM(&high_rom); 449 | return 1; 450 | } 451 | 452 | if(high_rom.rom_size != low_rom.rom_size) 453 | { 454 | printf("ERROR: High and Low ROMs must be the same size to merge.\n"); 455 | return 1; 456 | } 457 | 458 | if(high_rom.version == NULL) 459 | { 460 | printf("WARNING: Unknown High ROM loaded.\n"); 461 | } 462 | else 463 | { 464 | printf("Detected High ROM: %s\n", high_rom.version); 465 | } 466 | 467 | if(low_rom.version == NULL) 468 | { 469 | printf("WARNING: Unknown Low ROM loaded.\n"); 470 | } 471 | else 472 | { 473 | printf("Detected Low ROM: %s\n", low_rom.version); 474 | } 475 | 476 | if(high_rom.version != NULL && low_rom.version == NULL) 477 | { 478 | printf("WARNING: Known High ROM and unknown Low ROM detected.\n"); 479 | } 480 | else if(low_rom.version != NULL && high_rom.version == NULL) 481 | { 482 | printf("WARNING: Known Low ROM and unknown High ROM detected.\n"); 483 | } 484 | else if((high_rom.version != NULL && low_rom.version != NULL) && (strlen(high_rom.version) != strlen(low_rom.version) || strncmp(high_rom.version, low_rom.version, strlen(high_rom.version)) != 0)) 485 | { 486 | printf("WARNING: High and Low ROMs are not from the same set.\n"); 487 | } 488 | 489 | if(high_rom.type != 'A') 490 | { 491 | printf("WARNING: High ROM is not detected as a known High ROM.\n"); 492 | } 493 | 494 | if(low_rom.type != 'B') 495 | { 496 | printf("WARNING: Low ROM is not detected as a known Low ROM.\n"); 497 | } 498 | 499 | if((swap || unswap) && ((high_rom.type != 'U' || unconditional_swap) && SetAmigaROMByteSwap(&high_rom, swap, unswap, unconditional_swap) == 0)) 500 | { 501 | DestroyInitializedAmigaROM(&high_rom); 502 | DestroyInitializedAmigaROM(&low_rom); 503 | printf("ERROR: Unable to perform conditional swap operation for High ROM. Aborting.\n"); 504 | return 1; 505 | } 506 | 507 | if((swap || unswap) && ((low_rom.type != 'U' || unconditional_swap) && SetAmigaROMByteSwap(&low_rom, swap, unswap, unconditional_swap) == 0)) 508 | { 509 | DestroyInitializedAmigaROM(&high_rom); 510 | DestroyInitializedAmigaROM(&low_rom); 511 | printf("ERROR: Unable to perform conditional swap operation for Low ROM. Aborting.\n"); 512 | return 1; 513 | } 514 | 515 | if(!MergeAmigaROM(&high_rom, &low_rom, &output_rom)) 516 | { 517 | if(output_rom.rom_data) 518 | { 519 | DestroyInitializedAmigaROM(&output_rom); 520 | } 521 | 522 | DestroyInitializedAmigaROM(&high_rom); 523 | DestroyInitializedAmigaROM(&low_rom); 524 | printf("ERROR: ROM merge operation failed. Aborting.\n"); 525 | return 1; 526 | } 527 | 528 | ParseAmigaROMData(&output_rom, encryption_key_path); 529 | 530 | if(output_rom.has_valid_checksum) 531 | { 532 | printf("Merged ROM checksum is valid.\n"); 533 | } 534 | else 535 | { 536 | if(correct_checksum) 537 | { 538 | if(CorrectAmigaROMChecksum(&output_rom)) 539 | { 540 | printf("Corrected merged ROM checksum.\n"); 541 | } 542 | else 543 | { 544 | DestroyInitializedAmigaROM(&output_rom); 545 | DestroyInitializedAmigaROM(&high_rom); 546 | DestroyInitializedAmigaROM(&low_rom); 547 | printf("ERROR: Unable to correct merged ROM checksum.\n"); 548 | return 1; 549 | } 550 | } 551 | else 552 | { 553 | printf("WARNING: Merged ROM checksum is invalid.\n"); 554 | } 555 | } 556 | 557 | if(encrypt_rom) 558 | { 559 | if(encryption_key_path == NULL) 560 | { 561 | DestroyInitializedAmigaROM(&output_rom); 562 | DestroyInitializedAmigaROM(&high_rom); 563 | DestroyInitializedAmigaROM(&low_rom); 564 | printf("ERROR: Encrypting a ROM requires specifying an encryption key.\n"); 565 | return 1; 566 | } 567 | 568 | if(high_rom.is_encrypted) 569 | { 570 | printf("INFO: Encrypting merged ROM with the same key as the High ROM.\n"); 571 | } 572 | if(low_rom.is_encrypted) 573 | { 574 | printf("INFO: Encrypting merged ROM with the same key as the Low ROM.\n"); 575 | } 576 | 577 | if(!CryptAmigaROM(&output_rom, true, encryption_key_path)) 578 | { 579 | DestroyInitializedAmigaROM(&output_rom); 580 | DestroyInitializedAmigaROM(&high_rom); 581 | DestroyInitializedAmigaROM(&low_rom); 582 | printf("ERROR: Unable to access ROM encryption key.\n"); 583 | return 1; 584 | } 585 | else 586 | { 587 | printf("Encrypted ROM.\n"); 588 | } 589 | } 590 | 591 | if(!WriteAmigaROM(&output_rom, rom_output_path)) 592 | { 593 | DestroyInitializedAmigaROM(&output_rom); 594 | DestroyInitializedAmigaROM(&high_rom); 595 | DestroyInitializedAmigaROM(&low_rom); 596 | printf("ERROR: Unable to write merged ROM to disk. Aborting."); 597 | return 1; 598 | } 599 | 600 | DestroyInitializedAmigaROM(&output_rom); 601 | DestroyInitializedAmigaROM(&high_rom); 602 | DestroyInitializedAmigaROM(&low_rom); 603 | printf("Successfully wrote merged ROM.\n"); 604 | 605 | return 0; 606 | } 607 | 608 | int swap_rom(const bool swap_state, const bool unconditional_swap, const bool encrypt_rom, const char* encryption_key_path, const bool correct_checksum, const char* rom_input_path, const char* rom_output_path) 609 | { 610 | size_t encrypted_input_rom_size = 0; 611 | ParsedAmigaROMData input_rom = GetInitializedAmigaROM(); 612 | 613 | input_rom = ReadAmigaROM(rom_input_path, encryption_key_path); 614 | if(!input_rom.parsed_rom) 615 | { 616 | if(input_rom.is_encrypted && !input_rom.can_decrypt) 617 | { 618 | printf("ERROR: Source ROM is encrypted. Please provide a valid key to decrypt."); 619 | } 620 | else 621 | { 622 | printf("ERROR: Unable to load source ROM at: %s\n", rom_input_path); 623 | printf("Is it a valid ROM?\n"); 624 | } 625 | 626 | if(input_rom.rom_data != NULL) 627 | { 628 | DestroyInitializedAmigaROM(&input_rom); 629 | } 630 | 631 | return 1; 632 | } 633 | 634 | if(input_rom.version == NULL) 635 | { 636 | printf("WARNING: Unknown source ROM loaded.\n"); 637 | } 638 | else 639 | { 640 | printf("Detected source ROM: %s\n", input_rom.version); 641 | } 642 | 643 | if(SetAmigaROMByteSwap(&input_rom, swap_state, !swap_state, unconditional_swap) == 0) 644 | { 645 | DestroyInitializedAmigaROM(&input_rom); 646 | printf("ERROR: Unable to perform conditional swap operation for ROM. Aborting.\n"); 647 | return 1; 648 | } 649 | 650 | if(input_rom.has_valid_checksum) 651 | { 652 | printf("ROM checksum is valid.\n"); 653 | } 654 | else 655 | { 656 | if(correct_checksum) 657 | { 658 | if(CorrectAmigaROMChecksum(&input_rom)) 659 | { 660 | printf("Corrected ROM checksum.\n"); 661 | } 662 | else 663 | { 664 | DestroyInitializedAmigaROM(&input_rom); 665 | printf("ERROR: Unable to correct checksum for ROM. Aborting.\n"); 666 | return 1; 667 | } 668 | } 669 | else 670 | { 671 | printf("WARNING: ROM checksum is invalid.\n"); 672 | } 673 | } 674 | 675 | if(encrypt_rom) 676 | { 677 | if(encryption_key_path == NULL) 678 | { 679 | DestroyInitializedAmigaROM(&input_rom); 680 | printf("ERROR: Encrypting a ROM requires specifying an encryption key.\n"); 681 | return 1; 682 | } 683 | 684 | if(input_rom.is_encrypted) 685 | { 686 | printf("INFO: Encrypting swapped ROM with the same key as the source ROM.\n"); 687 | } 688 | 689 | if(!CryptAmigaROM(&input_rom, true, encryption_key_path)) 690 | { 691 | DestroyInitializedAmigaROM(&input_rom); 692 | printf("ERROR: Unable to access ROM encryption key.\n"); 693 | return 1; 694 | } 695 | else 696 | { 697 | printf("Encrypted ROM.\n"); 698 | input_rom.rom_size = encrypted_input_rom_size; 699 | } 700 | } 701 | 702 | if(!WriteAmigaROM(&input_rom, rom_output_path)) 703 | { 704 | DestroyInitializedAmigaROM(&input_rom); 705 | printf("ERROR: Unable to write swapped ROM to disk.\n"); 706 | return 1; 707 | } 708 | 709 | DestroyInitializedAmigaROM(&input_rom); 710 | 711 | if(swap_state) 712 | { 713 | printf("Successfully wrote swapped ROM.\n"); 714 | } 715 | else 716 | { 717 | printf("Successfully wrote unswapped ROM.\n"); 718 | } 719 | 720 | return 0; 721 | } 722 | 723 | int crypt_rom(const bool encryption_state, const char* encryption_key_path, const char* rom_input_path, const char* rom_output_path) 724 | { 725 | size_t encrypted_input_rom_size = 0; 726 | 727 | ParsedAmigaROMData input_rom = GetInitializedAmigaROM(); 728 | 729 | input_rom = ReadAmigaROM(rom_input_path, encryption_key_path); 730 | if(!input_rom.parsed_rom) 731 | { 732 | if(input_rom.is_encrypted && !input_rom.can_decrypt) 733 | { 734 | printf("ERROR: Source ROM is encrypted. Please provide a valid key to decrypt."); 735 | } 736 | else 737 | { 738 | printf("ERROR: Unable to load source ROM at: %s\n", rom_input_path); 739 | printf("Is it a valid ROM?\n"); 740 | } 741 | 742 | if(input_rom.rom_data != NULL) 743 | { 744 | DestroyInitializedAmigaROM(&input_rom); 745 | } 746 | 747 | return 1; 748 | } 749 | 750 | if(input_rom.version == NULL) 751 | { 752 | printf("WARNING: Unknown source ROM loaded.\n"); 753 | } 754 | else 755 | { 756 | printf("Detected source ROM: %s\n", input_rom.version); 757 | } 758 | 759 | if(input_rom.is_encrypted && input_rom.successfully_decrypted && !encryption_state) 760 | { 761 | { 762 | printf("Decrypted ROM.\n"); 763 | } 764 | } 765 | 766 | if(encryption_state) 767 | { 768 | if(input_rom.is_encrypted) 769 | { 770 | DestroyInitializedAmigaROM(&input_rom); 771 | printf("ERROR: Encrypting with the same key used to decrypt the ROM.\n"); 772 | return 1; 773 | } 774 | 775 | if(!CryptAmigaROM(&input_rom, true, encryption_key_path)) 776 | { 777 | DestroyInitializedAmigaROM(&input_rom); 778 | printf("ERROR: Unable to access ROM encryption key.\n"); 779 | return 1; 780 | } 781 | else 782 | { 783 | printf("Encrypted ROM.\n"); 784 | input_rom.rom_size = encrypted_input_rom_size; 785 | } 786 | } 787 | 788 | if(!WriteAmigaROM(&input_rom, rom_output_path)) 789 | { 790 | DestroyInitializedAmigaROM(&input_rom); 791 | 792 | if(encryption_state) 793 | { 794 | printf("ERROR: Unable to write encrypted ROM to disk.\n"); 795 | } 796 | else 797 | { 798 | printf("ERROR: Unable to write decrypted ROM to disk.\n"); 799 | } 800 | 801 | return 1; 802 | } 803 | 804 | DestroyInitializedAmigaROM(&input_rom); 805 | if(encryption_state) 806 | { 807 | printf("Successfully wrote encrypted ROM.\n"); 808 | } 809 | else 810 | { 811 | printf("Successfully wrote decrypted ROM.\n"); 812 | } 813 | 814 | return 0; 815 | } 816 | 817 | int checksum_rom(const bool correct_checksum, const char* encryption_key_path, const char* rom_input_path, const char* rom_output_path) 818 | { 819 | ParsedAmigaROMData input_rom; 820 | 821 | input_rom = ReadAmigaROM(rom_input_path, encryption_key_path); 822 | if(!input_rom.parsed_rom) 823 | { 824 | if(input_rom.is_encrypted && !input_rom.can_decrypt) 825 | { 826 | printf("ERROR: Source ROM is encrypted. Please provide a valid key to decrypt."); 827 | } 828 | else 829 | { 830 | printf("ERROR: Unable to load source ROM at: %s\n", rom_input_path); 831 | printf("Is it a valid ROM?\n"); 832 | } 833 | 834 | if(input_rom.rom_data != NULL) 835 | { 836 | DestroyInitializedAmigaROM(&input_rom); 837 | } 838 | 839 | return 1; 840 | } 841 | 842 | if(input_rom.version == NULL) 843 | { 844 | printf("WARNING: Unknown source ROM loaded.\n"); 845 | } 846 | else 847 | { 848 | printf("Detected source ROM: %s\n", input_rom.version); 849 | } 850 | 851 | if(input_rom.has_valid_checksum) 852 | { 853 | printf("ROM checksum is valid.\n"); 854 | } 855 | else 856 | { 857 | if(correct_checksum) 858 | { 859 | if(CorrectAmigaROMChecksum(&input_rom)) 860 | { 861 | printf("Corrected ROM checksum.\n"); 862 | 863 | if(!WriteAmigaROM(&input_rom, rom_output_path)) 864 | { 865 | DestroyInitializedAmigaROM(&input_rom); 866 | printf("ERROR: Unable to write corrected ROM to disk.\n"); 867 | return 1; 868 | } 869 | 870 | printf("Successfully wrote corrected ROM.\n"); 871 | } 872 | else 873 | { 874 | DestroyInitializedAmigaROM(&input_rom); 875 | printf("ERROR: Unable to correct ROM checksum.\n"); 876 | return 1; 877 | } 878 | } 879 | else 880 | { 881 | DestroyInitializedAmigaROM(&input_rom); 882 | printf("ERROR: ROM checksum is invalid.\n"); 883 | return 1; 884 | } 885 | } 886 | 887 | DestroyInitializedAmigaROM(&input_rom); 888 | 889 | return 0; 890 | } 891 | -------------------------------------------------------------------------------- /teeny-sha1.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Teeny SHA-1 3 | * 4 | * The below sha1digest() calculates a SHA-1 hash value for a 5 | * specified data buffer and generates a hex representation of the 6 | * result. This implementation is a re-forming of the SHA-1 code at 7 | * https://github.com/jinqiangshou/EncryptionLibrary. 8 | * 9 | * Copyright (c) 2017 CTrabant 10 | * 11 | * License: MIT, see included LICENSE file for details. 12 | * 13 | * To use the sha1digest() function either copy it into an existing 14 | * project source code file or include this file in a project and put 15 | * the declaration (example below) in the sources files where needed. 16 | ******************************************************************************/ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /* Declaration: 24 | extern int sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databytes); 25 | */ 26 | 27 | /******************************************************************************* 28 | * sha1digest: https://github.com/CTrabant/teeny-sha1 29 | * 30 | * Calculate the SHA-1 value for supplied data buffer and generate a 31 | * text representation in hexadecimal. 32 | * 33 | * Based on https://github.com/jinqiangshou/EncryptionLibrary, credit 34 | * goes to @jinqiangshou, all new bugs are mine. 35 | * 36 | * @input: 37 | * data -- data to be hashed 38 | * databytes -- bytes in data buffer to be hashed 39 | * 40 | * @output: 41 | * digest -- the result, MUST be at least 20 bytes 42 | * hexdigest -- the result in hex, MUST be at least 41 bytes 43 | * 44 | * At least one of the output buffers must be supplied. The other, if not 45 | * desired, may be set to NULL. 46 | * 47 | * @return: 0 on success and non-zero on error. 48 | ******************************************************************************/ 49 | int sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databytes); 50 | 51 | int 52 | sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databytes) 53 | { 54 | #define SHA1ROTATELEFT(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 55 | 56 | uint32_t W[80]; 57 | uint32_t H[] = {0x67452301, 58 | 0xEFCDAB89, 59 | 0x98BADCFE, 60 | 0x10325476, 61 | 0xC3D2E1F0}; 62 | uint32_t a; 63 | uint32_t b; 64 | uint32_t c; 65 | uint32_t d; 66 | uint32_t e; 67 | uint32_t f = 0; 68 | uint32_t k = 0; 69 | 70 | uint32_t idx; 71 | uint32_t lidx; 72 | uint32_t widx; 73 | uint32_t didx = 0; 74 | 75 | int32_t wcount; 76 | uint32_t temp; 77 | uint64_t databits = ((uint64_t)databytes) * 8; 78 | uint32_t loopcount = (uint32_t)((databytes + 8) / 64 + 1); 79 | uint32_t tailbytes = (uint32_t)(64 * loopcount - databytes); 80 | uint8_t datatail[128] = {0}; 81 | 82 | if (!digest && !hexdigest) 83 | return -1; 84 | 85 | if (!data) 86 | return -1; 87 | 88 | /* Pre-processing of data tail (includes padding to fill out 512-bit chunk): 89 | Add bit '1' to end of message (big-endian) 90 | Add 64-bit message length in bits at very end (big-endian) */ 91 | datatail[0] = 0x80; 92 | datatail[tailbytes - 8] = (uint8_t) (databits >> 56 & 0xFF); 93 | datatail[tailbytes - 7] = (uint8_t) (databits >> 48 & 0xFF); 94 | datatail[tailbytes - 6] = (uint8_t) (databits >> 40 & 0xFF); 95 | datatail[tailbytes - 5] = (uint8_t) (databits >> 32 & 0xFF); 96 | datatail[tailbytes - 4] = (uint8_t) (databits >> 24 & 0xFF); 97 | datatail[tailbytes - 3] = (uint8_t) (databits >> 16 & 0xFF); 98 | datatail[tailbytes - 2] = (uint8_t) (databits >> 8 & 0xFF); 99 | datatail[tailbytes - 1] = (uint8_t) (databits >> 0 & 0xFF); 100 | 101 | /* Process each 512-bit chunk */ 102 | for (lidx = 0; lidx < loopcount; lidx++) 103 | { 104 | /* Compute all elements in W */ 105 | memset (W, 0, 80 * sizeof (uint32_t)); 106 | 107 | /* Break 512-bit chunk into sixteen 32-bit, big endian words */ 108 | for (widx = 0; widx <= 15; widx++) 109 | { 110 | wcount = 24; 111 | 112 | /* Copy byte-per byte from specified buffer */ 113 | while (didx < databytes && wcount >= 0) 114 | { 115 | W[widx] += (((uint32_t)data[didx]) << wcount); 116 | didx++; 117 | wcount -= 8; 118 | } 119 | /* Fill out W with padding as needed */ 120 | while (wcount >= 0) 121 | { 122 | W[widx] += (((uint32_t)datatail[didx - databytes]) << wcount); 123 | didx++; 124 | wcount -= 8; 125 | } 126 | } 127 | 128 | /* Extend the sixteen 32-bit words into eighty 32-bit words, with potential optimization from: 129 | "Improving the Performance of the Secure Hash Algorithm (SHA-1)" by Max Locktyukhin */ 130 | for (widx = 16; widx <= 31; widx++) 131 | { 132 | W[widx] = SHA1ROTATELEFT ((W[widx - 3] ^ W[widx - 8] ^ W[widx - 14] ^ W[widx - 16]), 1); 133 | } 134 | for (widx = 32; widx <= 79; widx++) 135 | { 136 | W[widx] = SHA1ROTATELEFT ((W[widx - 6] ^ W[widx - 16] ^ W[widx - 28] ^ W[widx - 32]), 2); 137 | } 138 | 139 | /* Main loop */ 140 | a = H[0]; 141 | b = H[1]; 142 | c = H[2]; 143 | d = H[3]; 144 | e = H[4]; 145 | 146 | for (idx = 0; idx <= 79; idx++) 147 | { 148 | if (idx <= 19) 149 | { 150 | f = (b & c) | ((~b) & d); 151 | k = 0x5A827999; 152 | } 153 | else if (idx >= 20 && idx <= 39) 154 | { 155 | f = b ^ c ^ d; 156 | k = 0x6ED9EBA1; 157 | } 158 | else if (idx >= 40 && idx <= 59) 159 | { 160 | f = (b & c) | (b & d) | (c & d); 161 | k = 0x8F1BBCDC; 162 | } 163 | else if (idx >= 60 && idx <= 79) 164 | { 165 | f = b ^ c ^ d; 166 | k = 0xCA62C1D6; 167 | } 168 | temp = SHA1ROTATELEFT (a, 5) + f + e + k + W[idx]; 169 | e = d; 170 | d = c; 171 | c = SHA1ROTATELEFT (b, 30); 172 | b = a; 173 | a = temp; 174 | } 175 | 176 | H[0] += a; 177 | H[1] += b; 178 | H[2] += c; 179 | H[3] += d; 180 | H[4] += e; 181 | } 182 | 183 | /* Store binary digest in supplied buffer */ 184 | if (digest) 185 | { 186 | for (idx = 0; idx < 5; idx++) 187 | { 188 | digest[idx * 4 + 0] = (uint8_t) (H[idx] >> 24); 189 | digest[idx * 4 + 1] = (uint8_t) (H[idx] >> 16); 190 | digest[idx * 4 + 2] = (uint8_t) (H[idx] >> 8); 191 | digest[idx * 4 + 3] = (uint8_t) (H[idx]); 192 | } 193 | } 194 | 195 | /* Store hex version of digest in supplied buffer */ 196 | if (hexdigest) 197 | { 198 | snprintf (hexdigest, 41, "%08x%08x%08x%08x%08x", 199 | H[0],H[1],H[2],H[3],H[4]); 200 | } 201 | 202 | return 0; 203 | } /* End of sha1digest() */ 204 | --------------------------------------------------------------------------------