├── .gitattributes ├── .github └── workflows │ ├── test-build-lnx.yml │ ├── test-build-osx.yml │ └── test-build-win.yml ├── .gitignore ├── .gitmodules ├── .vscode └── extensions.json ├── CONFIG.md ├── LICENSE ├── Makefile ├── README.md ├── README_org.md ├── STM32F411duino-bootloader.code-workspace ├── build ├── stm32f401xe_0x2000 │ ├── firmware.hex │ └── firmware.map ├── stm32f401xe_0x4000 │ ├── firmware.hex │ └── firmware.map ├── stm32f411xe_0x2000 │ ├── firmware.hex │ └── firmware.map └── stm32f411xe_0x4000 │ ├── firmware.hex │ └── firmware.map ├── config.h ├── examples └── hello_world │ ├── .gitignore │ ├── .vscode │ └── extensions.json │ ├── hello_world.code-workspace │ ├── include │ └── README │ ├── lib │ └── README │ ├── pio-tools │ ├── custom_board.py │ ├── dfu-upload.py │ └── dfu-upload.sh │ ├── platformio.ini │ ├── src │ └── main.cpp │ └── test │ └── README ├── flow.md ├── inc ├── arc4.h ├── blowfish.h ├── bootloader.h ├── chacha.h ├── chacha_a.h ├── checksum.h ├── crypto.h ├── descriptors.h ├── flash.h ├── getopt.h ├── gost.h ├── magma.h ├── misc.h ├── raiden.h ├── rc5.h ├── rc5_a.h ├── rc6.h ├── rc6a.h ├── rijndael.h ├── rtea.h ├── speck.h ├── usb_msft.h ├── xtea.h └── xtea1.h ├── ldscript.mk ├── matrix ├── matrix_stm32f070xb.md ├── matrix_stm32f103x8.md ├── matrix_stm32f303xe.md ├── matrix_stm32f429xi.md ├── matrix_stm32f446xc.md ├── matrix_stm32g474xb.md ├── matrix_stm32l052x8.md ├── matrix_stm32l100xc.md ├── matrix_stm32l433xc.md └── matrix_stm32l476xe.md ├── mcu ├── stm32f0xx.S ├── stm32f103.S ├── stm32f105.S ├── stm32f303.S ├── stm32f4xx.S ├── stm32g4xx.S ├── stm32l0xx.S ├── stm32l1xx.S └── stm32l4xx.S ├── platformio.ini ├── scripts ├── both.sh ├── build.sh └── download.sh ├── src ├── arc4.c ├── blowfish.c ├── bootloader.c ├── chacha.c ├── chacha_a.S ├── checksum.c ├── crypto.c ├── ctest.c ├── descriptors.c ├── encrypter.c ├── gost.c ├── magma.c ├── raiden.c ├── rc5.c ├── rc5a.S ├── rc6.c ├── rc6a.S ├── rijndael.c ├── rtea.c ├── speck.c ├── xtea.c └── xtea1.c └── userconfig-example.h /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/workflows/test-build-lnx.yml: -------------------------------------------------------------------------------- 1 | name: LNX build 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | paths-ignore: 7 | - '**.md' 8 | push: 9 | branches: 10 | - master 11 | paths-ignore: 12 | - '**.md' 13 | 14 | jobs: 15 | build: 16 | name: Linux 17 | env: 18 | CMSIS: CMSIS_5 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: ARM GCC setup 22 | uses: fiam/arm-none-eabi-gcc@v1 23 | with: 24 | release: 8-2019-q3 25 | - name: Checkout 26 | uses: actions/checkout@v2 27 | - name: Resolve prerequisites 28 | run: make prerequisites 29 | - name: Build firmware 30 | run: make stm32f103x8 31 | - name: Build encrypter 32 | run: make crypter 33 | - name: Build testsuite 34 | run: make testsuite 35 | - name: Vector test 36 | run: build/cipher_test 37 | -------------------------------------------------------------------------------- /.github/workflows/test-build-osx.yml: -------------------------------------------------------------------------------- 1 | name: OSX build 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | paths-ignore: 7 | - '**.md' 8 | push: 9 | branches: 10 | - master 11 | paths-ignore: 12 | - '**.md' 13 | 14 | jobs: 15 | build: 16 | name: OSX 17 | env: 18 | CMSIS: CMSIS_5 19 | runs-on: macos-latest 20 | steps: 21 | - name: ARM GCC setup 22 | uses: fiam/arm-none-eabi-gcc@v1 23 | with: 24 | release: 8-2019-q3 25 | - name: Checkout 26 | uses: actions/checkout@v2 27 | - name: Update make 28 | run: brew install make 29 | - name: Resolve prerequisites 30 | run: gmake prerequisites 31 | - name: Build firmware 32 | run: gmake stm32f103x8 33 | - name: Build encrypter 34 | run: gmake crypter 35 | - name: Build testsuite 36 | run: gmake testsuite 37 | - name: Vector test 38 | run: build/cipher_test 39 | -------------------------------------------------------------------------------- /.github/workflows/test-build-win.yml: -------------------------------------------------------------------------------- 1 | name: WIN build 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | paths-ignore: 7 | - '**.md' 8 | push: 9 | branches: 10 | - master 11 | paths-ignore: 12 | - '**.md' 13 | 14 | jobs: 15 | build: 16 | name: Windows 17 | env: 18 | CMSIS: CMSIS_5 19 | runs-on: windows-latest 20 | steps: 21 | - name: ARM GCC setup 22 | uses: fiam/arm-none-eabi-gcc@v1 23 | with: 24 | release: 8-2019-q3 25 | - name: Checkout 26 | uses: actions/checkout@v2 27 | - name: Resolve prerequisites 28 | run: make prerequisites 29 | - name: Build firmware 30 | run: make stm32f103x8 SHELL=cmd 31 | - name: Build encrypter 32 | run: make crypter SHELL=cmd SWTOOLS= 33 | - name: Build testsuite 34 | run: make testsuite SHELL=cmd SWTOOLS= 35 | - name: Vector test 36 | run: build/cipher_test 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #user files 2 | userconfig.h 3 | 4 | #working subdirs 5 | obj/* 6 | bin/* 7 | build/* 8 | 9 | #EmBitz project files 10 | *.depend 11 | *.ebp 12 | *.elay 13 | 14 | #OpenOCD configuration 15 | openocd.cfg 16 | 17 | #sublime project files 18 | *.sublime-project 19 | *.sublime-workspace 20 | 21 | # Prerequisites 22 | *.d 23 | 24 | # Compiled Object files 25 | *.slo 26 | *.lo 27 | *.o 28 | *.obj 29 | 30 | # Precompiled Headers 31 | *.gch 32 | *.pch 33 | 34 | # Compiled Dynamic libraries 35 | *.so 36 | *.dylib 37 | *.dll 38 | 39 | # Fortran module files 40 | *.mod 41 | *.smod 42 | 43 | # Compiled Static libraries 44 | *.lai 45 | *.la 46 | *.a 47 | *.lib 48 | 49 | # PlatformIO 50 | .pio 51 | 52 | # Visual Studio Code 53 | .vscode/.browse.c_cpp.db* 54 | .vscode/c_cpp_properties.json 55 | .vscode/launch.json 56 | .vscode/ipch 57 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libusb_stm32"] 2 | path = usb 3 | url = http://github.com/dmitrystu/libusb_stm32.git 4 | branch = master 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ], 7 | "unwantedRecommendations": [ 8 | "ms-vscode.cpptools-extension-pack" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /CONFIG.md: -------------------------------------------------------------------------------- 1 | ## Configuring bootloader 2 | The bootloader can be configured by overriding defaults through parameters passed to make. 3 | + Use external file to override default settings 4 | ``` 5 | make DFU_USER_CONFIG=userconfig.h 6 | ``` 7 | + Override settings directly 8 | ``` 9 | make DFU_BOOTSTRAP_PIN=2 DFU_CIPHER=DFU_CIPHER_XTEA DFU_VERIFY_CHECKSUM=FNV1A64 10 | ``` 11 | You can find configuration parameters in the following tables. Defaults marked **bold**. 12 | 13 | 14 | ### Table 1. Generic config 15 | |Parameter | Description | Values/Types | Notes | 16 | |--------------------|-------------------------------------|--------------------------------|-------------------------| 17 | |DFU_USER_CONFIG | Defines file with overrides | filename | **not defined** 18 | |DFU_DNLOAD_NOSYNC | Disables DFU SYNC state | **_ENABLE**/_DISABLE | | 19 | |DFU_INTF_EEPROM | Enables EEPROM interface | _ENABLE/_DISABLE/**_AUTO** | | 20 | |DFU_CAN_UPLOAD | Enables uploads from device | **_ENABLE**/_DISABLE | | 21 | |DFU_DETACH | Enables DFU_DETACH command | **_ENABLE**/_DISABLE | Issues RESET on detach | 22 | |DFU_VERIFY_CHECKSUM | Enables checksum verification | See Table 2 | **_DISABLE** | 23 | |DFU_VENDOR_ID | USB Device VID | UINT16 | **0x0483** | 24 | |DFU_DEVICE_ID | USB Device DID | UINT16 | **0xDF11** | 25 | |DFU_STR_MANUF | USB Device manufacturer string | ASCII/UTF-16 | **"Your company name"** | 26 | |DFU_STR_PRODUCT | USB Device product string | ASCII/UTF-16 | **"Secure bootloader"** | 27 | |DFU_DSC_CONFIG | Enables Device configuration string | _ENABLE/**_DISABLE** | | 28 | |DFU_STR_CONFIG | Device configuration string | ASCII/UTF-16 | **"DFU"** | 29 | |DFU_DSC_FLASH | Enables flash interface string | **_ENABLE**/_DISABLE | | 30 | |DFU_STR_FLASH | Flash interface string | ASCII/UTF-16 | **"Internal flash"** | 31 | |DFU_DSC_EEPROM | Enables EEPROM interface string | **_ENABLE**/_DISABLE | | 32 | |DFU_STR_EEPROM | EEPROM interface string | ASCII/UTF-16 | **"Internal EEPROM"** | 33 | |DFU_POLL_TIMEOUT | DFU poll time (ms) | > 0 | **20** | 34 | |DFU_DETACH_TIMEOUT | DFU detach timeout (ms) | > 0 | **200** | 35 | |DFU_BLOCKSZ | DFU block size (bytes) | must fit cipher block size | **0x80** | 36 | |DFU_BOOTKEY | DFU bootkey value | UINT32 | **0x157F32D4** | 37 | |DFU_BOOTKEY_ADDR | Address of the bootkey in RAM | RAM ADDRESS/_DISABLE/**_AUTO** | **on the top of stack** | 38 | |DFU_BOOTSTRAP_GPIO | DFU bootstrap port | GPIOx/_DISABLE | **GPIOA** | 39 | |DFU_BOOTSTRAP_PIN | DFU bootstarp pin | 0-15 | **1** | 40 | |DFU_BOOTSTRAP_LEVEL | Level on bootstrap pin to activate | **_LOW**/_HIGH | | 41 | |DFU_BOOTSTRAP_PULL | Bootstrap pin pullup control | _DISABLE/**_AUTO**/_LOW/_HIGH | | 42 | |DFU_DBLRESET_MS | Doublereset activation time (ms) | TIMEOUT/_DISABLE | **300** | 43 | |DFU_APP_START | Start address for user code | ROM ADDRESS/**_AUTO** | must be page aligned | 44 | |DFU_APP_SIZE | User application max size | AMOUNT/**_AUTO** | up to the ROM end | 45 | |DFU_WCID | Enables Microsoft OS Descriptors | _ENABLE/**_DISABLE** | Aut. Win. driver assign.| 46 | |DFU_CIPHER | Type of ciper | See Table 3 | **DFU_CIPHER_RC5** | 47 | |DFU_CIPHER_MODE | Cipher mode of operation | See Table 4 | **DFU_CIPHER_CBC** | 48 | |DFU_AES_KEY_128 | 128-bit cipher key | Comma separated bytes | | 49 | |DFU_AES_KEY_256 | 256-bit cipher key | Comma separated bytes | | 50 | |DFU_AES_IV_64 | 64-bit cipher IV | Comma separated bytes | | 51 | |DFU_AES_IV_96 | 96-bit cipher IV | Comma separated bytes | Used for the CHACHA | 52 | |DFU_AES_IV_128 | 128-bit cipher IV | Comma separated bytes | | 53 | 54 | ### Table 2. Available Checksums 55 | *Note:* Firmware checksum will be checked on every startup. Bootloader will be activated if no correct firmware found. It may take a lot of time. 56 | |Checksum | Description | 57 | |-----------|-------------------------------------------------------------------------------| 58 | |_DISABLE | Disable firmware verification | 59 | |CRC32FAST | Lookup table based crc32 algorithm, consumes 1Kb of RAM for the table | 60 | |CRC32SMALL | Permutation based crc32 algorithm, no lookup table required but slower | 61 | |FNV1A32 | Fowler–Noll–Vo 32 bit Hash | 62 | |FNV1A64 | Fowler–Noll–Vo 64 bit Hash | 63 | |CRC64FAST | Lookup table based crc64 algorithm, consumes 2Kb of RAM for the table | 64 | |CRC64SMALL | Permutation based crc64 algorithm, no lookup table required but extremly slow | 65 | 66 | 67 | ### Table 3. Available Ciphers 68 | |Cipher Type/Mode | Description | Block size | Key Size | IV size | Notes | 69 | |--------------------|------------------------------|------------|----------|---------|--------------------------| 70 | |_DISABLE | Disable encryption | | | | | 71 | |DFU_CIPHER_ARC4 | Rivest RC-4 | Stream | 128 | N/A | Unsafe | 72 | |DFU_CIPHER_CHACHA | RFC7539-CHACHA20 | Stream | 256 | 96 | | 73 | |DFU_CIPHER_CHACHA_A | RFC7539-CHACHA20 | Stream | 256 | 96 | THUMB ASM version | 74 | |DFU_CIPHER_GOST | GOST R 34.12-2015 MAGMA | 64 | 256 | 64 | treat data as LE64 | 75 | |DFU_CIPHER_MAGMA | GOST R 34.12-2015 MAGMA | 64 | 256 | 64 | | 76 | |DFU_CIPHER_RAIDEN | RAIDEN | 64 | 128 | 64 | | 77 | |DFU_CIPHER_RC5 | Rivest RC5-32/12/128 | 64 | 128 | 64 | | 78 | |DFU_CIPHER_RC5_A | Rivest RC5-32/12/128 | 64 | 128 | 64 | THUMB ASM version | 79 | |DFU_CIPHER_SPECK | SPECK 64/128 | 64 | 128 | 64 | | 80 | |DFU_CIPHER_XTEA | XTEA | 64 | 128 | 64 | treat data as LE32 | 81 | |DFU_CIPHER_XTEA1 | XTEA-1 | 64 | 128 | 64 | treat data as LE32 | 82 | |DFU_CIPHER_BLOWFISH | Blowfish | 64 | 256 | 64 | Uses xorshift instead PI | 83 | |DFU_CIPHER_RTEA | Ruptor's TEA or Repaired TEA | 64 | 256 | 64 | | 84 | |DFU_CIPHER_RC6 | Rivest RC6-32/20/16 | 128 | 128 | 128 | | 85 | |DFU_CIPHER_RC6_A | Rivest RC6-32/20/16 | 128 | 128 | 128 | THUMB ASM verison | 86 | |DFU_CIPHER_RIJNDAEL | Rijndael AES-128/192/256 | 128 | 128 | 128 | 128-bit key by default | 87 | 88 | ### Table 4. Available Block Cipher Modes of Operation 89 | |Cipher mode | Description | 90 | |----------------|------------------------------------------| 91 | |DFU_CIPHER_ECB | Electronic Codebook (ECB) | 92 | |DFU_CIPHER_CBC | Cipher Block Chaining (CBC) | 93 | |DFU_CIPHER_PCBC | Propagating Cipher Block Chaining (PCBC) | 94 | |DFU_CIPHER_CFB | Cipher Feedback (CFB) | 95 | |DFU_CIPHER_OFB | Output Feedback (OFB) | 96 | |DFU_CIPHER_CTR | Counter (CTR) (simply IV increment) | 97 | 98 | 99 | ### WCID 100 | DFU_WCID can be enabled to obtain a Microsoft-defined mechanism called WCID which is used by Windows to automatically assign a USB driver upon device connection. You probably want this as it enhances Windows user experience massively. See https://github.com/pbatard/libwdi/wiki/WCID-Devices 101 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | First things first: Don't forget to read the original [README.md](README_org.md) of the parent project. 2 | 3 | # Secure STM32duino-compatible USB DFU1.1 bootloader for STM32F401(xE) and STM32F411(xE) (Blackpill) 4 | This is a fork of [dmitrystu's](https://github.com/dmitrystu/) great [sboot_stm32](https://github.com/dmitrystu/sboot_stm32) bootloader, which is a beautiful piece of software, with a few modifications to make it act similarly like [rogerclarkmelbourne's](https://github.com/rogerclarkmelbourne/) [STM32duino-bootloader](https://github.com/rogerclarkmelbourne/STM32duino-bootloader), adapt the nifty little RTC magic number feature from [Serasidis'](https://github.com/Serasidis/) [STM32 HID-Bootloader](https://github.com/Serasidis/STM32_HID_Bootloader), and thus provide better compatiblity to the [STM32duino Arduino Core](https://github.com/stm32duino/Arduino_Core_STM32) - especially when developing with [PlatformIO](https://docs.platformio.org/en/latest/integration/ide/vscode.html) and VSCode. 5 | 6 | ## So why all this? 7 | For downloading firmwares to your Blackpill via USB you can simply do the little finger dance and you're fine... kind of... unless you're some lazy dude like me, who doesn't want to do the extra [equilibristics](https://en.wiktionary.org/wiki/equilibristics) to fiddle around with the board all the time while coding. Having a pretty weak pull-down connected to BOOT1 with a far higher resistance than my thick clumsy fingers doesn't help neither. 8 | 9 | Since the STM32F103 doesn't have a USB-capable bootloader in ROM, [Roger](https://github.com/rogerclarkmelbourne/) wrote the [STM32duino-bootloader](https://github.com/rogerclarkmelbourne/STM32duino-bootloader) for the Bluepill and [ST-Link Baite-Clones](https://www.google.com/search?q=STink+bait), which always starts up after resetting the board and then proceeds to the user application after a short timeout. This way the host can toggle the DTR "pin" of the USB-serial which is detected by the [STM32duino Arduino Core](https://github.com/stm32duino/Arduino_Core_STM32) and triggers a reset of the board like the [Maple](https://www.leaflabs.com/maple) boards first implemented this. 10 | 11 | The beforementioned [HID Bootloader](https://github.com/Serasidis/STM32_HID_Bootloader), which is [only partly supported](https://docs.platformio.org/en/stable/boards/ststm32/blackpill_f411ce.html#uploading) by PlatformIO's [ST STM32-platform](https://docs.platformio.org/en/stable/platforms/ststm32.html), and [Roger's](https://github.com/rogerclarkmelbourne/) [STM32duino-bootloader](https://github.com/rogerclarkmelbourne/STM32duino-bootloader) additionally implement [checking a register of the RTC's backup domain](https://github.com/rogerclarkmelbourne/STM32duino-bootloader/blob/master/hardware.c#L241) to determine whether the bootloader should be [force-entered](https://github.com/Serasidis/STM32_HID_Bootloader/blob/master/bootloader/F4/Src/main.c#L136) or [skipped completely](https://github.com/rogerclarkmelbourne/STM32duino-bootloader/blob/master/main.c#L49) after the reset, which can be controlled by the user application and is also reflected in the [STM32duino Arduino Core](https://github.com/stm32duino/Arduino_Core_STM32). See its [bootloader.c](https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/SrcWrapper/src/stm32/bootloader.c) for more details. 12 | 13 | To complete the whole and round it nicely [WeAct](https://github.com/WeActStudio/) especially made their [HID Bootloader](https://github.com/WeActStudio/WeAct_HID_Bootloader_F4x1) incompatible with [Serasidis'](https://github.com/Serasidis/) [STM32 HID-Bootloader](https://github.com/Serasidis/STM32_HID_Bootloader) from which it was forked and their Blackpills are usually shipped with. Yay! [I'm lovin' it!](https://www.youtube.com/watch?v=tfhlEP8LT4k) 14 | 15 | ## Bringing it all together 16 | So what would be nice is a standard dfu-capable bootloader that can easily be entered automatically using your development IDE and is supported by the standard STM32-Arduino Framework. 17 | So here you go! 18 | 19 | ### This bootloader implements 20 | + The DFU protocol (sboot) 21 | + Application offsets 0x2000 and 0x4000 in flash 22 | (it can actually be quite tiny depending on the selected features) 23 | + Automatically entering the bootloader after power-on (STM32duino-bootloader) 24 | + Entering the bootloader by double-clicking the reset-button (sboot) 25 | + Entering the bootloader by holding down a user-button (all) 26 | + Force-entering the bootloader when no firmware is detected (STM32duino-bootloader) 27 | + Force-entering or force-skipping the bootloader by 28 | + RTC magic number (HID/STM32duino Bootloader) or 29 | + magic number in SRAM (sboot) 30 | + Automatically exiting the bootloader and running the firmware after various configurable timeouts 31 | + Encrypted firmware downloads (sboot) 32 | + Verifying the checksum of the firmware (sboot) 33 | + A nervously flashing LED while in bootloader 34 | + Each of the features above can be enabled/disabled separately 35 | Not all combinations make sense! You choose! ([userconfig.h](https://github.com/rbm78bln/STM32duino-bootloader_stm32f411-blackpill/blob/master/userconfig-example.h)) 36 | 37 | ### Supported MCU targets 38 | 39 | | mcu_target | MCU | remarks | 40 | |---------------|-------------|---------| 41 | | stm32f401xe | STM32F401xE | tested | 42 | | stm32f411xe | STM32F411xE | tested | 43 | 44 | ### This bootloader does not (yet?) implement 45 | + ST-DfuSe extensions 46 | + STM32F103 MCU targets (Bluepills, [Baite-STLinks](https://www.google.com/search?q=STink+bait)) 47 | + Being badly incompatible to everything else ([WeAct HID-Bootloader](https://github.com/WeActStudio/WeAct_HID_Bootloader_F4x1)) 48 | 49 | ## Activating the bootloader 50 | + Simply just power up your board 51 | + Toggle the DTR "pin" of the USB-serial interface 52 | + Write RTC_MAGIC_NUMBER_BOOTLOADER into register 4 of the RTC backup domain (RTC->BKP4R) and issue a (whatever) reset 53 | + Write DFU_BOOTKEY at DFU_BOOTKEY_ADDR (RAM top by default) and make a software reset 54 | + Assert DFU_BOOTSTRAP_PIN on DFU_BOOTSTRAP_PORT on startup 55 | + Make a double reset during the DFU_DBLRESET_MS period 56 | + Overwrite the first four bytes of your user firmware 57 | 58 | ## Using the bootloader 59 | In [```examples/hello_world```](examples/hello_world) you can find a very basic example on how to use this bootloader for your daily work with [PlatformIO](https://docs.platformio.org/en/latest/integration/ide/vscode.html) and VSCode. 60 |
61 | 62 | #### How can I use this bootloader with Arduino IDE? 63 | What is [Arduino IDE](https://github.com/arduino/arduino-ide)? 64 |
65 | 66 | ![sboot_stm32f411](https://miunske.eu/github/?sboot_stm32f411) 67 | -------------------------------------------------------------------------------- /README_org.md: -------------------------------------------------------------------------------- 1 | ![LNX build](https://github.com/dmitrystu/sboot_stm32/workflows/LNX%20build/badge.svg) 2 | ![WIN build](https://github.com/dmitrystu/sboot_stm32/workflows/WIN%20build/badge.svg) 3 | ![OSX build](https://github.com/dmitrystu/sboot_stm32/workflows/OSX%20build/badge.svg) 4 | ### Secure USB DFU1.1 bootloader for STM32 5 | #### Features 6 | + Small size. Fits in 4K ROM segment (ASM or no encryption, otherwise a bit more). 7 | + USB DFU1.1 compatible 8 | + Supported by [dfu-util](http://dfu-util.sourceforge.net/) 9 | + Supported ciphers: 10 | + No encryption 11 | + ARCFOUR stream cipher 12 | + CHACHA20 stream cipher 13 | + RC5-32/12/16 block cipher (C and ASM implementation) 14 | + RC6-32/20/16 block cipher (C and ASM implementation) 15 | + GOST R 34.12-2015 "MAGMA" block cipher 16 | + RAIDEN block cipher 17 | + SPECK 64/128 block cipher 18 | + XTEA (classic and XTEA-1) block cipher 19 | + RTEA block cipher 20 | + BLOWFISH type block cipher 21 | + Rijndael AES-128/192/256 block cipher 22 | + Supported cipher modes for block ciphers: 23 | + Electronic Codebook (ECB) 24 | + Cipher Block Chaining (CBC) 25 | + Propagating CBC (PCBC) 26 | + Cipher Feedback (CFB) 27 | + Output Feedback (OFB) 28 | + Counter (CTR) 29 | + Supported firmware verification methods: 30 | + CRC (CRC32, CRC64) 31 | + Fowler-Noll-Vo (FNV-1A-32, FNV1A-64) 32 | + Separate interfaces for flash and EEPROM programming 33 | + Autoseal using RDP level 1 or 2 (prevents reading decrypted FW trough debug interface). 34 | Be careful when you set RDP to level 2. **This operation is irreversible and disables 35 | all debug functions and option bytes programming.** 36 | + Software for firmware encryption/decryption included 37 | + Supported STM32 families: 38 | + STM32L0x2 39 | + STM32L1xx 40 | + STM32L476xx (OTG FS in device mode) 41 | + STM32F103 42 | + STM32F105, STM32F107 (OTG FS in device mode) 43 | + STM32F0 series 44 | + STM32F3 series 45 | + STM32F4 series 46 | + STM32G4 series 47 | 48 | #### Generic flow 49 | 50 | ![Generic Flow](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVERcbiAgICBzdGFydChbUkVTRVRdKVxuICAgIGdvYXBwKFtBY3RpdmF0ZSBhcHBsaWNhdGlvbl0pXG4gICAgZ29ib290KFtBY3RpdmF0ZSBib290bG9hZGVyXSlcbiAgICBib290a2V5MXt7Ym9vdGtleSBtYXRjaCBpbnZlcnRlZD99fVxuICAgIGJvb3RrZXkye3tib290a2V5IG1hdGNoIG9uIHN0YXJ0P319XG4gICAgd2FpdChTZXQgYm9vdGtleSBhbmQgd2FpdCBzb21lIHRpbWUpXG4gICAgY2xyYm9vdGtleVtDbGVhciBib290a2V5XVxuICAgIHNldGNsb2NrW1NldHVwIFJDQ11cbiAgICBjaGVja3BpbihTZXR1cCBhbmQgY2hlY2sgcGluKVxuICAgIHNldHJlZ3NbU2V0dXAgTVNQIGFuZCBWVE9SXVxuICAgIGNzdmVyaWZ5KFZlcmlmeSBhcHBsaWNhdGlvbiBzaWduYXR1cmUpXG4gICAgc2V0aW52Ym9vdGtleVtTZXQgaW52ZXJ0ZWQgYm9vdGtleV1cblxuICAgIHN0YXJ0LS0-Ym9vdGtleTFcbiAgICBib290a2V5MS0tWWVzLS0-c2V0cmVnc1xuICAgIHNldHJlZ3MtLT5nb2FwcFxuICAgIGJvb3RrZXkxLS0-d2FpdFxuICAgIHdhaXQtLT5jbHJib290a2V5XG4gICAgY2xyYm9vdGtleS0tPnNldGNsb2NrXG4gICAgd2FpdC0uaGFyZHdhcmUgcmVzZXQuLT5zdGFydFxuICAgIHNldGNsb2NrLS0-Ym9vdGtleTJcbiAgICBib290a2V5Mi0tWWVzLS0-Z29ib290XG4gICAgYm9vdGtleTItLT5jaGVja3BpblxuICAgIGNoZWNrcGluLS1QaW4gYWN0aXZlLS0-Z29ib290XG4gICAgY2hlY2twaW4tLT5jc3ZlcmlmeVxuICAgIGNzdmVyaWZ5LS1Ob3QgbWF0Y2gtLT5nb2Jvb3RcbiAgICBjc3ZlcmlmeS0tPnNldGludmJvb3RrZXlcbiAgICBzZXRpbnZib290a2V5LS5OVklDIHJlc2V0Li0-c3RhcnQiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9LCJ1cGRhdGVFZGl0b3IiOmZhbHNlfQ) 51 | 52 | #### Usage: 53 | 54 | #### Configuring bootloader 55 | The bootloader can be configured through the make parameters. See CONFIG.md for details. 56 | 57 | #### Building bootloader 58 | 1. Prerequisites 59 | + GNU make 60 | + arm-none-eabi-gcc toolchaipren v4.9 or later to build bootloader 61 | + gcc toolchain to build fwcrypt software 62 | + [CMSIS V4](https://github.com/ARM-software/CMSIS) or [CMSIS V5](https://github.com/ARM-software/CMSIS_5). 63 | + Device peripheral access layer header files for STM32. See [Vendor Template](https://github.com/ARM-software/CMSIS/tree/master/Device/_Template_Vendor) for details. 64 | + [stm32.h](https://github.com/dmitrystu/stm32h) STM32 universal header 65 | + optional [st-util](https://github.com/texane/stlink) tool to program bootloader 66 | 2. Makefile targets 67 | + **make prerequisites** to download required libs and headers 68 | + **make mcu_target** to build bootloader 69 | + **make program** to flash bootloader using st-flash 70 | + **make crypter** to build encryption software 71 | 3. Makefile and environmental variables 72 | 73 | | Variable | Default Value | Description | 74 | |----------|-------------------------------------|-------------------------------------| 75 | | CMSIS | CMSIS | path to CMSIS root folder | 76 | | CMSISDEV | $(CMSIS)/Device | path to CMSIS device folder | 77 | | OUTDIR | build | output folder for binaries | 78 | | FWNAME | firmware | name for bootloader binary | 79 | | SWNAME | fwcrypt | name for encrypter binary | 80 | 81 | 4. MCU targets 82 | 83 | | mcu_target | MCU | remarks | 84 | |---------------|----------------------------------------------------|-----------------| 85 | | stm32l100x6a | STM32L100C6-A | | 86 | | stm32l100x8a | STM32L100R8-A | | 87 | | stm32l100xba | STM32L100RB-A | | 88 | | stm32l100xc | STM32L100RC | tested | 89 | | stm32l151x6a | STM32L151C6-A, STM32L151R6-A | | 90 | | stm32l151x8a | STM32L151C8-A, STM32L151R8-A, STM31L151V8-A | | 91 | | stm32l151xba | STM32L151CB-A, STM32L151RB-A, STM31L151VB-A | | 92 | | stm32l151xc | STM32L151CC, STM32L151QC, SRM32L151RC, STM32L151UC | | 93 | | stm32l151xd | STM32L151QD, STM32L151RD, STM32L151VD, STM32L151ZD | | 94 | | stm32l151xe | STM32L151QE, STM32L151RE, STM32L151VE, STM32L151ZE | | 95 | | stm32l152x6a | STM32L152C6-A, STM32L152R6-A | | 96 | | stm32l152x8a | STM32L152C8-A, STM32L152R8-A, STM31L152V8-A | | 97 | | stm32l152xba | STM32L152CB-A, STM32L152RB-A, STM31L152VB-A | | 98 | | stm32l152xc | STM32L152CC, STM32L152QC, SRM32L152RC, STM32L152UC | | 99 | | stm32l152xd | STM32L152QD, STM32L152RD, STM32L152VD, STM32L152ZD | | 100 | | stm32l152xe | STM32L152QE, STM32L152RE, STM32L152VE, STM32L152ZE | | 101 | | stm32l162xc | STM32L162RC, STM32L162VC | | 102 | | stm32l162xd | STM32L162QD, STM32L156RD, STM32L162VD, STM32L162ZD | | 103 | | stm32l162xe | STM32L162QE, STM32L156RE, STM32L162VE, STM32L162ZE | | 104 | | stm32l052x6 | STM32L052K6, STM32L052T6, STM32L052C6, STM32L052R6 | | 105 | | stm32l052x8 | STM32L052K8, STM32L052T8, STM32L052C8, STM32L052R8 | tested, default | 106 | | stm32l053x6 | STM32L053C6, STM32L053R6 | | 107 | | stm32l053x8 | STM32L053C8, STM32L053R8 | | 108 | | stm32l062x8 | STM32L062K8 | | 109 | | stm32l063x8 | STM32L063C8, STM32L063R8 | | 110 | | stm32l072v8 | STM32L072V8 | | 111 | | stm32l072xb | STM32L072KB, STM32L072CB, STM32L072RB, STM32L072VB | tested | 112 | | stm32l072xz | STM32L072KZ, STM32L072CZ, STM32L072RZ, STM32L072VZ | | 113 | | stm32l073v8 | STM32L073V8 | | 114 | | stm32l073xb | STM32L073CB, STM32L073RB, STM32L073VB | | 115 | | stm32l073xz | STM32L073CZ, STM32L073RZ, STM32L073VZ | | 116 | | stm32l476xc | STM32L476RC, STM32L476VC | | 117 | | stm32l476xe | STM32L476RE, STM32L476JE, STM32L476ME, STM32L476VE | | 118 | | stm32l476xg | STM32L476RG, STM32L476JG, STM32L476MG, STM32L476VG | tested | 119 | | stm32f103x6 | STM32F103T6, STM32F103C6, STM32F103R6 | | 120 | | stm32f103x8 | STM32F103T8, STM32F103C8, STM32F103R8, STM32f103V8 | tested | 121 | | stm32f105xb | STM32F105RB, STM32F105VB | tested | 122 | | stm32f107xb | STM32F107RB, STM32F107VB | tested | 123 | | stm32l433xb | STM32L433CB, STM32L433RB | | 124 | | stm32l433xc | STM32L433CC, STM32L433RC, STM32L433VC | tested | 125 | | stm32f070x6 | STM32F070C6 | | 126 | | stm32f070xb | STM32F070CB | tested | 127 | | stm32f429xe | STM32F429xE series (single bank mode) | | 128 | | stm32f429xg | STM32F429xG series (single bank mode) | | 129 | | stm32f429xi | STM32F429xI series (single and dual bank) | tested | 130 | | stm32g431x6 | STM32G431x6, STM32G441x6 | | 131 | | stm32g431x8 | STM32G431x8, STM32G441x8 | | 132 | | stm32g431xb | STM32G431xB, STM32G441xB | tested G431RB | 133 | | stm32g474xb | STM32G471xB, STM32G473xB, STM32G474xB, STM32G483xB | | 134 | | stm32g474xc | STM32G471xC, STM32G473xC, STM32G474xC, STM32G483xC | | 135 | | stm32g474xe | STM32G471xE, STM32G473xE, STM32G474xE, STM32G483xE | tested G747RE | 136 | | stm32f303xe | STM32F303xE | tested | 137 | | stm32f373xc | STM32F373xC | tested | 138 | 139 | #### Adjusting user firmware 140 | + Check bootloader's linker map for the ````__app_start```` address. This is the new ROM origin for the user firmware (ISR vectors). 141 | + Adjust your linker script to set new ROM origin and ROM length. 142 | 143 | #### Utilizing usbd core and usbd driver from bootloader in the user firmware 144 | + Check bootloader's linker map for the ````usbd_poll```` entry point and usbd driver (````usbd_devfs````, ````usbd_otgfs````, e.t.c. depends used MCU). It's located just after the ```.isr_vector``` section. 145 | + Add address for usbd_driver structure to your linker script. For example ````usbd_drv = 0x08000040;```` 146 | + Add address for usbd_poll entry point to your linker script. For example ````usbd_poll = 0x08000074;```` 147 | + Add ````extern struct usbd_driver usbd_drv;```` driver declaration to your code. 148 | + Include at least "usbd_core.h" and "usb_std.h" to your code. 149 | 150 | Now you can use the usbd core and driver from the bootloader in your application. Don't forget to set GPIO and RCC for USB according to MCU requirements. 151 | 152 | #### Activating bootloader 153 | + Write DFU_BOOTKEY at DFU_BOOTKEY_ADDR (RAM top by default) and make a software reset. 154 | + Assert DFU_BOOTSTRAP_PIN on DFU_BOOTSTRAP_PORT on startup (optional). 155 | + Make a double reset during the DFU_DBLRESET_MS period (optional). 156 | 157 | #### Encrypting user firmware 158 | We provide a utility for encryption and decryption of firmware images. At this moment, only raw binary files are supported. 159 | 160 | To encrypt: 161 | ```` 162 | fwcrypt -e -i infile.bin -o outfile.bin 163 | ```` 164 | To decrypt: 165 | ```` 166 | fwcrypt -d -i infile.bin -o outfile.bin 167 | ```` 168 | -------------------------------------------------------------------------------- /STM32F411duino-bootloader.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "name": "STM32F411duino-bootloader", 5 | "path": "." 6 | } 7 | ], 8 | "settings": { 9 | "platformio-ide.autoPreloadEnvTasks": true, 10 | "platformio-ide.disablePIOHomeStartup": true, 11 | "files.associations": { 12 | "*.json": "jsonc" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /build/stm32f401xe_0x2000/firmware.map: -------------------------------------------------------------------------------- 1 | Archive member included to satisfy reference by file (symbol) 2 | 3 | build/objfw/libusb.a(usbd_core.o) 4 | build/objfw/bootloader.o (symbol from plugin) (usbd_poll) 5 | build/objfw/libusb.a(usbd_stm32f429_otgfs.o) 6 | build/objfw/bootloader.o (symbol from plugin) (usbd_otgfs) 7 | 8 | Discarded input sections 9 | 10 | .text 0x0000000000000000 0x0 /tmp/ccr2Deah.ltrans0.ltrans.o 11 | .data 0x0000000000000000 0x0 /tmp/ccr2Deah.ltrans0.ltrans.o 12 | .bss 0x0000000000000000 0x0 /tmp/ccr2Deah.ltrans0.ltrans.o 13 | .bss 0x0000000000000000 0x0 build/objfw/stm32f4xx.o 14 | .text 0x0000000000000000 0xd0 build/objfw/rc5a.o 15 | .data 0x0000000000000000 0x0 build/objfw/rc5a.o 16 | .bss 0x0000000000000000 0x68 build/objfw/rc5a.o 17 | .ARM.attributes 18 | 0x0000000000000000 0x22 build/objfw/rc5a.o 19 | .text 0x0000000000000000 0x134 build/objfw/chacha_a.o 20 | .data 0x0000000000000000 0x0 build/objfw/chacha_a.o 21 | .bss 0x0000000000000000 0x84 build/objfw/chacha_a.o 22 | .ARM.attributes 23 | 0x0000000000000000 0x22 build/objfw/chacha_a.o 24 | .text 0x0000000000000000 0x0 build/objfw/rc6a.o 25 | .data 0x0000000000000000 0x0 build/objfw/rc6a.o 26 | .bss 0x0000000000000000 0xb0 build/objfw/rc6a.o 27 | .text.rc6a_init 28 | 0x0000000000000000 0x68 build/objfw/rc6a.o 29 | .text.rc6a_encrypt 30 | 0x0000000000000000 0x54 build/objfw/rc6a.o 31 | .text.rc6a_decrypt 32 | 0x0000000000000000 0x54 build/objfw/rc6a.o 33 | .ARM.attributes 34 | 0x0000000000000000 0x22 build/objfw/rc6a.o 35 | 36 | Memory Configuration 37 | 38 | Name Origin Length Attributes 39 | ROM 0x0000000008000000 0x0000000000080000 xr 40 | RAM 0x0000000020000000 0x0000000000018000 xrw 41 | *default* 0x0000000000000000 0xffffffffffffffff 42 | 43 | Linker script and memory map 44 | 45 | 46 | .text 0x0000000008000000 0x107c 47 | *(.isr_vector) 48 | .isr_vector 0x0000000008000000 0x40 build/objfw/stm32f4xx.o 49 | 0x0000000008000000 __isr_vector 50 | *(.rodata.usbd_devfs) 51 | *(.rodata.usbd_devfs_asm) 52 | *(.rodata.usbd_otgfs) 53 | .rodata.usbd_otgfs 54 | 0x0000000008000040 0x34 /tmp/ccr2Deah.ltrans0.ltrans.o 55 | 0x0000000008000040 usbd_otgfs 56 | *(.rodata_usbd_otghs) 57 | *(.text.usbd_poll) 58 | .text.usbd_poll 59 | 0x0000000008000074 0xc /tmp/ccr2Deah.ltrans0.ltrans.o 60 | 0x0000000008000074 usbd_poll 61 | *(.text*) 62 | .text.dfu_get_descriptor 63 | 0x0000000008000080 0x48 /tmp/ccr2Deah.ltrans0.ltrans.o 64 | .text.dfu_set_idle 65 | 0x00000000080000c8 0x2c /tmp/ccr2Deah.ltrans0.ltrans.o 66 | .text.dfu_control 67 | 0x00000000080000f4 0x188 /tmp/ccr2Deah.ltrans0.ltrans.o 68 | .text.dfu_config 69 | 0x000000000800027c 0x18 /tmp/ccr2Deah.ltrans0.ltrans.o 70 | .text.set_led.part.0 71 | 0x0000000008000294 0x30 /tmp/ccr2Deah.ltrans0.ltrans.o 72 | .text.set_led 0x00000000080002c4 0x2c /tmp/ccr2Deah.ltrans0.ltrans.o 73 | .text.usbd_set_address 74 | 0x00000000080002f0 0x1e /tmp/ccr2Deah.ltrans0.ltrans.o 75 | .text.usbd_process_callback 76 | 0x000000000800030e 0x12 /tmp/ccr2Deah.ltrans0.ltrans.o 77 | .text.usbd_stall_pid 78 | 0x0000000008000320 0x26 /tmp/ccr2Deah.ltrans0.ltrans.o 79 | .text.usbd_process_eptx 80 | 0x0000000008000346 0x78 /tmp/ccr2Deah.ltrans0.ltrans.o 81 | *fill* 0x00000000080003be 0x2 82 | .text.usbd_process_ep0 83 | 0x00000000080003c0 0x224 /tmp/ccr2Deah.ltrans0.ltrans.o 84 | .text.usbd_process_evt 85 | 0x00000000080005e4 0x64 /tmp/ccr2Deah.ltrans0.ltrans.o 86 | .text.Flush_TX 87 | 0x0000000008000648 0x20 /tmp/ccr2Deah.ltrans0.ltrans.o 88 | .text.getinfo 0x0000000008000668 0x24 /tmp/ccr2Deah.ltrans0.ltrans.o 89 | .text.ep_setstall 90 | 0x000000000800068c 0x50 /tmp/ccr2Deah.ltrans0.ltrans.o 91 | .text.ep_isstalled 92 | 0x00000000080006dc 0x24 /tmp/ccr2Deah.ltrans0.ltrans.o 93 | .text.enable 0x0000000008000700 0xa0 /tmp/ccr2Deah.ltrans0.ltrans.o 94 | .text.connect 0x00000000080007a0 0x38 /tmp/ccr2Deah.ltrans0.ltrans.o 95 | .text.setaddr 0x00000000080007d8 0x14 /tmp/ccr2Deah.ltrans0.ltrans.o 96 | .text.set_tx_fifo 97 | 0x00000000080007ec 0x5e /tmp/ccr2Deah.ltrans0.ltrans.o 98 | *fill* 0x000000000800084a 0x2 99 | .text.ep_config 100 | 0x000000000800084c 0xf0 /tmp/ccr2Deah.ltrans0.ltrans.o 101 | .text.ep_deconfig 102 | 0x000000000800093c 0xa0 /tmp/ccr2Deah.ltrans0.ltrans.o 103 | .text.ep_read 0x00000000080009dc 0x54 /tmp/ccr2Deah.ltrans0.ltrans.o 104 | .text.ep_write 105 | 0x0000000008000a30 0x80 /tmp/ccr2Deah.ltrans0.ltrans.o 106 | .text.get_frame 107 | 0x0000000008000ab0 0x10 /tmp/ccr2Deah.ltrans0.ltrans.o 108 | .text.evt_poll 109 | 0x0000000008000ac0 0x104 /tmp/ccr2Deah.ltrans0.ltrans.o 110 | .text.get_serialno_desc 111 | 0x0000000008000bc4 0x90 /tmp/ccr2Deah.ltrans0.ltrans.o 112 | .text.dfu_reset 113 | 0x0000000008000c54 0x4 /tmp/ccr2Deah.ltrans0.ltrans.o 114 | .text.rtcmagic_to_dfubootkey 115 | 0x0000000008000c58 0x70 /tmp/ccr2Deah.ltrans0.ltrans.o 116 | 0x0000000008000c58 rtcmagic_to_dfubootkey 117 | .text.have_valid_user_app 118 | 0x0000000008000cc8 0x24 /tmp/ccr2Deah.ltrans0.ltrans.o 119 | 0x0000000008000cc8 have_valid_user_app 120 | .text.startup.main 121 | 0x0000000008000cec 0x16c /tmp/ccr2Deah.ltrans0.ltrans.o 122 | 0x0000000008000cec main 123 | .text 0x0000000008000e58 0x164 build/objfw/stm32f4xx.o 124 | 0x0000000008000e58 Reset_Handler 125 | 0x0000000008000efc System_try_Reboot_into_Application 126 | 0x0000000008000f06 System_Reset 127 | 0x0000000008000f12 System_Reboot_into_Bootloader 128 | 0x0000000008000f76 DebugMon_Handler 129 | 0x0000000008000f76 HardFault_Handler 130 | 0x0000000008000f76 SysTick_Handler 131 | 0x0000000008000f76 PendSV_Handler 132 | 0x0000000008000f76 NMI_Handler 133 | 0x0000000008000f76 UsageFault_Handler 134 | 0x0000000008000f76 MemManage_Handler 135 | 0x0000000008000f76 SVC_Handler 136 | 0x0000000008000f76 BusFault_Handler 137 | *(.rodata*) 138 | .rodata.dfu_flash_sdesc 139 | 0x0000000008000fbc 0x20 /tmp/ccr2Deah.ltrans0.ltrans.o 140 | .rodata.dfu_config_sdesc 141 | 0x0000000008000fdc 0xa /tmp/ccr2Deah.ltrans0.ltrans.o 142 | .rodata.dfu_product_sdesc 143 | 0x0000000008000fe6 0x26 /tmp/ccr2Deah.ltrans0.ltrans.o 144 | .rodata.dfu_manuf_sdesc 145 | 0x000000000800100c 0x28 /tmp/ccr2Deah.ltrans0.ltrans.o 146 | .rodata.dfu_lang_sdesc 147 | 0x0000000008001034 0x4 /tmp/ccr2Deah.ltrans0.ltrans.o 148 | .rodata.dfu_config_desc 149 | 0x0000000008001038 0x1b /tmp/ccr2Deah.ltrans0.ltrans.o 150 | .rodata.dfu_device_desc 151 | 0x0000000008001053 0x12 /tmp/ccr2Deah.ltrans0.ltrans.o 152 | *fill* 0x0000000008001065 0x3 153 | .rodata.dtable 154 | 0x0000000008001068 0x14 /tmp/ccr2Deah.ltrans0.ltrans.o 155 | 156 | .glue_7 0x000000000800107c 0x0 157 | .glue_7 0x000000000800107c 0x0 linker stubs 158 | 159 | .glue_7t 0x000000000800107c 0x0 160 | .glue_7t 0x000000000800107c 0x0 linker stubs 161 | 162 | .vfp11_veneer 0x000000000800107c 0x0 163 | .vfp11_veneer 0x000000000800107c 0x0 linker stubs 164 | 165 | .v4_bx 0x000000000800107c 0x0 166 | .v4_bx 0x000000000800107c 0x0 linker stubs 167 | 168 | .iplt 0x000000000800107c 0x0 169 | .iplt 0x000000000800107c 0x0 build/objfw/stm32f4xx.o 170 | 171 | .rel.dyn 0x000000000800107c 0x0 172 | .rel.iplt 0x000000000800107c 0x0 build/objfw/stm32f4xx.o 173 | 0x000000000800107c . = ALIGN (0x4) 174 | 0x000000000800107c __etext = . 175 | 0x00000000080011dc . = (. + SIZEOF (.data)) 176 | 0x0000000008002000 __app_start = ALIGN (0x2000) 177 | 178 | .data 0x0000000020000000 0x160 load address 0x000000000800107c 179 | 0x0000000020000000 . = ALIGN (0x4) 180 | 0x0000000020000000 __data_start__ = . 181 | *(.data*) 182 | .data 0x0000000020000000 0x160 build/objfw/stm32f4xx.o 183 | 0x0000000020000000 program_flash 184 | 0x0000000020000160 . = ALIGN (0x4) 185 | 0x0000000020000160 __data_end__ = . 186 | 187 | .igot.plt 0x0000000020000160 0x0 load address 0x00000000080011dc 188 | .igot.plt 0x0000000020000160 0x0 build/objfw/stm32f4xx.o 189 | 190 | .bss 0x0000000020000160 0x880 load address 0x00000000080011dc 191 | 0x0000000020000160 . = ALIGN (0x4) 192 | 0x0000000020000160 __bss_start__ = . 193 | *(.bss*) 194 | .bss.dfu_buffer 195 | 0x0000000020000160 0x808 /tmp/ccr2Deah.ltrans0.ltrans.o 196 | .bss.dfu 0x0000000020000968 0x64 /tmp/ccr2Deah.ltrans0.ltrans.o 197 | .bss.dfu_timeout 198 | 0x00000000200009cc 0x4 /tmp/ccr2Deah.ltrans0.ltrans.o 199 | 0x00000000200009cc dfu_timeout 200 | .bss.dfu_data 0x00000000200009d0 0x10 /tmp/ccr2Deah.ltrans0.ltrans.o 201 | *(COMMON) 202 | 0x00000000200009e0 . = ALIGN (0x4) 203 | 0x00000000200009e0 __bss_end__ = . 204 | 0x0000000008080000 PROVIDE (__romend = (ORIGIN (ROM) + LENGTH (ROM))) 205 | 0x0000000020017ffc PROVIDE (__stack = ((ORIGIN (RAM) + LENGTH (RAM)) - 0x4)) 206 | LOAD build/objfw/arc4.o 207 | LOAD /tmp/ccr2Deah.ltrans0.ltrans.o 208 | LOAD build/objfw/chacha.o 209 | LOAD build/objfw/gost.o 210 | LOAD build/objfw/raiden.o 211 | LOAD build/objfw/rc5.o 212 | LOAD build/objfw/speck.o 213 | LOAD build/objfw/xtea.o 214 | LOAD build/objfw/xtea1.o 215 | LOAD build/objfw/blowfish.o 216 | LOAD build/objfw/rtea.o 217 | LOAD build/objfw/rc6.o 218 | LOAD build/objfw/rijndael.o 219 | LOAD build/objfw/magma.o 220 | LOAD build/objfw/checksum.o 221 | LOAD build/objfw/crypto.o 222 | LOAD build/objfw/stm32f4xx.o 223 | LOAD build/objfw/descriptors.o 224 | LOAD build/objfw/bootloader.o 225 | LOAD build/objfw/rc5a.o 226 | LOAD build/objfw/chacha_a.o 227 | LOAD build/objfw/rc6a.o 228 | LOAD build/objfw/libusb.a 229 | START GROUP 230 | LOAD /usr/lib/gcc/arm-none-eabi/12.2.0/thumb/v7e-m/nofp/libgcc.a 231 | LOAD /usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libc_nano.a 232 | END GROUP 233 | START GROUP 234 | LOAD /usr/lib/gcc/arm-none-eabi/12.2.0/thumb/v7e-m/nofp/libgcc.a 235 | LOAD /usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libc_nano.a 236 | END GROUP 237 | OUTPUT(build/firmware.elf elf32-littlearm) 238 | LOAD linker stubs 239 | 240 | .comment 0x0000000000000000 0x1e 241 | .comment 0x0000000000000000 0x1e /tmp/ccr2Deah.ltrans0.ltrans.o 242 | 0x1f (size before relaxing) 243 | 244 | .ARM.attributes 245 | 0x0000000000000000 0x2a 246 | .ARM.attributes 247 | 0x0000000000000000 0x2c /tmp/ccr2Deah.ltrans0.ltrans.o 248 | .ARM.attributes 249 | 0x000000000000002c 0x21 build/objfw/stm32f4xx.o 250 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef _DFU_BOOTLOADER_H_ 17 | #define _DFU_BOOTLOADER_H_ 18 | 19 | /* Internal variables. Do not touch this section */ 20 | #define _AUTO -1 /* set automatically */ 21 | #define _DISABLE 0 /* disable feature */ 22 | #define _ENABLE 1 /* enable feature */ 23 | #define _LOW 2 24 | #define _HIGH 3 25 | /** DFU cipher definitions. */ 26 | #define DFU_CIPHER_ARC4 10 /* ARCFOUR (Rivest RC-4) stream cipher */ 27 | #define DFU_CIPHER_CHACHA 11 /* RFC7539-CHACHA20 stream cipher */ 28 | #define DFU_CIPHER_CHACHA_A 12 /* RFC7539-CHACHA20 stream cipher (ASM) */ 29 | #define DFU_CIPHER_GOST 13 /* GOST R 34.12-2015 "MAGMA" block cipher */ 30 | #define DFU_CIPHER_RAIDEN 14 /* RAIDEN block cipher */ 31 | #define DFU_CIPHER_RC5 15 /* Rivest RC5-32/12/128 clock cipher */ 32 | #define DFU_CIPHER_RC5_A 16 /* Rivest RC5-32/12/128 clock cipher (ASM) */ 33 | #define DFU_CIPHER_SPECK 17 /* SPECK 64/128 block cipher */ 34 | #define DFU_CIPHER_XTEA 18 /* XTEA block cipher */ 35 | #define DFU_CIPHER_XTEA1 19 /* XTEA-1 block cipher */ 36 | #define DFU_CIPHER_BLOWFISH 20 /* Blowfish block cipher */ 37 | #define DFU_CIPHER_RTEA 21 /* Ruptor's TEA or Repaired TEA */ 38 | #define DFU_CIPHER_RC6 22 /* Rivest RC6-32/20/128 block cipher */ 39 | #define DFU_CIPHER_RC6_A 23 /* Rivest RC6-32/20/128 block cipher (ASM)*/ 40 | #define DFU_CIPHER_RIJNDAEL 24 /* Rinjdael AES-128 block cipher */ 41 | #define DFU_CIPHER_MAGMA 25 /* GOST R 34.12-2015 "MAGMA" (Endianess fixed) block cipher */ 42 | /** Modes for using with block cipher */ 43 | #define DFU_CIPHER_ECB 0 /* Electronic Codebook (ECB) */ 44 | #define DFU_CIPHER_CBC 1 /* Cipher Block Chaining (CBC) */ 45 | #define DFU_CIPHER_PCBC 2 /* Propagating Cipher Block Chaining (PCBC) */ 46 | #define DFU_CIPHER_CFB 3 /* Cipher Feedback (CFB) */ 47 | #define DFU_CIPHER_OFB 4 /* Output Feedback (OFB) */ 48 | #define DFU_CIPHER_CTR 5 /* Counter (CTR) */ 49 | 50 | /** Checksum definitions. */ 51 | #define CRC32FAST 1 /* Lookup table based crc32 algorithm, consumes 1Kb of RAM for the table */ 52 | #define CRC32SMALL 2 /* Permutation based crc32 algorithm, no lookup table required but slower */ 53 | #define FNV1A32 3 /* Fowler–Noll–Vo 32 bit Hash */ 54 | #define FNV1A64 4 /* Fowler–Noll–Vo 64 bit Hash */ 55 | #define CRC64FAST 5 /* Lookup table based crc64 algorithm, consumes 2Kb of RAM for the table */ 56 | #define CRC64SMALL 6 /* Permutation based crc32 algorithm, no lookup table required but extremly slow */ 57 | 58 | #define __STR(x) #x 59 | #define STR(x) __STR(x) 60 | 61 | #ifdef DFU_USER_CONFIG 62 | #include STR(DFU_USER_CONFIG) 63 | #endif 64 | 65 | /* DEFAULT CONFIG STARTS HERE */ 66 | /* Skip unwanted dfuDNLOAD_SYNC phase. Slightly improve speed, but don't meets DFU1.1 state diagram */ 67 | #ifndef DFU_DNLOAD_NOSYNC 68 | #define DFU_DNLOAD_NOSYNC _ENABLE 69 | #endif 70 | 71 | /** Add extra DFU interface for EEPROM */ 72 | #ifndef DFU_INTF_EEPROM 73 | #define DFU_INTF_EEPROM _AUTO 74 | #endif 75 | 76 | /** Firmware can be uploaded from device */ 77 | #ifndef DFU_CAN_UPLOAD 78 | #define DFU_CAN_UPLOAD _ENABLE 79 | #endif 80 | 81 | /** Handle DFU_DETACH request in DFU mode. System reset will be issued. */ 82 | #ifndef DFU_DETACH 83 | #define DFU_DETACH _ENABLE 84 | #endif 85 | 86 | /** Whether application image is checked by its vector table */ 87 | #ifndef DFU_VERIFY_VTABLE 88 | #define DFU_VERIFY_VTABLE _ENABLE 89 | #endif 90 | 91 | /** Whether application image is verified by a checksum algorithm */ 92 | #ifndef DFU_VERIFY_CHECKSUM 93 | #define DFU_VERIFY_CHECKSUM _DISABLE 94 | #endif 95 | 96 | /** Memory Readout Protection level **/ 97 | #ifndef DFU_SEAL_LEVEL 98 | #define DFU_SEAL_LEVEL 0 99 | #endif 100 | 101 | /* USB VID */ 102 | #ifndef DFU_VENDOR_ID 103 | #define DFU_VENDOR_ID 0x0483 104 | #endif 105 | 106 | /* USB PID */ 107 | #ifndef DFU_DEVICE_ID 108 | #define DFU_DEVICE_ID 0xDF11 109 | #endif 110 | 111 | /* USB manufacturer string */ 112 | #ifndef DFU_STR_MANUF 113 | #define DFU_STR_MANUF "Your company name" 114 | #endif 115 | 116 | /* USB product sting */ 117 | #ifndef DFU_STR_PRODUCT 118 | #define DFU_STR_PRODUCT "Secure bootloader" 119 | #endif 120 | 121 | /* USB string for DFU configuration string descriptor. */ 122 | #ifndef DFU_DSC_CONFIG 123 | #define DFU_DSC_CONFIG _ENABLE 124 | #endif 125 | #ifndef DFU_STR_CONFIG 126 | #define DFU_STR_CONFIG "DFU" 127 | #endif 128 | 129 | /* USB string for DFU flash interface string descriptor. */ 130 | #ifndef DFU_DSC_FLASH 131 | #define DFU_DSC_FLASH _ENABLE 132 | #endif 133 | #ifndef DFU_STR_FLASH 134 | #define DFU_STR_FLASH "Internal flash" 135 | //#define DFU_STR_FLASH "@Internal Flash/0x08000000/04*016Kg,01*064Kg,03*128Kg" 136 | #endif 137 | 138 | /* USB string for DFU EEPROM interface sreing descriptor */ 139 | #ifndef DFU_DSC_EEPROM 140 | #define DFU_DSC_EEPROM _ENABLE 141 | #endif 142 | #ifndef DFU_STR_EEPROM 143 | #define DFU_STR_EEPROM "Internal EEPROM" 144 | #endif 145 | 146 | /* USB EP0 size. Must be 8 for USB FS */ 147 | #define DFU_EP0_SIZE 8 148 | 149 | /* DFU properties */ 150 | #ifndef DFU_POLL_TIMEOUT 151 | #define DFU_POLL_TIMEOUT 20 152 | #endif 153 | #ifndef DFU_DETACH_TIMEOUT 154 | #define DFU_DETACH_TIMEOUT 200 155 | #endif 156 | #ifndef DFU_BLOCKSZ 157 | #define DFU_BLOCKSZ 0x800 158 | #endif 159 | 160 | /** Whether the RTC register is checked to enforce bootloader or user application mode */ 161 | #ifndef DFU_CHECK_RTC_MAGIC_NUMBER 162 | #define DFU_CHECK_RTC_MAGIC_NUMBER _ENABLE 163 | #endif 164 | #ifndef RTC_MAGIC_NUMBER_BOOTLOADER 165 | #define RTC_MAGIC_NUMBER_BOOTLOADER 0x424c 166 | #endif 167 | #ifndef RTC_MAGIC_NUMBER_USERAPP 168 | #define RTC_MAGIC_NUMBER_USERAPP 0x424d 169 | #endif 170 | 171 | /* 32 bit DFU bootkey value */ 172 | #ifndef DFU_BOOTKEY 173 | #define DFU_BOOTKEY 0x157F32D4 174 | #endif 175 | 176 | /* DFU bootkey address. Top of the ram by default. _AUTO, _DISABLE or set address. 177 | * May be enabled internally. */ 178 | #ifndef DFU_BOOTKEY_ADDR 179 | #define DFU_BOOTKEY_ADDR _AUTO 180 | #endif 181 | 182 | /* DFU bootstrap port/pin settings. Set GPIOx or _DISABLE */ 183 | #ifndef DFU_BOOTSTRAP_GPIO 184 | #define DFU_BOOTSTRAP_GPIO GPIOA 185 | #endif 186 | #ifndef DFU_BOOTSTRAP_PIN 187 | #define DFU_BOOTSTRAP_PIN 0 188 | #endif 189 | 190 | /* Active bootstrap pin logic level. _HIGH, _LOW */ 191 | #ifndef DFU_BOOTSTRAP_LEVEL 192 | #define DFU_BOOTSTRAP_LEVEL _LOW 193 | #endif 194 | 195 | /* Pullup or pulldown settings for the bootstrap pin _AUTO, _DISABLE, _HIGH, _LOW */ 196 | #ifndef DFU_BOOTSTRAP_PULL 197 | #define DFU_BOOTSTRAP_PULL _AUTO 198 | #endif 199 | 200 | /* Double reset waiting time in mS. _DISABLE or time in mS */ 201 | #ifndef DFU_DBLRESET_MS 202 | #define DFU_DBLRESET_MS 300 203 | #endif 204 | 205 | /* DFU bootstrap port/pin settings. Set GPIOx or _DISABLE */ 206 | #ifndef DFU_LED_GPIO 207 | #define DFU_LED_GPIO GPIOC 208 | #endif 209 | #ifndef DFU_LED_RCC 210 | #define DFU_LED_RCC 0x004 // (0x1UL << 'x'-'A') => A=0x001, B=0x002, C=0x004 etc 211 | #endif 212 | #ifndef DFU_LED_PIN 213 | #define DFU_LED_PIN 13 214 | #endif 215 | #ifndef DFU_LED_ON_LEVEL 216 | #define DFU_LED_ON_LEVEL _LOW 217 | #endif 218 | 219 | /* Exit the bootloader into the user application after this many "time units" */ 220 | /* (0 = never, 1 = instantly/fastboot, 6 = 0.5s/minimum, 680 = 60s, ...32bit) */ 221 | #ifndef DFU_TIMEOUT_DEFAULT 222 | #define DFU_TIMEOUT_DEFAULT 6 // = 0.5s: use dfu-util -w 223 | #endif 224 | #ifndef DFU_TIMEOUT_RTC_MAGIC 225 | #define DFU_TIMEOUT_RTC_MAGIC 35 // = 3s 226 | #endif 227 | #ifndef DFU_TIMEOUT_UPDOWNLOAD 228 | #define DFU_TIMEOUT_UPDOWNLOAD 680 // = 60s 229 | #endif 230 | 231 | /* Skip entering the bootloader after download even when fastboot is disabled */ 232 | #ifndef DFU_SKIP_BOOTLOADER_AFTER_DOWNLOAD 233 | #define DFU_SKIP_BOOTLOADER_AFTER_DOWNLOAD _DISABLE 234 | #endif 235 | 236 | /* User application address. _AUTO or page aligned address. 237 | * for _AUTO check __app_start address in output linker map file*/ 238 | #ifndef DFU_APP_START 239 | #define DFU_APP_START _AUTO 240 | #endif 241 | 242 | /* User application size. _AUTO or required size in bytes. */ 243 | #ifndef DFU_APP_SIZE 244 | #define DFU_APP_SIZE _AUTO 245 | #endif 246 | 247 | /* Microsoft WCID allows automatic driver (WinUSB) installation on device 248 | * connection. Use _ENABLE to make your device likeable by Windows. */ 249 | #ifndef DFU_WCID 250 | #define DFU_WCID _DISABLE 251 | #endif 252 | 253 | /* Cipher to use. set _DISABLE or choose from implemented ciphers */ 254 | #ifndef DFU_CIPHER 255 | #define DFU_CIPHER DFU_CIPHER_RC5 256 | #endif 257 | #ifndef DFU_CIPHER_MODE 258 | #define DFU_CIPHER_MODE DFU_CIPHER_CBC 259 | #endif 260 | 261 | /** DFU secure key. */ 262 | #define DFU_AES_KEY_A 0x2D, 0x4D, 0x61, 0x6B, 0x65, 0x4C, 0x6F, 0x76, \ 263 | 0x65, 0x4E, 0x6F, 0x74, 0x57, 0x61, 0x72, 0x2D 264 | #define DFU_AES_KEY_B 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, \ 265 | 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F 266 | #ifndef DFU_AES_KEY_128 267 | #define DFU_AES_KEY_128 DFU_AES_KEY_A 268 | #endif 269 | 270 | #ifndef DFU_AES_KEY_192 271 | #define DFU_AES_KEY_192 0x2D, 0x4D, 0x61, 0x6B, 0x65, 0x4C, 0x6F, 0x76, \ 272 | 0x65, 0x4E, 0x6F, 0x74, 0x57, 0x61, 0x72, 0x2D, \ 273 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 274 | #endif 275 | 276 | #ifndef DFU_AES_KEY_256 277 | #define DFU_AES_KEY_256 DFU_AES_KEY_A, DFU_AES_KEY_B 278 | #endif 279 | 280 | /** cipher initialization vector for block cipher and CHACHA */ 281 | #ifndef DFU_AES_IV_64 282 | #define DFU_AES_IV_64 0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55 283 | #endif 284 | 285 | #ifndef DFU_AES_IV_96 286 | #define DFU_AES_IV_96 0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55, \ 287 | 0xCC, 0xBB, 0xAA, 0x99 288 | #endif 289 | 290 | #ifndef DFU_AES_IV_128 291 | #define DFU_AES_IV_128 0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55,\ 292 | 0xCC, 0xBB, 0xAA, 0x99, 0x44, 0x33, 0x22, 0x11 293 | #endif 294 | 295 | #endif // _DFU_BOOTLOADER_H_ 296 | -------------------------------------------------------------------------------- /examples/hello_world/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /examples/hello_world/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ], 7 | "unwantedRecommendations": [ 8 | "ms-vscode.cpptools-extension-pack" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /examples/hello_world/hello_world.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "name": "hello_world", 5 | "path": "." 6 | } 7 | ], 8 | "settings": { 9 | "files.associations": { 10 | "*.json": "jsonc", 11 | "array": "cpp", 12 | "deque": "cpp", 13 | "forward_list": "cpp", 14 | "list": "cpp", 15 | "string": "cpp", 16 | "unordered_map": "cpp", 17 | "unordered_set": "cpp", 18 | "vector": "cpp", 19 | "string_view": "cpp", 20 | "initializer_list": "cpp", 21 | "bootloader.h": "c" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/hello_world/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /examples/hello_world/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /examples/hello_world/pio-tools/custom_board.py: -------------------------------------------------------------------------------- 1 | Import('env') 2 | import os 3 | import re 4 | 5 | build_base = 0x08000000 6 | build_offset = 0x00002000 7 | build_address = (build_base+build_offset) 8 | 9 | board_config = env.BoardConfig() 10 | board_config.update("build.hwids", [ 11 | ["0x0483", "0xDF11"], # dfu-util will compare against the first one 12 | ["0x1EAF", "0x0003"], # maple_bootloader 13 | ["0x1EAF", "0x0004"] # maple_runtime 14 | ]) 15 | board_config.update("build.address", "0x%08x" % build_address) 16 | board_config.update("build.offset", "0x%08x" % build_offset) 17 | board_config.update("upload.offset_address", "0x%08x" % build_address) 18 | 19 | if "BUILD_UNFLAGS" not in env: 20 | env.Replace(BUILD_UNFLAGS=[]) 21 | 22 | build_unflags = env['BUILD_UNFLAGS'] 23 | build_unflags.append('-DVECT_TAB_OFFSET=0x0') 24 | build_unflags.append('-Wl,--defsym=LD_FLASH_OFFSET=0x0') 25 | env.Replace(BUILD_UNFLAGS=build_unflags) 26 | 27 | if "BUILD_FLAGS" not in env: 28 | env.Replace(BUILD_FLAGS=[]) 29 | 30 | build_flags = env['BUILD_FLAGS'] 31 | build_flags.append('-D BL_HID') 32 | build_flags.append('-D VECT_TAB_OFFSET=0x%x' % build_offset) 33 | build_flags.append('-Wl,--defsym=LD_FLASH_OFFSET=0x%x' % build_offset) 34 | env.Replace(BUILD_FLAGS=build_flags) 35 | 36 | # board_config.update("upload.require_upload_port", "false") 37 | # board_config.update("upload.use_1200bps_touch", "false") 38 | # board_config.update("upload.wait_for_upload_port", "false") 39 | 40 | # print(env.Dump()) 41 | # env.Exit(1) 42 | -------------------------------------------------------------------------------- /examples/hello_world/pio-tools/dfu-upload.py: -------------------------------------------------------------------------------- 1 | Import('env') 2 | import os 3 | import re 4 | from platformio.device.finder import SerialPortFinder 5 | 6 | def before_upload(source, target, env): 7 | print("Looking for upload port...") 8 | env.Replace( 9 | UPLOAD_PORT=SerialPortFinder( 10 | board_config=env.BoardConfig() if "BOARD" in env else None, 11 | upload_protocol=None, 12 | prefer_gdb_port=None, 13 | verbose=int(ARGUMENTS.get("PIOVERBOSE", 0)), 14 | ).find(None) 15 | ) 16 | if env['UPLOAD_PORT'] != None: 17 | print("Entering bootloader...") 18 | env.Execute(env['UPLOADER_RESETTER']+" "+env['UPLOAD_PORT']+" 1250") 19 | 20 | env.AddPreAction("upload", before_upload) 21 | 22 | # print(env.Dump()) 23 | 24 | uploader = env['UPLOADER'] 25 | resetter = re.sub( r"tool-dfuutil.*$", "tool-stm32duino/upload-reset\"", uploader ) 26 | 27 | flags = " ".join(env['UPLOADERFLAGS']) 28 | flags = re.sub( r"-s.*-D", "-D", flags ) 29 | flags = re.sub( r",0x1EAF.*0x.... ", " ", flags ) 30 | flags = uploader+" -R "+flags 31 | flags = flags.split() 32 | 33 | env.Replace(UPLOADER_ORG=uploader) 34 | env.Replace(UPLOADER_RESETTER=resetter) 35 | env.Replace(UPLOADER=os.path.join("pio-tools", "dfu-upload.sh")) 36 | env.Replace(UPLOADERFLAGS=flags) 37 | 38 | # print(env.Dump()) 39 | -------------------------------------------------------------------------------- /examples/hello_world/pio-tools/dfu-upload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | UPLOADER="$1" 4 | shift 1 5 | 6 | echo "${UPLOADER}" "$@" 7 | "${UPLOADER}" "$@" 8 | RC=$? 9 | 10 | [ "${RC}" -eq "74" ] && RC=0 # LIBUSB_ERROR_OTHER 11 | [ "${RC}" -eq "251" ] && RC=0 # whatever... 12 | 13 | exit ${RC} 14 | -------------------------------------------------------------------------------- /examples/hello_world/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | description = Simple USB-serial echo example using DFU upload on STM32F411CE 13 | default_envs = blackpill_f411ce_dfu 14 | 15 | [env] 16 | platform = ststm32 17 | framework = arduino 18 | upload_protocol = dfu 19 | monitor_dtr = 1 20 | build_flags = 21 | -D PIO_FRAMEWORK_ARDUINO_USB_HIGHSPEED_FULLMODE_unused 22 | -D PIO_FRAMEWORK_ARDUINO_USB_HIGHSPEED_unused 23 | -D PIO_FRAMEWORK_ARDUINO_ENABLE_HID_unused 24 | -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC 25 | -D USBD_USE_CDC 26 | -D USBCON 27 | -D USBD_VID=0x1eaf 28 | -D USBD_PID=0x0004 29 | -D USB_MANUFACTURER_STRING="\"LeafLabs\"" 30 | -D USB_PRODUCT_STRING="\"Maple 004\"" 31 | 32 | [env:blackpill_f411ce_dfu] 33 | board = blackpill_f411ce 34 | build_flags = ${env.build_flags} 35 | extra_scripts = 36 | pre:pio-tools/custom_board.py 37 | post:pio-tools/dfu-upload.py 38 | 39 | ;[env:blackpill_f411ce_hid] 40 | ;board = blackpill_f411ce 41 | ;build_flags = ${env.build_flags} 42 | ;upload_protocol = hid 43 | 44 | [env:bluepill_f103c8_64k] 45 | board = bluepill_f103c8 46 | build_flags = ${env.build_flags} 47 | upload_port = /dev/ttyACM2 48 | 49 | [env:bluepill_f103c8_128k] 50 | board = bluepill_f103c8_128k 51 | build_flags = ${env.build_flags} 52 | upload_port = /dev/ttyACM2 53 | -------------------------------------------------------------------------------- /examples/hello_world/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | String buffer; 5 | bool bufferComplete; 6 | 7 | #ifdef STM32F1xx 8 | #undef LED_BUILTIN 9 | #define LED_BUILTIN PA9 10 | #endif 11 | 12 | #ifdef STM32F4xx 13 | #undef LED_BUILTIN 14 | #define LED_BUILTIN PC13 15 | #endif 16 | 17 | void setup() { 18 | // put your setup code here, to run once: 19 | bufferComplete = false; 20 | 21 | pinMode(LED_BUILTIN, OUTPUT); // LED on 22 | #ifdef STM32F4xx 23 | pinMode(USER_BTN, INPUT_PULLUP); 24 | #endif 25 | 26 | SerialUSB.begin(115200); 27 | while(!SerialUSB) { 28 | digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); 29 | delay(250); 30 | 31 | #ifdef STM32F4xx 32 | if(digitalRead(USER_BTN) == LOW) { 33 | pinMode(LED_BUILTIN, INPUT); // LED off 34 | __disable_irq(); 35 | NVIC_SystemReset(); 36 | while (true); 37 | } 38 | #endif 39 | } 40 | delay(1000); 41 | SerialUSB.print(String("\x0d\x0aPlease type something and hit ENTER:\x0d\x0a> ")); 42 | 43 | digitalWrite(LED_BUILTIN, HIGH); // LED blue 44 | } 45 | 46 | void loop() { 47 | // put your main code here, to run repeatedly: 48 | if(SerialUSB.available()>0 && !bufferComplete) { 49 | while(SerialUSB.available()>0 && !bufferComplete) { 50 | int c = SerialUSB.read(); 51 | switch (c) 52 | { 53 | case 10: 54 | case 13: 55 | bufferComplete = buffer.length()>0; 56 | break; 57 | 58 | default: 59 | buffer += static_cast(c); 60 | SerialUSB.print(static_cast(c)); 61 | if(buffer.length()>60) bufferComplete = true; 62 | break; 63 | } 64 | } 65 | } else { 66 | delay(100); 67 | if(!SerialUSB) { 68 | pinMode(LED_BUILTIN, INPUT); // LED off 69 | __disable_irq(); 70 | NVIC_SystemReset(); 71 | while (true); 72 | } 73 | #ifdef STM32F4xx 74 | if(digitalRead(USER_BTN) == LOW) { 75 | pinMode(LED_BUILTIN, INPUT); // LED off 76 | __disable_irq(); 77 | NVIC_SystemReset(); 78 | while (true); 79 | } 80 | #endif 81 | } 82 | if(bufferComplete) { 83 | SerialUSB.print(String("\x0d\x0aYou wrote: ")+buffer+String("\x0d\x0a> ")); 84 | bufferComplete = false; 85 | buffer.remove(0); 86 | delay(500); 87 | digitalWrite(LED_BUILTIN, LOW); // LED red 88 | delay(500); 89 | digitalWrite(LED_BUILTIN, HIGH); // LED blue 90 | } 91 | } -------------------------------------------------------------------------------- /examples/hello_world/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | -------------------------------------------------------------------------------- /flow.md: -------------------------------------------------------------------------------- 1 | ## Generic flow 2 | ````mermaid 3 | graph TD 4 | start([RESET]) 5 | goapp([Activate application]) 6 | goboot([Activate bootloader]) 7 | bootkey1{{bootkey match inverted?}} 8 | bootkey2{{bootkey match on start?}} 9 | wait(Set bootkey and wait some time) 10 | clrbootkey[Clear bootkey] 11 | setclock[Setup RCC] 12 | checkpin(Setup and check pin) 13 | setregs[Setup MSP and VTOR] 14 | csverify(Verify application signature) 15 | setinvbootkey[Set inverted bootkey] 16 | 17 | start-->bootkey1 18 | bootkey1--Yes-->setregs 19 | setregs-->goapp 20 | bootkey1-->wait 21 | wait-->clrbootkey 22 | clrbootkey-->setclock 23 | wait-.hardware reset.->start 24 | setclock-->bootkey2 25 | bootkey2--Yes-->goboot 26 | bootkey2-->checkpin 27 | checkpin--Pin active-->goboot 28 | checkpin-->csverify 29 | csverify--Not match-->goboot 30 | csverify-->setinvbootkey 31 | setinvbootkey-.NVIC reset.->start 32 | ```` -------------------------------------------------------------------------------- /inc/arc4.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef _ARC4_H_ 17 | #define _ARC4_H_ 18 | #if defined(__cplusplus) 19 | extern "C" { 20 | #endif 21 | 22 | /** @brief Initialize RC-4 stream cipher 23 | * @param key pointer to array contains 128-bit key 24 | */ 25 | void arc4_init(const void* key); 26 | 27 | /** @brief Encrypt/Decrypt byte 28 | * @param out cipher output 29 | * @param in cipher input 30 | */ 31 | void arc4_crypt(void *out, const void *in); 32 | 33 | #if defined(__cplusplus) 34 | } 35 | #endif 36 | #endif //_ARC4_H_ 37 | -------------------------------------------------------------------------------- /inc/blowfish.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * Blowfish cypher implementation based on 3 | * https://www.schneier.com/academic/archives/1994/09/description_of_a_new.html 4 | * 5 | * Copyright ©2017 Dmitry Filimonchuk 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef _BLOWFISH_H_ 19 | #define _BLOWFISH_H_ 20 | #if defined(__cplusplus) 21 | extern "C" { 22 | #endif 23 | 24 | /** @brief Initialize Blowfish-type block cipher 25 | * @param key pointer to array contains 256-bit key 26 | * @note incompatible with reference, cipher uses XORSHIFT PRNG instead digits of the PI 27 | */ 28 | void blowfish_init(const void *key); 29 | 30 | /** @brief Encrypt 64-bit block 31 | * @param out cipher output 32 | * @param in cipher input 33 | */ 34 | void blowfish_encrypt(uint32_t *out, const uint32_t *in); 35 | 36 | /** @brief Decrypt 64-bit block 37 | * @param out cipher output 38 | * @param in cipher input 39 | */ 40 | void blowfish_decrypt(uint32_t *out, const uint32_t *in); 41 | 42 | #if defined(__cplusplus) 43 | } 44 | #endif 45 | #endif // _BLOWFISH_H_ 46 | -------------------------------------------------------------------------------- /inc/bootloader.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * Copyright 2019 by Tsien (UK) Ltd. 5 | * 6 | * Author: Adrian Carpenter 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | #ifndef _BOOTLOADER_H_ 21 | #define _BOOTLOADER_H_ 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * @brief Transfer and translate RTC magic number to DFU bootkey 28 | * @return Nothing, just causes side-effects. :) 29 | */ 30 | void rtcmagic_to_dfubootkey(uint32_t* key_addr); 31 | 32 | /** 33 | * @brief Check for having a valid user application in flash 34 | * @return uint32_t type of bootloader action defined by the user application: 35 | * 0 = preconditions for starting the app failed, enter bootloader and stay there 36 | * 1 = preconditions for starting the app passed, continue booting normally 37 | */ 38 | uint32_t have_valid_user_app(); 39 | 40 | #if defined(__cplusplus) 41 | } 42 | #endif 43 | #endif // _BOOTLOADER_H_ -------------------------------------------------------------------------------- /inc/chacha.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * ChaCha20 stream cipher implementation based on RFC7539 4 | * "ChaCha20 and Poly1305 for IETF Protocols" 5 | * https://tools.ietf.org/html/rfc7539 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef _CHACHA_H_ 21 | #define _CHACHA_H_ 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | /** @brief Initialize CHACHA-20 stream cipher 27 | * @param key pointer to array contains 256-bit key 28 | * @param nonce pointer to array contains 24-bit nonce 29 | */ 30 | void chacha_init(const void* key, const void* nonce); 31 | 32 | /** @brief Encrypt/Decrypt byte 33 | * @param out cipher output 34 | * @param in cipher input 35 | */ 36 | void chacha_crypt(void *out, const void *in); 37 | 38 | #if defined(__cplusplus) 39 | } 40 | #endif 41 | #endif //_CHACHA_H_ 42 | -------------------------------------------------------------------------------- /inc/chacha_a.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * ChaCha20 stream cipher implementation based on RFC7539 4 | * "ChaCha20 and Poly1305 for IETF Protocols" 5 | * https://tools.ietf.org/html/rfc7539 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef _CHACHA_A_H_ 21 | #define _CHACHA_A_H_ 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * @brief initialize CHACHA-20 stream cipher 28 | * @param key 256-bit ket 29 | * @param nonce 96-bit IV 30 | */ 31 | void _chacha_init(const void *key, const void *nonce); 32 | 33 | /** @brief Encrypt/Decrypt byte 34 | * @param out cipher output 35 | * @param in cipher input 36 | */ 37 | void _chacha_crypt(void *out, const void *in); 38 | 39 | #if defined(__cplusplus) 40 | } 41 | #endif 42 | #endif //_CHACHA_A_H_ 43 | -------------------------------------------------------------------------------- /inc/checksum.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * Copyright 2019 by Tsien (UK) Ltd. 5 | * 6 | * Author: Adrian Carpenter 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | #ifndef _CHECKSUM_H_ 21 | #define _CHECKSUM_H_ 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | extern const char *checksum_name; 27 | extern const size_t checksum_length; 28 | 29 | /** 30 | * @brief Calculate and append checksum to data. 31 | * @param data data buffer 32 | * @param len data length 33 | * @param bsize data buffer size 34 | * @return size_t length of the data with appended checksum or 0 if no enought space in buffer 35 | */ 36 | size_t append_checksum(void *data, size_t len, size_t bsize); 37 | 38 | /** 39 | * @brief Find and derify checksum. 40 | * @param data data buffer 41 | * @param bsize length of the data buffer 42 | * @return size_t length of the data w/o checksum or 0 if no data with correct checksum found 43 | */ 44 | size_t validate_checksum(const void *data, size_t bsize); 45 | 46 | #if defined(__cplusplus) 47 | } 48 | #endif 49 | #endif // _CHECKSUM_H_ -------------------------------------------------------------------------------- /inc/crypto.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef _CRYPTO_H_ 17 | #define _CRYPTO_H_ 18 | #if defined(__cplusplus) 19 | extern "C" { 20 | #endif 21 | /** 22 | * @brief Initialize cipher 23 | */ 24 | void aes_init(void); 25 | 26 | /** 27 | * @brief Encrypt data 28 | * @param out output buffer 29 | * @param in input buffer 30 | * @param sz data amount in bytes. must fit block size. 31 | */ 32 | void aes_encrypt(void *out, const void *in, size_t sz); 33 | 34 | /** 35 | * @brief Decrypt data 36 | * @param out output buffer 37 | * @param in input buffer 38 | * @param sz data amount in bytes. must fit block size 39 | */ 40 | void aes_decrypt(void *out, const void *in, size_t sz); 41 | 42 | /** 43 | * @brief Cipher name and mode 44 | */ 45 | extern const char *aes_name; 46 | 47 | /** 48 | * @brief Cipher block size 49 | */ 50 | extern const size_t aes_blksize; 51 | 52 | #if defined(__cplusplus) 53 | } 54 | #endif 55 | #endif //_CRYPTO_H_ 56 | -------------------------------------------------------------------------------- /inc/descriptors.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef _DFU_DESCRIPTORS_H_ 17 | #define _DFU_DESCRIPTORS_H_ 18 | #if defined(__cplusplus) 19 | extern "C" { 20 | #endif 21 | 22 | usbd_respond dfu_get_descriptor(usbd_ctlreq *req, void **address, uint16_t *len); 23 | 24 | #if (DFU_WCID != _DISABLE) 25 | usbd_respond dfu_get_vendor_descriptor(usbd_ctlreq *req, void**address, uint16_t *len); 26 | #endif 27 | 28 | #if defined (__cplusplus) 29 | } 30 | #endif 31 | #endif // _DFU_DESCRIPTORS_H_ 32 | -------------------------------------------------------------------------------- /inc/flash.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef _FLASH_H_ 17 | #define _FLASH_H_ 18 | #if defined(__cplusplus) 19 | extern "C" { 20 | #endif 21 | __attribute__((long_call)) uint8_t program_eeprom(void *romaddr, const void *buffer, size_t blksize); 22 | __attribute__((long_call)) uint8_t program_flash(void *romaddr, const void *buffer, size_t blksize); 23 | __attribute__((long_call)) uint8_t seal_flash(void); 24 | #if defined(__cplusplus) 25 | } 26 | #endif 27 | #endif // _FLASH_H_ 28 | -------------------------------------------------------------------------------- /inc/getopt.h: -------------------------------------------------------------------------------- 1 | /* A minimal POSIX getopt() implementation in ANSI C 2 | * 3 | * This is free and unencumbered software released into the public domain. 4 | * 5 | * This implementation supports the convention of resetting the option 6 | * parser by assigning optind to 0. This resets the internal state 7 | * appropriately. 8 | * 9 | * Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html 10 | */ 11 | #ifndef GETOPT_H 12 | #define GETOPT_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | static int optind = 1; 19 | static int opterr = 1; 20 | static int optopt; 21 | static char *optarg; 22 | 23 | static int 24 | getopt(int argc, char *const argv[], const char *optstring) 25 | { 26 | static int optpos = 1; 27 | const char *arg; 28 | (void)argc; 29 | 30 | /* Reset? */ 31 | if (optind == 0) 32 | { 33 | optind = 1; 34 | optpos = 1; 35 | } 36 | 37 | arg = argv[optind]; 38 | if (arg && strcmp(arg, "--") == 0) 39 | { 40 | optind++; 41 | return -1; 42 | } 43 | else if (!arg || arg[0] != '-' || !isalnum(arg[1])) 44 | { 45 | return -1; 46 | } 47 | else 48 | { 49 | const char *opt = strchr(optstring, arg[optpos]); 50 | optopt = arg[optpos]; 51 | if (!opt) 52 | { 53 | if (opterr && *optstring != ':') 54 | fprintf(stderr, "%s: illegal option: %c\n", argv[0], optopt); 55 | return '?'; 56 | } 57 | else if (opt[1] == ':') 58 | { 59 | if (arg[optpos + 1]) 60 | { 61 | optarg = (char *)arg + optpos + 1; 62 | optind++; 63 | optpos = 1; 64 | return optopt; 65 | } 66 | else if (argv[optind + 1]) 67 | { 68 | optarg = (char *)argv[optind + 1]; 69 | optind += 2; 70 | optpos = 1; 71 | return optopt; 72 | } 73 | else 74 | { 75 | if (opterr && *optstring != ':') 76 | fprintf(stderr, 77 | "%s: option requires an argument: %c\n", 78 | argv[0], optopt); 79 | return *optstring == ':' ? ':' : '?'; 80 | } 81 | } 82 | else 83 | { 84 | if (!arg[++optpos]) 85 | { 86 | optind++; 87 | optpos = 1; 88 | } 89 | return optopt; 90 | } 91 | } 92 | } 93 | 94 | #endif -------------------------------------------------------------------------------- /inc/gost.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * GOST R 34.12-2015 "MAGMA" block cipher implementation based on 4 | * official GOST R 34.12-2015 national standard of the Russian Federation 5 | * 6 | * Copyright ©2016 Dmitry Filimonchuk 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _GOST_H_ 20 | #define _GOST_H_ 21 | #if defined(__cplusplus) 22 | extern "C" { 23 | #endif 24 | 25 | /** @brief Initialize GOST R 34.12-2015 "MAGMA" 64-bit block cipher 26 | * @param key pointer to array contains 256-bit key 27 | * @note incompatible with reference, input data treated as 64-bit LE instead BE 28 | */ 29 | void gost_init(const void* key); 30 | 31 | /** @brief Encrypt 64-bit block 32 | * @param out cipher output 33 | * @param in cipher input 34 | */ 35 | void gost_encrypt(uint32_t *out, const uint32_t *in); 36 | 37 | /** @brief Decrypt 64-bit block 38 | * @param out cipher output 39 | * @param in cipher input 40 | */ 41 | void gost_decrypt(uint32_t *out, const uint32_t *in); 42 | 43 | #if defined(__cplusplus) 44 | } 45 | #endif 46 | #endif // _GOST_H_ 47 | -------------------------------------------------------------------------------- /inc/magma.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * GOST R 34.12-2015 "MAGMA" block cipher implementation based on 4 | * official GOST R 34.12-2015 national standard of the Russian Federation 5 | * 6 | * Copyright ©2016 Dmitry Filimonchuk 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _MAGMA_H_ 20 | #define _MAGMA_H_ 21 | #if defined(__cplusplus) 22 | extern "C" { 23 | #endif 24 | 25 | /** @brief Initialize GOST R 34.12-2015 "MAGMA" 64-bit block cipher 26 | * @param key pointer to array contains 256-bit key 27 | */ 28 | void magma_init(const void* key); 29 | 30 | /** @brief Encrypt 64-bit block 31 | * @param out cipher output 32 | * @param in cipher input 33 | */ 34 | void magma_encrypt(uint32_t *out, const uint32_t *in); 35 | 36 | /** @brief Decrypt 64-bit block 37 | * @param out cipher output 38 | * @param in cipher input 39 | */ 40 | void magma_decrypt(uint32_t *out, const uint32_t *in); 41 | 42 | #if defined(__cplusplus) 43 | } 44 | #endif 45 | #endif // _MAGMA_H_ 46 | -------------------------------------------------------------------------------- /inc/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef _MISC_H_ 2 | #define _MISC_H_ 3 | 4 | #define __ror32(a,b) (((a) >> ((b) & 0x1F)) | ((a) << (0x20 - ((b) & 0x1F)))) 5 | #define __rol32(a,b) (((a) << ((b) & 0x1F)) | ((a) >> (0x20 - ((b) & 0x1F)))) 6 | 7 | #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) 8 | #define CPUTOBE32(x) __builtin_bswap32(x) 9 | #define BE32TOCPU(x) __builtin_bswap32(x) 10 | #else 11 | #define CPUTOBE32(x) (x) 12 | #define BE32TOCPU(x) (x) 13 | #endif 14 | 15 | 16 | #endif /* _MISC_H_ */ 17 | -------------------------------------------------------------------------------- /inc/raiden.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Raiden block cipher implementation based on original code developed by 4 | * Julio César Hernández Castro and Javier Polimón Olabarrieta 5 | * https://sourceforge.net/projects/raiden-cipher/ 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef _RAIDEN_H_ 21 | #define _RAIDEN_H_ 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | /** @brief Initialize RAIDEN cipher 27 | * @param key pointer to array contains 128-bit key 28 | */ 29 | void raiden_init(const void* key); 30 | 31 | /** @brief Encrypt 64-bit block 32 | * @param out cipher output 33 | * @param in cipher input 34 | */ 35 | void raiden_encrypt(uint32_t *out, const uint32_t *in); 36 | 37 | /** @brief Decrypt 64-bit block 38 | * @param out cipher output 39 | * @param in cipher input 40 | */ 41 | void raiden_decrypt(uint32_t *out, const uint32_t *in); 42 | 43 | #if defined(__cplusplus) 44 | } 45 | #endif 46 | #endif // _RAIDEN_H_ 47 | -------------------------------------------------------------------------------- /inc/rc5.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * RC5-32/12/128 block cipher implementation based on 4 | * Ronald L. Rivest "The RC5 Encryption Algorithm" 5 | * http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef _RC5_H_ 21 | #define _RC5_H_ 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | /** @brief Initialize RC5-64/12/128 cipher 27 | * @param key pointer to 128-bit key 28 | */ 29 | void rc5_init(const void* key); 30 | 31 | /** @brief Encrypt 64-bit block 32 | * @param out cipher output 33 | * @param in cipher input 34 | */ 35 | void rc5_encrypt(uint32_t *out, const uint32_t *in); 36 | 37 | /** @brief Decrypt 64-bit block 38 | * @param out cipher output 39 | * @param in cipher input 40 | */ 41 | void rc5_decrypt(uint32_t *out, const uint32_t *in); 42 | 43 | #if defined(__cplusplus) 44 | } 45 | #endif 46 | #endif // _RC5_H_ 47 | -------------------------------------------------------------------------------- /inc/rc5_a.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * RC5-32/12/128-CBC block cipher implementation based on 4 | * Ronald L. Rivest "The RC5 Encryption Algorithm" 5 | * http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef _RC5_A_H_ 21 | #define _RC5_A_H_ 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | /** @brief Initialize RC5-64/12/128 cipher 27 | * @param key pointer to 128-bit key 28 | * @note THUMB assembly version 29 | */ 30 | void _rc5_init(const void* key); 31 | 32 | /** @brief Encrypt 64-bit block 33 | * @param out cipher output 34 | * @param in cipher input 35 | */ 36 | void _rc5_encrypt(uint32_t *out, const uint32_t *in); 37 | 38 | /** @brief Decrypt 64-bit block 39 | * @param out cipher output 40 | * @param in cipher input 41 | */ 42 | void _rc5_decrypt(uint32_t *out, const uint32_t *in); 43 | 44 | #if defined(__cplusplus) 45 | } 46 | #endif 47 | #endif // _RC5_H_ 48 | -------------------------------------------------------------------------------- /inc/rc6.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * RC6-32/20/16 block cipher implementation based on 4 | * RonaldL.Rivest ,M.J.B.Robshaw ,R.Sidney ,andY.L.Yin "The RC6(TM) Block Cipher" 5 | * http://people.csail.mit.edu/rivest/pubs/RRSY98.pdf 6 | * 7 | * Copyright ©2020 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef _RC6_H_ 21 | #define _RC6_H_ 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | /** @brief Initialize RC6-32/12/16 cipher 27 | * @param key pointer to 128-bit key 28 | */ 29 | void rc6_init(const void* key); 30 | 31 | /** @brief Encrypt 128-bit block 32 | * @param out cipher output 33 | * @param in cipher input 34 | */ 35 | void rc6_encrypt(uint32_t *out, const uint32_t *in); 36 | 37 | /** @brief Decrypt 128-bit block 38 | * @param out cipher output 39 | * @param in cipher input 40 | */ 41 | void rc6_decrypt(uint32_t *out, const uint32_t *in); 42 | 43 | #if defined(__cplusplus) 44 | } 45 | #endif 46 | #endif // _RC6_H_ 47 | -------------------------------------------------------------------------------- /inc/rc6a.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * RC6-32/20/16 block cipher implementation based on 4 | * RonaldL.Rivest ,M.J.B.Robshaw ,R.Sidney ,andY.L.Yin "The RC6(TM) Block Cipher" 5 | * http://people.csail.mit.edu/rivest/pubs/RRSY98.pdf 6 | * 7 | * Copyright ©2020 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef _RC6A_H_ 21 | #define _RC6A_H_ 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | /** @brief Initialize RC6-32/20/128 cipher 27 | * @param key pointer to 128-bit key 28 | * @note THUMB assembly version 29 | */ 30 | void rc6a_init(const void* key); 31 | 32 | /** @brief Encrypt 128-bit block 33 | * @param out cipher output 34 | * @param in cipher input 35 | */ 36 | void rc6a_encrypt(uint32_t *out, const uint32_t *in); 37 | 38 | /** @brief Decrypt 128-bit block 39 | * @param out cipher output 40 | * @param in cipher input 41 | */ 42 | void rc6a_decrypt(uint32_t *out, const uint32_t *in); 43 | 44 | #if defined(__cplusplus) 45 | } 46 | #endif 47 | #endif // _RC6A_H_ 48 | -------------------------------------------------------------------------------- /inc/rijndael.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Rijndael AES-128/192/256 4 | * 5 | * Copyright ©2020 Dmitry Filimonchuk 6 | * Based on: https://github.com/kokke/tiny-AES-c 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _RINJDAEL_H_ 20 | #define _RINJDAEL_H_ 21 | #if defined(__cplusplus) 22 | extern "C" { 23 | #endif 24 | 25 | #ifndef RIJNDAEL_KEYSIZE 26 | #define RIJNDAEL_KEYSIZE 128 27 | #endif 28 | 29 | #ifndef RIJNDAEL_ROM_SBOXES 30 | #define RIJNDAEL_ROM_SBOXES 0 31 | #endif 32 | 33 | 34 | /** @brief Initialize AES-128/192/256 cipher 35 | * @param key pointer to 128-bit key 36 | */ 37 | void rijndael_init(const void* key); 38 | 39 | /** @brief Encrypt 128-bit block 40 | * @param out cipher output 41 | * @param in cipher input 42 | */ 43 | void rijndael_encrypt(uint32_t *out, const uint32_t *in); 44 | 45 | /** @brief Decrypt 128-bit block 46 | * @param out cipher output 47 | * @param in cipher input 48 | */ 49 | void rijndael_decrypt(uint32_t *out, const uint32_t *in); 50 | 51 | #if defined(__cplusplus) 52 | } 53 | #endif 54 | #endif // _RINJDAEL_H_ 55 | -------------------------------------------------------------------------------- /inc/rtea.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Ruptor's TEA or Repaired TEA 4 | * 5 | * Copyright ©2017 Dmitry Filimonchuk 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef _RTEA_H_ 19 | #define _RTEA_H_ 20 | #if defined(__cplusplus) 21 | extern "C" { 22 | #endif 23 | 24 | /** @brief Initialize RTEA cipher 25 | * @param key pointer to 256-bit key 26 | */ 27 | void rtea_init(const void* key); 28 | 29 | /** @brief Encrypt 64-bit block 30 | * @param out cipher output 31 | * @param in cipher input 32 | */ 33 | void rtea_encrypt(uint32_t *out, const uint32_t *in); 34 | 35 | /** @brief Decrypt 64-bit block 36 | * @param out cipher output 37 | * @param in cipher input 38 | */ 39 | void rtea_decrypt(uint32_t *out, const uint32_t *in); 40 | 41 | #if defined(__cplusplus) 42 | } 43 | #endif 44 | #endif // _RTEA_H_ 45 | -------------------------------------------------------------------------------- /inc/speck.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * SPECK 64/128 block cipher implementation based on 4 | * "The Simon and Speck Families Of Lightwieght Block Ciphers" 5 | * http://eprint.iacr.org/2013/404.pdf 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef _SPECK_H_ 21 | #define _SPECK_H_ 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | /** @brief Initialize SPECK clock cipher 27 | * @param key pointer to array contains 128-bit key 28 | */ 29 | void speck_init(const void* key); 30 | 31 | /** @brief Encrypt 64-bit block 32 | * @param out cipher output 33 | * @param in cipher input 34 | */ 35 | void speck_encrypt(uint32_t *out, const uint32_t *in); 36 | 37 | /** @brief Decrypt 64-bit block 38 | * @param out cipher output 39 | * @param in cipher input 40 | */ 41 | void speck_decrypt(uint32_t *out, const uint32_t *in); 42 | 43 | #if defined(__cplusplus) 44 | } 45 | #endif 46 | #endif // _SPECK_H_ 47 | -------------------------------------------------------------------------------- /inc/usb_msft.h: -------------------------------------------------------------------------------- 1 | #ifndef _USB_MSFT_H_ 2 | #define _USB_MSFT_H_ 3 | #if defined(__cplusplus) 4 | extern "C" { 5 | #endif 6 | 7 | #include 8 | 9 | /* Microsoft OS 1.0 descriptors */ 10 | 11 | /* Extended Compat ID OS Feature Descriptor Specification */ 12 | #define USB_MSFT_REQ_GET_COMPAT_ID_FEATURE_DESCRIPTOR 0x04 13 | 14 | /* Table 2. Function Section */ 15 | struct usb_msft_compat_id_func_section { 16 | uint8_t bInterfaceNumber; 17 | uint8_t reserved0[1]; 18 | const char compatibleId[8]; 19 | const char subCompatibleId[8]; 20 | uint8_t reserved1[6]; 21 | } __attribute__((packed)); 22 | 23 | #define USB_MSFT_COMPAT_ID_FUNCTION_SECTION_SIZE 24 24 | 25 | /* Table 1. Header Section */ 26 | struct usb_msft_compat_id_desc { 27 | uint32_t dwLength; 28 | uint16_t bcdVersion; 29 | uint16_t wIndex; 30 | uint8_t bNumSections; 31 | uint8_t reserved[7]; 32 | struct usb_msft_compat_id_func_section functions[]; 33 | } __attribute__((packed)); 34 | 35 | #define USB_MSFT_COMPAT_ID_HEADER_SIZE 16 36 | 37 | #if defined(__cplusplus) 38 | } 39 | #endif 40 | 41 | #endif /* _USB_MSFT_H_ */ 42 | -------------------------------------------------------------------------------- /inc/xtea.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * eXtended TEA block cipher based on: 4 | * "Tea extensions" Roger M. Needham and David J. Wheeler 5 | * http://www.cix.co.uk/~klockstone/xtea.pdf 6 | * "Extended TEA Algorithms" Tom St Denis 7 | * http://tomstdenis.tripod.com/xtea.pdf 8 | * 9 | * Copyright ©2017 Dmitry Filimonchuk 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | 22 | #ifndef _XTEA_H_ 23 | #define _XTEA_H_ 24 | #if defined(__cplusplus) 25 | extern "C" { 26 | #endif 27 | 28 | /** @brief Initialize XTEA block cipher 29 | * @param key pointer to array contains 128-bit key 30 | * @note incomaptible with reference, data and key treated as 32-bit LE instead BE 31 | */ 32 | void xtea_init(const void* key); 33 | 34 | /** @brief Encrypt 64-bit block 35 | * @param out cipher output 36 | * @param in cipher input 37 | */ 38 | void xtea_encrypt(uint32_t *out, const uint32_t *in); 39 | 40 | /** @brief Decrypt 64-bit block 41 | * @param out cipher output 42 | * @param in cipher input 43 | */ 44 | void xtea_decrypt(uint32_t *out, const uint32_t *in); 45 | 46 | #if defined(__cplusplus) 47 | } 48 | #endif 49 | #endif // _XTEA_H_ 50 | -------------------------------------------------------------------------------- /inc/xtea1.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * eXtended TEA block cipher based on: 4 | * "Tea extensions" Roger M. Needham and David J. Wheeler 5 | * http://www.cix.co.uk/~klockstone/xtea.pdf 6 | * "Extended TEA Algorithms" Tom St Denis 7 | * http://tomstdenis.tripod.com/xtea.pdf 8 | * 9 | * Copyright ©2017 Dmitry Filimonchuk 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | 22 | #ifndef _XTEA1_H_ 23 | #define _XTEA1_H_ 24 | #if defined(__cplusplus) 25 | extern "C" { 26 | #endif 27 | 28 | /** @brief Initialize XTEA-1 block cipher 29 | * @param key pointer to array contains 128-bit key 30 | */ 31 | void xtea1_init(const void* key); 32 | 33 | /** @brief Encrypt 64-bit block 34 | * @param out cipher output 35 | * @param in cipher input 36 | */ 37 | void xtea1_encrypt(uint32_t *out, const uint32_t *in); 38 | 39 | /** @brief Decrypt 64-bit block 40 | * @param out cipher output 41 | * @param in cipher input 42 | */ 43 | void xtea1_decrypt(uint32_t *out, const uint32_t *in); 44 | 45 | #if defined(__cplusplus) 46 | } 47 | #endif 48 | #endif // _XTEA1_H_ 49 | -------------------------------------------------------------------------------- /ldscript.mk: -------------------------------------------------------------------------------- 1 | # This file is the part of the STM32 secure bootloader 2 | # 3 | # Copyright ©2016 Dmitry Filimonchuk 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | ROMSTART ?= 0x08000000 16 | ROMLEN ?= 256K 17 | RAMSTART ?= 0x20000000 18 | RAMLEN ?= 32K 19 | APPALIGN ?= 0x0800 20 | OUTFILE ?= script.ld 21 | 22 | define LDSCRIPT 23 | /* This file is automatically generated */ 24 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 25 | OUTPUT_ARCH(arm) 26 | MEMORY 27 | { 28 | ROM (rx) : ORIGIN = $(ROMSTART), LENGTH = ${ROMLEN} 29 | RAM (rwx) : ORIGIN = $(RAMSTART), LENGTH = $(RAMLEN) 30 | } 31 | SECTIONS 32 | { 33 | .text : 34 | { 35 | KEEP(*(.isr_vector)) 36 | *(.rodata.usbd_devfs) 37 | *(.rodata.usbd_devfs_asm) 38 | *(.rodata.usbd_otgfs) 39 | *(.rodata_usbd_otghs) 40 | *(.text.usbd_poll) 41 | *(.text*) 42 | *(.rodata*) 43 | } > ROM 44 | . = ALIGN(4); 45 | __etext = .; 46 | . = . + SIZEOF(.data); 47 | __app_start = ALIGN($(APPALIGN)); 48 | .data : AT (__etext) 49 | { 50 | . = ALIGN(4); 51 | __data_start__ = .; 52 | *(.data*) 53 | . = ALIGN(4); 54 | __data_end__ = .; 55 | } > RAM 56 | .bss (NOLOAD): 57 | { 58 | . = ALIGN(4); 59 | __bss_start__ = .; 60 | *(.bss*) 61 | *(COMMON) 62 | . = ALIGN(4); 63 | __bss_end__ = .; 64 | } > RAM 65 | PROVIDE(__romend = ORIGIN(ROM) + LENGTH(ROM)); 66 | PROVIDE(__stack = ORIGIN(RAM) + LENGTH(RAM) - 4); 67 | } 68 | endef 69 | 70 | .PHONY: all 71 | 72 | all: $(OUTFILE) 73 | @echo Building linker script 74 | 75 | $(OUTFILE): 76 | $(file >$@,$(LDSCRIPT)) 77 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | ; ********************************************************** 12 | ; * Use make instead of PlatformIO to build the bootloader * 13 | ; ********************************************************** 14 | 15 | [env:genericSTM32F411CE] 16 | platform = ststm32 17 | board = genericSTM32F411CE 18 | ; framework = cmsis 19 | build_flags = 20 | -DSTM32F4 21 | -DSTM32F411xE 22 | -DDFU_USER_CONFIG=userconfig.h 23 | -I./ 24 | -I./inc 25 | -I./CMSIS/CMSIS/Core/Include 26 | -I./CMSIS/Device/ST 27 | -I./usb/inc 28 | -------------------------------------------------------------------------------- /scripts/both.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | ./build.sh 4 | ./download.sh 5 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | test -f Makefile || cd .. 4 | 5 | make clean 6 | # make DFU_USER_CONFIG=userconfig.h stm32f103x8 # bluepill 7 | # make DFU_USER_CONFIG=userconfig.h stm32f103xb # stink baite 8 | # make DFU_USER_CONFIG=userconfig.h stm32f401xe # blackpill 9 | # make DFU_USER_CONFIG=userconfig.h stm32f401xe_0x2000 # blackpill 10 | # make DFU_USER_CONFIG=userconfig.h stm32f411xe # blackpill 11 | # make DFU_USER_CONFIG=userconfig.h stm32f411xe_0x2000 # blackpill 12 | 13 | ls -l build/ 14 | -------------------------------------------------------------------------------- /scripts/download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | test -f Makefile || cd .. 4 | 5 | openocd \ 6 | -f interface/stlink.cfg -c "transport select hla_swd" \ 7 | -f target/stm32f4x.cfg -c init \ 8 | -c "reset halt" -c "wait_halt 2000" -c "stm32f2x unlock 0" -c "wait_halt 2000" \ 9 | -c "reset halt" -c "wait_halt 2000" -c "stm32f2x mass_erase 0" -c "wait_halt 10000" \ 10 | -c "reset halt" -c "wait_halt 2000" -c "program build/firmware.hex" \ 11 | -c "reset run" -c shutdown 12 | 13 | exit $? 14 | -------------------------------------------------------------------------------- /src/arc4.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include "arc4.h" 18 | 19 | static uint8_t S[256]; 20 | static uint8_t si; 21 | static uint8_t sj; 22 | 23 | void arc4_init (const void *key) { 24 | for (int i=0; i < 256; i++) { 25 | S[i] = i; 26 | } 27 | for (int i=0, j=0; i < 255; i++) { 28 | j = (j + S[i] + ((uint8_t*)key)[i & 0x0F]) & 0xFF; 29 | uint8_t _t = S[i]; 30 | S[i] = S[j]; 31 | S[j] = _t; 32 | } 33 | si = 0; 34 | sj = 0; 35 | } 36 | 37 | void arc4_crypt(void *out, const void *in) { 38 | uint8_t _t; 39 | _t = S[++si]; 40 | sj = sj + _t; 41 | S[si] = S[sj]; 42 | S[sj] = _t; 43 | *(uint8_t*)out = *(uint8_t*)in ^ S[(S[si] + S[sj]) & 0xFF]; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/blowfish.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Blowfish cypher implementation based on 4 | * https://www.schneier.com/academic/archives/1994/09/description_of_a_new.html 5 | * 6 | * Xorshift implementation based on Xorshift RNGs by George Marsaglia 7 | * https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf 8 | * 9 | * Copyright ©2017 Dmitry Filimonchuk 10 | * * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | 22 | #include 23 | #include "misc.h" 24 | #include "blowfish.h" 25 | 26 | #define rounds 16 27 | 28 | static struct { 29 | uint32_t P[18]; 30 | uint32_t S[4][256]; 31 | } D; 32 | 33 | static uint32_t F(uint32_t x) { 34 | uint32_t h = D.S[0][x >> 24] + D.S[1][(x >> 16) & 0xFF]; 35 | return (h ^ D.S[2][(x >> 8) & 0xFF]) + D.S[3][x & 0xFF]; 36 | } 37 | 38 | void blowfish_encrypt(uint32_t *out, const uint32_t *in){ 39 | uint32_t L = in[0]; 40 | uint32_t R = in[1]; 41 | for (int i = 0; i < rounds; i+=2) { 42 | L ^= D.P[i]; 43 | R ^= F(L); 44 | R ^= D.P[i+1]; 45 | L ^= F(R); 46 | } 47 | L ^= D.P[16]; 48 | R ^= D.P[17]; 49 | out[0] = R; 50 | out[1] = L; 51 | } 52 | 53 | void blowfish_decrypt(uint32_t *out, const uint32_t *in) { 54 | uint32_t L = in[0]; 55 | uint32_t R = in[1]; 56 | for (int i = rounds; i > 0; i-=2) { 57 | L ^= D.P[i+1]; 58 | R ^= F(L); 59 | R ^= D.P[i]; 60 | L ^= F(R); 61 | } 62 | L ^= D.P[1]; 63 | R ^= D.P[0]; 64 | out[0] = R; 65 | out[1] = L; 66 | } 67 | 68 | void blowfish_init(const void *key) { 69 | /* Original implementation is based on PI digits, but 70 | * "There is nothing sacred about pi; any string of random bits--digits 71 | * of e, RAND tables, output of a random number generator--will suffice. 72 | * B. Schneier" 73 | * So, we will use pseudo random numbers fom xorshift 74 | */ 75 | uint32_t T[2] = {0,0}; 76 | uint32_t S = 0xDEADBEEF; 77 | uint32_t *K = (uint32_t*)&D; 78 | for (int i = 0; i < sizeof(D) / 4; i++) { 79 | S ^= S << 13; 80 | S ^= S >> 17; 81 | S ^= S << 5; 82 | K[i] = S; 83 | } 84 | 85 | for (int i = 0; i < (18 * 4); i++) { 86 | ((uint8_t*)D.P)[i] ^= ((uint8_t*)key)[i & 0x1F]; 87 | } 88 | 89 | for (int i = 0; i < 18; i+=2) { 90 | blowfish_encrypt(T, T); 91 | D.P[i] = T[0]; 92 | D.P[i+1] = T[1]; 93 | } 94 | for (int i = 0; i < 4; ++i) { 95 | for (int j = 0; j < 256; j+=2) { 96 | blowfish_encrypt(T, T); 97 | D.S[i][j] = T[0]; 98 | D.S[i][j+1] = T[1]; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/chacha.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * ChaCha20 stream cipher implementation based on RFC7539 4 | * "ChaCha20 and Poly1305 for IETF Protocols" 5 | * https://tools.ietf.org/html/rfc7539 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include "misc.h" 23 | #include "chacha.h" 24 | 25 | #define QR(s,a,b,c,d) Qround((s), (a) << 24 | (b) << 16 | (c) << 8 | (d) << 0) 26 | 27 | #define SPLIT(x) (x) & 0xFF, ((x) >> 8) & 0xFF, ((x) >> 16) & 0xFF, ((x) >> 24) & 0xFF 28 | 29 | static const uint8_t prefix[] = { 30 | 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x20, 0x33, 31 | 0x32, 0x2d, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 32 | }; 33 | 34 | static uint32_t inits[16]; 35 | static uint32_t state[16]; 36 | static uint8_t bytecount; 37 | 38 | static void Qround (uint32_t *s, uint32_t abcd) { 39 | 40 | uint32_t A = s[(abcd >> 24) & 0x0F]; 41 | uint32_t B = s[(abcd >> 16) & 0x0F]; 42 | uint32_t C = s[(abcd >> 8 ) & 0x0F]; 43 | uint32_t D = s[(abcd >> 0 ) & 0x0F]; 44 | 45 | A += B; D ^= A; D = __rol32(D, 16); 46 | C += D; B ^= C; B = __rol32(B, 12); 47 | A += B; D ^= A; D = __rol32(D, 8); 48 | C += D; B ^= C; B = __rol32(B, 7); 49 | 50 | s[(abcd >> 24) & 0x0F] = A; 51 | s[(abcd >> 16) & 0x0F] = B; 52 | s[(abcd >> 8) & 0x0F] = C; 53 | s[(abcd >> 0) & 0x0F] = D; 54 | } 55 | 56 | static void chacha_block() { 57 | memcpy(state, inits, sizeof(state)); 58 | for (int i = 0; i < 10; i++) { 59 | QR(state, 0, 4, 8, 12); 60 | QR(state, 1, 5, 9, 13); 61 | QR(state, 2, 6, 10, 14); 62 | QR(state, 3, 7, 11, 15); 63 | QR(state, 0, 5, 10, 15); 64 | QR(state, 1, 6, 11, 12); 65 | QR(state, 2, 7, 8, 13); 66 | QR(state, 3, 4, 9, 14); 67 | } 68 | for (int i = 0; i < 16; i++) { 69 | state[i] += inits[i]; 70 | } 71 | } 72 | 73 | void chacha_init(const void* key, const void* nonce) { 74 | memcpy(&inits[0], prefix, 16); 75 | memcpy(&inits[4], key, 32); 76 | memcpy(&inits[13], nonce, 12); 77 | inits[12] = 0; 78 | bytecount = 0; 79 | } 80 | 81 | void chacha_crypt(void *out, const void *in) { 82 | if ((bytecount & 0x3F) == 0) { 83 | inits[12]++; 84 | chacha_block(); 85 | } 86 | *(uint8_t*)out = *(uint8_t*)in ^ ((uint8_t*)state)[bytecount & 0x3F]; 87 | bytecount++; 88 | } 89 | -------------------------------------------------------------------------------- /src/chacha_a.S: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * ChaCha20 stream cipher implementation based on RFC7539 4 | * "ChaCha20 and Poly1305 for IETF Protocols" 5 | * https://tools.ietf.org/html/rfc7539 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include "../config.h" 21 | #define QR(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) 22 | 23 | .syntax unified 24 | .cpu cortex-m0plus 25 | .thumb 26 | .section .text 27 | 28 | .thumb_func 29 | .globl _chacha_init 30 | .type _chacha_init, %function 31 | /* R0 <- key pointer 32 | * R1 <- iv pointer 33 | */ 34 | _chacha_init: 35 | push {r4, r5, lr} 36 | ldr r2, =_inits 37 | adr r3, _preamble 38 | movs r4, #0x10 39 | bl .L_memcpy 40 | adds r2, #0x10 41 | mov r3, r0 42 | movs r4, #0x20 43 | bl .L_memcpy 44 | adds r2, #0x20 45 | stmia r2!, {r4} 46 | mov r3, r1 47 | movs r4, 0x0C 48 | bl .L_memcpy 49 | ldr r2, =_counter 50 | str r4, [r2] 51 | pop {r4, r5, pc} 52 | .L_memcpy: 53 | subs r4, #1 54 | ldrb r5, [r3, r4] 55 | strb r5, [r2, r4] 56 | bne .L_memcpy 57 | bx lr 58 | .size _chacha_init, . - _chacha_init 59 | 60 | .thumb_func 61 | .globl _chacha_crypt 62 | .type _chacha_crypt, %function 63 | /* R0 <- out pointer 64 | * R1 <- in pointer 65 | */ 66 | _chacha_crypt: 67 | push {r4, r5, r6, r7, lr} 68 | ble .L_exit 69 | /* processing block */ 70 | ldr r5, =_state 71 | ldr r3, =_counter 72 | ldr r3, [r3] 73 | ands r3, r3 74 | bne .L_process_byte 75 | /* processing new state */ 76 | ldr r4, =_inits 77 | .L_next_state: 78 | /* increment counter in init block*/ 79 | ldr r3, [r4, #0x30] 80 | adds r3, #0x01 81 | str r3, [r4, #0x30] 82 | /* copy init to state */ 83 | movs r6, #0x3C 84 | .L_copy_state: 85 | ldr r3, [r4, r6] 86 | str r3, [r5, r6] 87 | subs r6, #0x04 88 | bhs .L_copy_state 89 | movs r6, #10 90 | ldr r3, =_Qround 91 | .L_qrounds: 92 | ldr r7, =#QR(0, 4, 8, 12) 93 | blx r3 94 | ldr r7, =#QR(1, 5, 9, 13) 95 | blx r3 96 | ldr r7, =#QR(2, 6, 10, 14) 97 | blx r3 98 | ldr r7, =#QR(3, 7, 11, 15) 99 | blx r3 100 | ldr r7, =#QR(0, 5, 10, 15) 101 | blx r3 102 | ldr r7, =#QR(1, 6, 11, 12) 103 | blx r3 104 | ldr r7, =#QR(2, 7, 8, 13) 105 | blx r3 106 | ldr r7, =#QR(3, 4, 9, 14) 107 | blx r3 108 | subs r6, #0x01 109 | bne .L_qrounds 110 | .L_add_init: 111 | ldr r3, [r4, r6] 112 | ldr r7, [r5, r6] 113 | add r7, r3 114 | str r7, [r5, r6] 115 | adds r6, #0x04 116 | cmp r6, #0x40 117 | bne .L_add_init 118 | movs r3, #0x00 119 | .L_process_byte: 120 | ldrb r2, [r5, r3] 121 | ldrb r4, [r1] 122 | eors r4, r2 123 | strb r4, [r0] 124 | movs r4, #0x3F 125 | adds r3, #0x01 126 | ands r3, r4 127 | ldr r2, =_counter 128 | str r3, [r2] 129 | .L_exit: 130 | pop {r4, r5, r6, r7, pc} 131 | .size _chacha_crypt, . - _chacha_crypt 132 | 133 | 134 | /* R 135 | * R5 <- state 136 | */ 137 | 138 | #define A r0 139 | #define B r1 140 | #define C r2 141 | #define D r4 142 | #define T r3 143 | .thumb_func 144 | .type _Qround, %function 145 | _Qround: 146 | push {r0-r4, lr} 147 | 148 | mov T, r7 149 | lsrs T, #22 150 | ldr A, [r5, r3] 151 | lsls T, r7, #8 152 | lsrs T, #22 153 | ldr B, [r5, r3] 154 | lsls T, r7, #16 155 | lsrs T, #22 156 | ldr C, [r5, r3] 157 | lsls T, r7, #24 158 | lsrs T, #22 159 | ldr D, [r5, r3] 160 | 161 | add A, B //A += B 162 | eors D, A //D ^= A 163 | movs T, #(32 - 16) 164 | rors D, T //D <<<= 15 165 | add C, D 166 | eors B, C 167 | movs T, #(32 - 12) 168 | rors B, T 169 | add A, B 170 | eors D, A 171 | movs T, #(32 - 8) 172 | rors D, T 173 | add C, D 174 | eors B, C 175 | movs T, #(32 - 7) 176 | rors B, T 177 | 178 | mov T, r7 179 | lsrs T, #22 180 | str A, [r5, r3] 181 | lsls T, r7, #8 182 | lsrs T, #22 183 | str B, [r5, r3] 184 | lsls T, r7, #16 185 | lsrs T, #22 186 | str C, [r5, r3] 187 | lsls T, r7, #24 188 | lsrs T, #22 189 | str D, [r5, r3] 190 | 191 | pop {r0-r4, pc} 192 | 193 | .size _Qround, . - _Qround 194 | 195 | .align 2 196 | _preamble: 197 | .byte 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x20, 0x33 198 | .byte 0x32, 0x2d, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b 199 | 200 | .pool 201 | 202 | .section .bss 203 | .align 2 204 | _counter: .space 4 205 | _inits: .space 64 206 | _state: .space 64 207 | -------------------------------------------------------------------------------- /src/checksum.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * Copyright 2019 by Tsien (UK) Ltd. 5 | * 6 | * Author: Adrian Carpenter 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "config.h" 24 | #include "checksum.h" 25 | 26 | 27 | #if ((DFU_VERIFY_CHECKSUM == CRC32FAST) || (DFU_VERIFY_CHECKSUM == CRC32SMALL)) 28 | typedef uint32_t checksum_t; 29 | const char *checksum_name = "CRC-32"; 30 | #define CRC_POLY 0xEDB88320UL 31 | #define CRC_INIT 0xFFFFFFFFUL 32 | 33 | #elif ((DFU_VERIFY_CHECKSUM == CRC64FAST) || (DFU_VERIFY_CHECKSUM == CRC64SMALL)) 34 | typedef uint64_t checksum_t; 35 | const char *checksum_name = "CRC-64"; 36 | #define CRC_POLY 0x95AC9329AC4BC9B5ULL 37 | #define CRC_INIT 0xFFFFFFFFFFFFFFFFULL 38 | 39 | #elif (DFU_VERIFY_CHECKSUM == FNV1A32) 40 | typedef uint32_t checksum_t; 41 | const char *checksum_name = "FNV1A-32"; 42 | #define FNV_OFFS 0x811c9dc5UL 43 | #define FNV_PRIM 16777619UL 44 | 45 | #elif (DFU_VERIFY_CHECKSUM == FNV1A64) 46 | const char *checksum_name = "FNV1A-64"; 47 | typedef uint64_t checksum_t; 48 | #define FNV_OFFS 0xcbf29ce484222325ULL 49 | #define FNV_PRIM 1099511628211ULL 50 | 51 | #else 52 | const char *checksum_name = "NONE"; 53 | typedef uint32_t checksum_t; 54 | #endif 55 | 56 | /* Function prototypes */ 57 | inline static void init_checksum(checksum_t *checksum); 58 | inline static void update_checksum(checksum_t *checksum, uint8_t data); 59 | 60 | 61 | /* Function implementations */ 62 | #if ((DFU_VERIFY_CHECKSUM == CRC32FAST) || (DFU_VERIFY_CHECKSUM == CRC64FAST)) 63 | 64 | static checksum_t table[0x100]; 65 | 66 | static void init_checksum(checksum_t *checksum) { 67 | for (int j = 0; j < 256; j++) { 68 | uint64_t cs = j; 69 | for (int i = 0; i < 8; i++) { 70 | if (cs & 0x01) { 71 | cs = (cs >> 1) ^ CRC_POLY; 72 | } else { 73 | cs = (cs >> 1); 74 | } 75 | } 76 | table[j] = cs; 77 | } 78 | *checksum = CRC_INIT; 79 | } 80 | 81 | static void update_checksum(checksum_t *checksum, uint8_t data) { 82 | data ^= *checksum & 0xFF; 83 | *checksum = (*checksum >> 8) ^ table[data]; 84 | } 85 | 86 | #elif ((DFU_VERIFY_CHECKSUM == CRC32SMALL) || (DFU_VERIFY_CHECKSUM == CRC64SMALL)) 87 | 88 | static void init_checksum(checksum_t *checksum) { 89 | *checksum = CRC_INIT; 90 | } 91 | 92 | static void update_checksum(checksum_t *checksum, uint8_t data) { 93 | *checksum ^= data; 94 | for (int i =0; i < 8; i++) { 95 | if (*checksum & 0x01) { 96 | *checksum = (*checksum >> 1) ^ CRC_POLY; 97 | } else { 98 | *checksum = (*checksum >> 1); 99 | } 100 | } 101 | } 102 | 103 | #elif ((DFU_VERIFY_CHECKSUM == FNV1A32) || (DFU_VERIFY_CHECKSUM == FNV1A64)) 104 | 105 | static void init_checksum(checksum_t *checksum) { 106 | *checksum = FNV_OFFS; 107 | } 108 | 109 | static void update_checksum(checksum_t *checksum, uint8_t data) { 110 | *checksum = (*checksum ^ data) * FNV_PRIM; 111 | } 112 | 113 | #else 114 | 115 | static void update_checksum(checksum_t *cs, uint8_t data) { } 116 | static void init_checksum(checksum_t *cs) { *cs = 0; } 117 | 118 | #endif 119 | 120 | static int __memcmp(const void *a, const void *b, size_t len) { 121 | const int8_t *x = a; 122 | const int8_t *y = b; 123 | for(size_t i = 0; i < len; i++){ 124 | int res = x[i] - y[i]; 125 | if (res != 0) return res; 126 | } 127 | return 0; 128 | } 129 | 130 | const size_t checksum_length = sizeof(checksum_t); 131 | 132 | size_t append_checksum(void *data, size_t len, size_t bsize) { 133 | checksum_t cs; 134 | uint8_t *buf = data; 135 | if (bsize < len + sizeof(checksum_t)) { 136 | return 0; 137 | } 138 | init_checksum(&cs); 139 | for (size_t i = 0; i < len; i++) { 140 | update_checksum(&cs, *buf); 141 | buf++; 142 | } 143 | memcpy(buf, &cs, sizeof(cs)); 144 | return len + sizeof(checksum_t); 145 | } 146 | 147 | size_t validate_checksum(const void *data, size_t bsize) { 148 | checksum_t cs; 149 | const uint8_t *buf = data; 150 | init_checksum(&cs); 151 | while(sizeof(checksum_t) <= bsize--) { 152 | if (__memcmp(&cs, buf, sizeof(cs)) == 0) { 153 | return (size_t)(buf - (uint8_t *)data); 154 | } 155 | update_checksum(&cs, *buf); 156 | buf++; 157 | } 158 | return 0; 159 | } 160 | -------------------------------------------------------------------------------- /src/ctest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "rc5.h" 6 | #include "gost.h" 7 | #include "speck.h" 8 | #include "xtea.h" 9 | #include "xtea1.h" 10 | #include "rtea.h" 11 | #include "raiden.h" 12 | #include "blowfish.h" 13 | #include "chacha.h" 14 | #include "arc4.h" 15 | #include "rc6.h" 16 | #include "rijndael.h" 17 | #include "magma.h" 18 | 19 | #define _countof(x) (sizeof(x) / sizeof(*x)) 20 | 21 | typedef struct test_s { 22 | const size_t blocksize; 23 | const char* key; 24 | const char* name; 25 | const char* plain; 26 | const char* cipher; 27 | void (*init)(const void *key); 28 | void (*encrypt)(uint32_t*, const uint32_t*); 29 | void (*decrypt)(uint32_t*, const uint32_t*); 30 | } test_t; 31 | 32 | /* wrappers for the stream ciphers */ 33 | 34 | static void arc4_enc128(uint32_t* out, const uint32_t* in) { 35 | uint8_t *o = (uint8_t*)out; 36 | const uint8_t *i = (const uint8_t*)in; 37 | for (int j = 0; j < 16; j++) { 38 | arc4_crypt(o, i); 39 | o++; 40 | i++; 41 | } 42 | } 43 | 44 | static void chaha_init_512(const void* key) { 45 | const uint8_t nonce[] = {0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00}; 46 | chacha_init(key, nonce); 47 | } 48 | 49 | static void chacha_enc_512(uint32_t* out, const uint32_t* in) { 50 | uint8_t *o = (uint8_t*)out; 51 | const uint8_t *i = (const uint8_t*)in; 52 | for (int j = 0; j < 64; j++) { 53 | chacha_crypt(o, i); 54 | o++; 55 | i++; 56 | } 57 | } 58 | 59 | const test_t data[] = { 60 | { 61 | .blocksize = 8, 62 | .name = "RC5-32-12-16 NESSIE-S8V1", 63 | .key = "2B D6 45 9F 82 C5 B3 00 95 2C 49 10 48 81 FF 48", 64 | .plain = "63 8B 3A 5E F7 2B 66 3F", 65 | .cipher = "EA 02 47 14 AD 5C 4D 84", 66 | .init = rc5_init, 67 | .encrypt = rc5_encrypt, 68 | .decrypt = rc5_decrypt, 69 | }, 70 | { 71 | .blocksize = 8, 72 | .name = "SPECK 64/128 Standard", 73 | .key = "00 01 02 03 08 09 0A 0B 10 11 12 13 18 19 1A 1B", 74 | .plain = "2D 43 75 74 74 65 72 3B", 75 | .cipher = "8B 02 4E 45 48 A5 6F 8C", 76 | .init = speck_init, 77 | .encrypt = speck_encrypt, 78 | .decrypt = speck_decrypt, 79 | }, 80 | { 81 | .blocksize = 8, 82 | .name = "XTEA 64/32/128 NOAA-V1(BE32->LE32)", 83 | .key = "03 02 01 00 07 06 05 04 0B 0A 09 08 0F 0E 0D 0C", 84 | .plain = "44 43 42 41 48 47 46 45", 85 | .cipher = "D0 F3 7D 49 B5 2C 61 72", 86 | .init = xtea_init, 87 | .encrypt = xtea_encrypt, 88 | .decrypt = xtea_decrypt, 89 | }, 90 | { 91 | .blocksize = 8, 92 | .name = "XTEA1 64/32/128 Custom", 93 | .key = "01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10", 94 | .plain = "F0 D5 D4 C9 CE F7 CF D2", 95 | .cipher = "8B 3B F4 25 0D 76 EF 2A", 96 | .init = xtea1_init, 97 | .encrypt = xtea1_encrypt, 98 | .decrypt = xtea1_decrypt, 99 | }, 100 | { 101 | .blocksize = 8, 102 | .name = "GOST R 34.12-2015 \"MAGMA\" Standard(BE64->LE64)", 103 | .key = "FF EE DD CC BB AA 99 88 77 66 55 44 33 22 11 00" 104 | "F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF", 105 | .plain = "10 32 54 76 98 BA DC FE", 106 | .cipher = "3D CA D8 C2 E5 01 E9 4E", 107 | .init = gost_init, 108 | .encrypt = gost_encrypt, 109 | .decrypt = gost_decrypt, 110 | }, 111 | { 112 | .blocksize = 8, 113 | .name = "GOST R 34.12-2015 \"MAGMA\" (FIXED) Standard", 114 | .key = "FF EE DD CC BB AA 99 88 77 66 55 44 33 22 11 00" 115 | "F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF", 116 | .plain = "FE DC BA 98 76 54 32 10", 117 | .cipher = "4E E9 01 E5 C2 D8 CA 3D", 118 | .init = magma_init, 119 | .encrypt = magma_encrypt, 120 | .decrypt = magma_decrypt, 121 | }, 122 | { 123 | .blocksize = 8, 124 | .name = "RTEA 64/64/256 Custom", 125 | .key = "01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10" 126 | "FE DC BA 98 76 54 32 10 01 23 45 67 89 AB CD EF", 127 | .plain = "BB 4F 5F E8 D2 FC 01 39", 128 | .cipher = "3D D8 8A BB 2B 5E 41 99", 129 | .init = rtea_init, 130 | .encrypt = rtea_encrypt, 131 | .decrypt = rtea_decrypt, 132 | }, 133 | { 134 | .blocksize = 8, 135 | .name = "RAIDEN 64/16/128 Custom", 136 | .key = "71 0B 18 F0 CA 9F 8E EE 6D B2 0C 5E 6A 91 F8 EC", 137 | .plain = "CF F3 F2 E8 ED C2 EE F0", 138 | .cipher = "D7 D9 0A D8 29 32 A0 0F", 139 | .init = raiden_init, 140 | .encrypt = raiden_encrypt, 141 | .decrypt = raiden_decrypt, 142 | }, 143 | { 144 | .blocksize = 8, 145 | .name = "BLOWFISH 64/16/256 Custom", 146 | .key = "01 23 45 67 89 AB CD EF FE DC BA 98 76 54 32 10" 147 | "FE DC BA 98 76 54 32 10 01 23 45 67 89 AB CD EF", 148 | .plain = "4F F7 6D C5 8D 0D 48 92", 149 | .cipher = "CF F3 F2 E8 ED C2 EE F0", 150 | .init = blowfish_init, 151 | .encrypt = blowfish_encrypt, 152 | .decrypt = blowfish_decrypt, 153 | }, 154 | { 155 | .blocksize = 16, 156 | .name = "RC4 RFC6229 page 8", 157 | .key = "EB B4 62 27 C6 CC 8B 37 64 19 10 83 32 22 77 2A", 158 | .plain = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 159 | .cipher = "72 0C 94 B6 3E DF 44 E1 31 D9 50 CA 21 1A 5A 30", 160 | .init = arc4_init, 161 | .encrypt = arc4_enc128, 162 | .decrypt = arc4_enc128, 163 | }, 164 | { 165 | .blocksize = 64, 166 | .name = "CHACHA-20 RFC7539 page 9", 167 | .key = "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" 168 | "10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F", 169 | .plain = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " 170 | "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " 171 | "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 " 172 | "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 173 | .cipher = "10 F1 E7 E4 D1 3B 59 15 50 0F DD 1F A3 20 71 C4 " 174 | "C7 D1 F4 C7 33 C0 68 03 04 22 AA 9A C3 D4 6C 4E " 175 | "D2 82 64 46 07 9F AA 09 14 C2 D7 05 D9 8B 02 A2 " 176 | "B5 12 9C D1 DE 16 4E B9 CB D0 83 E8 A2 50 3C 4E", 177 | .init = chaha_init_512, 178 | .encrypt = chacha_enc_512, 179 | .decrypt = chacha_enc_512, 180 | }, 181 | { 182 | .blocksize = 16, 183 | .name = "RC6-32/20/16 IETF", 184 | .key = "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F", 185 | .plain = "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F", 186 | .cipher = "3A 96 F9 C7 F6 75 5C FE 46 F0 0E 3D CD 5D 2A 3C", 187 | .init = rc6_init, 188 | .encrypt = rc6_encrypt, 189 | .decrypt = rc6_decrypt, 190 | }, 191 | #if (RIJNDAEL_KEYSIZE == 128) 192 | { 193 | .blocksize = 16, 194 | .name = "AES-128 NIST AESAVS C.1 Vector 2", 195 | .key = "CA EA 65 CD BB 75 E9 16 9E CD 22 EB E6 E5 46 75", 196 | .plain = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 197 | .cipher = "6E 29 20 11 90 15 2D F4 EE 05 81 39 DE F6 10 BB", 198 | .init = rijndael_init, 199 | .encrypt = rijndael_encrypt, 200 | .decrypt = rijndael_decrypt, 201 | }, 202 | { 203 | .blocksize = 16, 204 | .name = "AES-128 FIPS-197", 205 | .key = "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F", 206 | .plain = "00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF", 207 | .cipher = "69 C4 E0 D8 6A 7B 04 30 D8 CD B7 80 70 B4 C5 5A", 208 | .init = rijndael_init, 209 | .encrypt = rijndael_encrypt, 210 | .decrypt = rijndael_decrypt, 211 | }, 212 | #elif (RIJNDAEL_KEYSIZE == 192) 213 | { 214 | .blocksize = 16, 215 | .name = "AES-192 NIST AESAVS C.2 Vector 3", 216 | .key = "A8 A2 82 EE 31 C0 3F AE 4F 8E 9B 89 30 D5 47 3C" 217 | " 2E D6 95 A3 47 E8 8B 7C", 218 | .plain = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 219 | .cipher = "93 F3 27 0C FC 87 7E F1 7E 10 6C E9 38 97 9C B0", 220 | .init = rijndael_init, 221 | .encrypt = rijndael_encrypt, 222 | .decrypt = rijndael_decrypt, 223 | }, 224 | { 225 | .blocksize = 16, 226 | .name = "AES-192 FIPS-197", 227 | .key = "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" 228 | " 10 11 12 13 14 15 16 17", 229 | .plain = "00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF", 230 | .cipher = "DD A9 7C A4 86 4C DF E0 6E AF 70 A0 EC 0D 71 91", 231 | .init = rijndael_init, 232 | .encrypt = rijndael_encrypt, 233 | .decrypt = rijndael_decrypt, 234 | }, 235 | #elif (RIJNDAEL_KEYSIZE == 256) 236 | { 237 | .blocksize = 16, 238 | .name = "AES-256 NIST AESAVS C.3 Vector 1", 239 | .key = "C4 7B 02 94 DB BB EE 0F EC 47 57 F2 2F FE EE 35" 240 | " 87 CA 47 30 C3 D3 3B 69 1D F3 8B AB 07 6B C5 58", 241 | .plain = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 242 | .cipher = "46 F2 FB 34 2D 6F 0A B4 77 47 6F C5 01 24 2C 5F", 243 | .init = rijndael_init, 244 | .encrypt = rijndael_encrypt, 245 | .decrypt = rijndael_decrypt, 246 | }, 247 | { 248 | .blocksize = 16, 249 | .name = "AES-256 FIPS-197", 250 | .key = "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" 251 | " 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F", 252 | .plain = "00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF", 253 | .cipher = "8E A2 B7 CA 51 67 45 BF EA FC 49 90 4B 49 60 89", 254 | .init = rijndael_init, 255 | .encrypt = rijndael_encrypt, 256 | .decrypt = rijndael_decrypt, 257 | }, 258 | #endif 259 | 260 | 261 | 262 | 263 | }; 264 | 265 | size_t strtoba(const char *str, void *buf) { 266 | size_t count = 0; 267 | uint8_t *b = buf; 268 | while (*str) { 269 | int c = *str++; 270 | if (c == ' ') continue; 271 | if (c >= 'a') { 272 | c = c - 'a' + 10; 273 | } else if (c >= 'A') { 274 | c = c - 'A' + 10; 275 | } else { 276 | c = c - '0'; 277 | } 278 | if ((c > 0x0F) || (c < 0)) continue; 279 | if (count++ & 0x01) { 280 | *b++ |= (uint8_t)c; 281 | } else { 282 | *b = (uint8_t)c << 4; 283 | } 284 | } 285 | return count; 286 | } 287 | 288 | void batostr(const void *buf, char *str, size_t count) { 289 | const char *charset = "0123456789ABCDEF"; 290 | const uint8_t *b = buf; 291 | while (count--) { 292 | *str++ = charset[*b >> 4]; 293 | *str++ = charset[*b & 0x0F]; 294 | *str++ = ' '; 295 | b++; 296 | } 297 | *str = '\0'; 298 | } 299 | 300 | 301 | int test(const test_t* algo) { 302 | int ret = 0; 303 | char msg[0x100]; 304 | uint32_t pt[0x80]; 305 | uint32_t ct[0x80]; 306 | uint32_t buf[0x80]; 307 | uint8_t key[0x80]; 308 | 309 | printf("Testing %s ...", algo->name); 310 | 311 | strtoba(algo->plain, pt); 312 | strtoba(algo->cipher, ct); 313 | strtoba(algo->key, key); 314 | 315 | algo->init(key); 316 | algo->encrypt(buf, pt); 317 | if (memcmp(buf, ct, algo->blocksize) != 0) { 318 | batostr(buf, msg, algo->blocksize); 319 | printf("\nEncypt error.\nExpect %s\n Got %s", algo->cipher, msg); 320 | ret = -1; 321 | } 322 | 323 | algo->init(key); 324 | algo->decrypt(buf, ct); 325 | if (memcmp(buf, pt, algo->blocksize) != 0) { 326 | batostr(buf, msg, algo->blocksize); 327 | printf("\nDecrypt error.\nExpect %s\n Got %s", algo->plain, msg); 328 | ret = -1; 329 | } 330 | printf(" %s\n", (ret == 0) ? "PASS" : "\nFAIL"); 331 | return ret; 332 | } 333 | 334 | int main(int argc, char **argv) { 335 | int ret = 0; 336 | for (int i = 0; i < _countof(data); i++) { 337 | ret |= test(&data[i]); 338 | } 339 | return ret; 340 | } -------------------------------------------------------------------------------- /src/descriptors.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include "stm32.h" 20 | #include "config.h" 21 | #include "usb.h" 22 | #include "usb_dfu.h" 23 | #include "usb_msft.h" 24 | 25 | /* Checking for the EEPROM */ 26 | #if (defined(DATA_EEPROM_BASE) || defined(FLASH_EEPROM_BASE)) && (DFU_INTF_EEPROM != _DISABLE) 27 | #define _EEPROM_ENABLED 28 | #endif 29 | 30 | #define _NEXT_IDX (__COUNTER__ + 3) 31 | 32 | /* setting up descriptor indexex */ 33 | #if (DFU_DSC_CONFIG == _ENABLE) && defined(DFU_STR_CONFIG) 34 | #define _CONF_IDX _NEXT_IDX 35 | #else 36 | #define _CONF_IDX NO_DESCRIPTOR 37 | #endif 38 | 39 | #if (DFU_DSC_FLASH == _ENABLE) && defined(DFU_STR_FLASH) 40 | #define _FLASH_IDX _NEXT_IDX 41 | #else 42 | #define _FLASH_IDX NO_DESCRIPTOR 43 | #endif 44 | 45 | #if (DFU_DSC_EEPROM == _ENABLE) && defined(DFU_STR_EEPROM) && defined(_EEPROM_ENABLED) 46 | #define _EEPROM_IDX _NEXT_IDX 47 | #else 48 | #define _EEPROM_IDX NO_DESCRIPTOR 49 | #endif 50 | 51 | #define _countof(a) (sizeof(a)/sizeof(*(a))) 52 | 53 | struct config_desc { 54 | struct usb_config_descriptor config; 55 | struct usb_interface_descriptor flash; 56 | #if defined(_EEPROM_ENABLED) 57 | struct usb_interface_descriptor eeprom; 58 | #endif 59 | struct usb_dfu_func_desc dfufunc; 60 | } __attribute__((packed)); 61 | 62 | static const struct usb_device_descriptor dfu_device_desc = { 63 | .bLength = sizeof (struct usb_device_descriptor), 64 | .bDescriptorType = USB_DTYPE_DEVICE, 65 | .bcdUSB = VERSION_BCD(2,0,0), 66 | .bDeviceClass = USB_CLASS_PER_INTERFACE, 67 | .bDeviceSubClass = USB_SUBCLASS_NONE, 68 | .bDeviceProtocol = USB_PROTO_NONE, 69 | .bMaxPacketSize0 = DFU_EP0_SIZE, 70 | .idVendor = DFU_VENDOR_ID, 71 | .idProduct = DFU_DEVICE_ID, 72 | .bcdDevice = VERSION_BCD(1,0,0), 73 | .iManufacturer = 1, 74 | .iProduct = 2, 75 | .iSerialNumber = INTSERIALNO_DESCRIPTOR, 76 | .bNumConfigurations = 1, 77 | }; 78 | 79 | static const struct config_desc dfu_config_desc = { 80 | .config = { 81 | .bLength = sizeof(struct usb_config_descriptor), 82 | .bDescriptorType = USB_DTYPE_CONFIGURATION, 83 | .wTotalLength = sizeof(struct config_desc), 84 | .bNumInterfaces = 1, 85 | .bConfigurationValue = 1, 86 | .iConfiguration = _CONF_IDX, 87 | .bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, 88 | .bMaxPower = USB_CFG_POWER_MA(100), 89 | }, 90 | .flash = { 91 | .bLength = sizeof(struct usb_interface_descriptor), 92 | .bDescriptorType = USB_DTYPE_INTERFACE, 93 | .bInterfaceNumber = 0, 94 | .bAlternateSetting = 0, 95 | .bNumEndpoints = 0, 96 | .bInterfaceClass = USB_CLASS_DFU, 97 | .bInterfaceSubClass = USB_DFU_SUBCLASS_DFU, 98 | .bInterfaceProtocol = USB_DFU_PROTO_DFU, 99 | .iInterface = _FLASH_IDX, 100 | }, 101 | #if defined(_EEPROM_ENABLED) 102 | .eeprom = { 103 | .bLength = sizeof(struct usb_interface_descriptor), 104 | .bDescriptorType = USB_DTYPE_INTERFACE, 105 | .bInterfaceNumber = 0, 106 | .bAlternateSetting = 1, 107 | .bNumEndpoints = 0, 108 | .bInterfaceClass = USB_CLASS_DFU, 109 | .bInterfaceSubClass = USB_DFU_SUBCLASS_DFU, 110 | .bInterfaceProtocol = USB_DFU_PROTO_DFU, 111 | .iInterface = _EEPROM_IDX, 112 | }, 113 | #endif 114 | .dfufunc = { 115 | .bLength = sizeof(struct usb_dfu_func_desc), 116 | .bDescriptorType = USB_DTYPE_DFU_FUNCTIONAL, 117 | #if (DFU_CAN_UPLOAD == _ENABLE) 118 | .bmAttributes = USB_DFU_ATTR_CAN_DNLOAD | USB_DFU_ATTR_CAN_UPLOAD | USB_DFU_ATTR_MANIF_TOL, 119 | #else 120 | .bmAttributes = USB_DFU_ATTR_CAN_DNLOAD | USB_DFU_ATTR_MANIF_TOL, 121 | #endif 122 | .wDetachTimeout = DFU_DETACH_TIMEOUT, 123 | .wTransferSize = DFU_BLOCKSZ, 124 | .bcdDFUVersion = VERSION_BCD(1,1,0), 125 | }, 126 | }; 127 | 128 | static const struct usb_string_descriptor dfu_lang_sdesc = USB_ARRAY_DESC(USB_LANGID_ENG_US); 129 | static const struct usb_string_descriptor dfu_manuf_sdesc = USB_STRING_DESC(DFU_STR_MANUF); 130 | static const struct usb_string_descriptor dfu_product_sdesc = USB_STRING_DESC(DFU_STR_PRODUCT); 131 | #if (_CONF_IDX != NO_DESCRIPTOR) 132 | static const struct usb_string_descriptor dfu_config_sdesc = USB_STRING_DESC(DFU_STR_CONFIG); 133 | #endif 134 | #if (_FLASH_IDX != NO_DESCRIPTOR) 135 | static const struct usb_string_descriptor dfu_flash_sdesc = USB_STRING_DESC(DFU_STR_FLASH); 136 | #endif 137 | #if (_EEPROM_IDX != NO_DESCRIPTOR) 138 | static const struct usb_string_descriptor dfu_eeprom_sdesc = USB_STRING_DESC(DFU_STR_EEPROM); 139 | #endif 140 | 141 | static const struct usb_string_descriptor * const dtable[] = { 142 | &dfu_lang_sdesc, 143 | &dfu_manuf_sdesc, 144 | &dfu_product_sdesc, 145 | #if (_CONF_IDX != NO_DESCRIPTOR) 146 | &dfu_config_sdesc, 147 | #endif 148 | #if (_FLASH_IDX != NO_DESCRIPTOR) 149 | &dfu_flash_sdesc, 150 | #endif 151 | #if (_EEPROM_IDX != NO_DESCRIPTOR) 152 | &dfu_eeprom_sdesc, 153 | #endif 154 | }; 155 | 156 | #if (DFU_WCID != _DISABLE) 157 | static const struct usb_string_descriptor dfu_msft_sdesc = { 158 | .bLength = 18, 159 | .bDescriptorType = USB_DTYPE_STRING, 160 | .wString = u"MSFT100\x00\x00" 161 | }; 162 | 163 | static const struct usb_msft_compat_id_desc dfu_msft_compat_id_desc = { 164 | .dwLength = (USB_MSFT_COMPAT_ID_HEADER_SIZE + 165 | 1*USB_MSFT_COMPAT_ID_FUNCTION_SECTION_SIZE), 166 | .bcdVersion = 0x0100, 167 | .wIndex = 0x0004, 168 | .bNumSections = 1, 169 | .reserved = { 0, 0, 0, 0, 0, 0, 0 }, 170 | .functions = { 171 | { 172 | .bInterfaceNumber = 0, 173 | .reserved0 = { 1 }, 174 | .compatibleId = "WINUSB", 175 | .subCompatibleId = "", 176 | .reserved1 = { 0, 0, 0, 0, 0, 0} 177 | }, 178 | } 179 | }; 180 | #endif 181 | 182 | usbd_respond dfu_get_descriptor(usbd_ctlreq *req, void **address, uint16_t *len) { 183 | const uint8_t dtype = req->wValue >> 8; 184 | const uint8_t dindx = req->wValue & 0xFF; 185 | const void *desc; 186 | uint16_t dlen = 0; 187 | switch (dtype) { 188 | case USB_DTYPE_DEVICE: 189 | desc = &dfu_device_desc; 190 | break; 191 | case USB_DTYPE_CONFIGURATION: 192 | desc = &dfu_config_desc; 193 | if (*len >= sizeof(dfu_config_desc)) { 194 | dlen = sizeof(dfu_config_desc); 195 | } 196 | break; 197 | case USB_DTYPE_STRING: 198 | if (dindx < _countof(dtable)) { 199 | desc = dtable[dindx]; 200 | #if (DFU_WCID != _DISABLE) 201 | } else if (dindx == 0xEE) { 202 | desc = &dfu_msft_sdesc; 203 | #endif 204 | } else { 205 | return usbd_fail; 206 | } 207 | break; 208 | default: 209 | return usbd_fail; 210 | } 211 | if (dlen == 0) dlen = ((struct usb_string_descriptor*)desc)->bLength; 212 | *len = dlen; 213 | *address = (void*)desc; 214 | return usbd_ack; 215 | } 216 | 217 | #if (DFU_WCID != _DISABLE) 218 | usbd_respond dfu_get_vendor_descriptor(usbd_ctlreq *req, void**address, uint16_t *len) { 219 | if ((req->bmRequestType & USB_REQ_RECIPIENT) == USB_REQ_DEVICE) { 220 | if (req->wIndex == USB_MSFT_REQ_GET_COMPAT_ID_FEATURE_DESCRIPTOR) { 221 | *len = dfu_msft_compat_id_desc.dwLength; 222 | *address = (struct usb_msft_compat_id_desc*)&dfu_msft_compat_id_desc; 223 | return usbd_ack; 224 | } 225 | } 226 | return usbd_fail; 227 | } 228 | #endif 229 | -------------------------------------------------------------------------------- /src/encrypter.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "getopt.h" 21 | #include "config.h" 22 | #include "crypto.h" 23 | #include "checksum.h" 24 | 25 | 26 | typedef struct { 27 | uint16_t bcdDevice; 28 | uint16_t idProduct; 29 | uint16_t idVendor; 30 | uint16_t bcdDFU; 31 | uint8_t ucDfuSignature[3]; 32 | uint8_t bLength; 33 | uint32_t dwCRC; 34 | } __attribute__((packed)) dfu_suffix_t; 35 | 36 | static void exithelp(void) { 37 | printf("Usage: fwcrypt [options] -i infile -o outfile\n" 38 | "\t -e Encrypt (default)\n" 39 | "\t -d Decrypt\n" 40 | "\t -n No output (dry run)\n" 41 | "\t -c Without checksum signature\n" 42 | "\t -C Skip encryption/decryption\n" 43 | "\t -v VID:PID append DFU suffix (encrypt only)\n" 44 | ); 45 | exit(0); 46 | } 47 | 48 | #if (DFU_VERIFY_CHECKSUM != _DISABLE) 49 | static char *strsign(const void *data, size_t len) { 50 | static char s[0x100]; 51 | char *t = s; 52 | static const char *digits = "0123456789ABCDEF"; 53 | const uint8_t *buf = data; 54 | while(len--) { 55 | *t++ = digits[*buf >> 4]; 56 | *t++ = digits[*buf & 0x0F]; 57 | buf++; 58 | } 59 | *t = '\0'; 60 | return s; 61 | } 62 | #endif 63 | 64 | static uint32_t get_vidpid(const char *data) { 65 | unsigned int _vid, _pid; 66 | uint32_t vid, pid; 67 | if (2 == sscanf(data, "%x:%x", &_vid, &_pid)) { 68 | vid = _vid; pid = _pid; 69 | if (vid <= 0xFFFF && pid <= 0xFFFF) { 70 | return vid << 16 | pid; 71 | } 72 | } 73 | return 0; 74 | } 75 | 76 | static const uint32_t crc_table[] = { 77 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 78 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 79 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 80 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 81 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 82 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 83 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 84 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 85 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 86 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 87 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 88 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 89 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 90 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 91 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 92 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 93 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 94 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 95 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 96 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 97 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 98 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 99 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 100 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 101 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 102 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 103 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 104 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 105 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 106 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 107 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 108 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 109 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 110 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 111 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 112 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 113 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 114 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 115 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 116 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 117 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 118 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 119 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; 120 | 121 | 122 | static uint32_t compute_dfu_crc(const void *data, size_t length) { 123 | const uint8_t *src = data; 124 | uint32_t crc = 0xFFFFFFFFU; 125 | while(length--) { 126 | crc = crc_table[0xFFU & (crc ^ *src++)] ^ (crc >> 8); 127 | } 128 | return crc; 129 | } 130 | 131 | 132 | int main(int argc, char **argv) 133 | { 134 | int dir = 1; 135 | int crc = 1; 136 | int dry = 0; 137 | int enc = 1; 138 | char *infile = NULL; 139 | char *outfile = NULL; 140 | int c; 141 | uint32_t vidpid = 0; 142 | 143 | opterr = 0; 144 | 145 | while ((c = getopt(argc, argv, "edchnCi:o:v:")) != -1) 146 | switch (c) 147 | { 148 | case 'C': 149 | enc = 0; 150 | break; 151 | case 'e': 152 | dir = 1; 153 | break; 154 | case 'd': 155 | dir = 0; 156 | break; 157 | case 'c': 158 | crc = 0; 159 | break; 160 | case 'n': 161 | dry = 1; 162 | break; 163 | case 'i': 164 | infile = optarg; 165 | break; 166 | case 'o': 167 | outfile = optarg; 168 | break; 169 | case 'v': 170 | vidpid = get_vidpid(optarg); 171 | if (vidpid == 0) { 172 | printf("Error parsing VID:PID :\"%s\"\n", optarg); 173 | exit(-1); 174 | } 175 | break; 176 | case 'h': 177 | case '?': 178 | exithelp(); 179 | break; 180 | default: 181 | exit(-1); 182 | } 183 | 184 | if (infile == NULL) { 185 | exithelp(); 186 | } 187 | 188 | if (!enc && !crc) { 189 | printf("Nothing to do. Exiting.\n"); 190 | exit(0); 191 | } 192 | 193 | FILE *fi = fopen(infile, "rb"); 194 | if (fi == NULL) { 195 | printf("Failed to open file: %s\n", argv[optind]); 196 | exit(1); 197 | } 198 | 199 | fseek(fi, 0, SEEK_END); 200 | size_t length = ftell(fi); 201 | fseek(fi, 0, SEEK_SET); 202 | 203 | 204 | size_t blen = length + 0x1000; 205 | uint32_t *buf = malloc(blen); 206 | #if (DFU_VERIFY_CHECKSUM != _DISABLE) 207 | uint8_t *buf8 = (uint8_t*)buf; 208 | #endif 209 | 210 | if (buf == NULL) { 211 | printf("Failed to allocate buffer. length %zd\n", blen); 212 | exit(3); 213 | } 214 | 215 | if (length != fread(buf, 1, length, fi)) { 216 | printf("Failed to read input file."); 217 | exit(4); 218 | } 219 | fclose(fi); 220 | 221 | aes_init(); 222 | if (dir) { 223 | #if (DFU_VERIFY_CHECKSUM != _DISABLE) 224 | if (crc) { 225 | size_t newlen = append_checksum(buf, length, blen); 226 | 227 | printf("Firmware length: %zd bytes, signature: (%s) %s\n", 228 | length, 229 | checksum_name, 230 | strsign(&buf8[length], checksum_length) 231 | ); 232 | 233 | printf("Validating firmware signature. "); 234 | size_t checked_length = validate_checksum(buf, blen); 235 | 236 | if (checked_length != length ) { 237 | printf("FAIL. Collision found at offset %zd\n", checked_length); 238 | exit(-3); 239 | } else { 240 | printf("OK.\n"); 241 | } 242 | length = newlen; 243 | } 244 | #endif 245 | 246 | #if(DFU_CIPHER != _DISABLE) 247 | if (enc) { 248 | if (length % aes_blksize) { 249 | length += (aes_blksize - (length % aes_blksize)); 250 | } 251 | printf("Encrypting %zd bytes using %s cipher.\n", length, aes_name); 252 | aes_encrypt(buf, buf, length); 253 | } else { 254 | printf("Skipping encryption.\n"); 255 | } 256 | #endif 257 | 258 | if (vidpid != 0) { 259 | printf("Appending DFU suffix\n"); 260 | dfu_suffix_t *dfu_suffix = (void*)(&((uint8_t*)buf)[length]); 261 | length += sizeof(dfu_suffix_t); 262 | dfu_suffix->bcdDevice = 0xFFFF; 263 | dfu_suffix->idProduct = vidpid; 264 | dfu_suffix->idVendor = vidpid >> 16; 265 | dfu_suffix->bcdDFU = 0x0101; 266 | dfu_suffix->ucDfuSignature[0] = 'U'; 267 | dfu_suffix->ucDfuSignature[1] = 'F'; 268 | dfu_suffix->ucDfuSignature[2] = 'D'; 269 | dfu_suffix->bLength = 16; 270 | dfu_suffix->dwCRC = compute_dfu_crc(buf, length - 4); 271 | } 272 | 273 | } else { 274 | 275 | #if(DFU_CIPHER != _DISABLE) 276 | if (enc) { 277 | printf("Decrypting %zd bytes using %s cipher.\n", length, aes_name); 278 | aes_decrypt(buf, buf, length); 279 | } else { 280 | printf("Skipping decryption.\n"); 281 | } 282 | #endif 283 | 284 | #if (DFU_VERIFY_CHECKSUM != _DISABLE) 285 | if (crc) { 286 | size_t checked_length = validate_checksum(buf, blen); 287 | if (checked_length == 0) { 288 | printf("No valid signature found.\n"); 289 | } else { 290 | printf("Valid signature (%s) %s found at offset %zd\n", 291 | checksum_name, 292 | strsign(&buf8[checked_length], checksum_length), 293 | checked_length 294 | ); 295 | length = checked_length; 296 | } 297 | } 298 | #endif 299 | 300 | } 301 | if (dry || outfile == NULL) { 302 | printf("Writing %zd bytes. Dry run.\n", length); 303 | } else { 304 | FILE *fo = fopen(outfile, "wb"); 305 | if (fo == NULL) { 306 | printf("Failed to open file: %s\n", argv[optind]); 307 | exit(2); 308 | } 309 | 310 | fwrite(buf, 1, length, fo); 311 | fclose(fo); 312 | } 313 | free(buf); 314 | return 0; 315 | } 316 | -------------------------------------------------------------------------------- /src/gost.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * GOST R 34.12-2015 "MAGMA" CBC block cipher implementation based on 4 | * official GOST R 34.12-2015 national standard of the Russian Federation 5 | * 6 | * Copyright ©2016 Dmitry Filimonchuk 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include "misc.h" 21 | #include "gost.h" 22 | 23 | #define rounds 32 24 | 25 | static uint32_t RK[32]; 26 | 27 | static const uint32_t S[] = { 28 | 0xC6BC7581, 0x4838FDE7, 0x62525F2E, 0x2381A65D, 29 | 0xA92D8960, 0x5AF41295, 0xB5AF6C18, 0x9CD6DAC3, 30 | 0xE1E70BF4, 0x8E10974F, 0xD47A38BA, 0x7745E106, 31 | 0x0BC3B4D9, 0x3D9E43AC, 0xF0692E3B, 0x1F0BC072, 32 | }; 33 | 34 | #pragma GCC diagnostic push 35 | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 36 | static uint32_t sbox(uint32_t in) { 37 | uint32_t out; 38 | for(int i = 0; i < 8; i++) { 39 | out <<= 4; 40 | out += (S[in >> 28] >> (i * 4)) & 0x0F; 41 | in <<= 4; 42 | } 43 | return out; 44 | } 45 | #pragma GCC diagnostic pop 46 | 47 | 48 | static uint32_t F(uint32_t data, uint32_t round) { 49 | return __rol32(sbox(data + RK[round]), 11); 50 | } 51 | 52 | void gost_encrypt(uint32_t *out, const uint32_t *in) { 53 | uint32_t A = in[0]; 54 | uint32_t B = in[1]; 55 | for (int i = 0; i < rounds; i++) { 56 | uint32_t A1 = B ^ F(A, i); 57 | B = A; 58 | A = A1; 59 | } 60 | out[0] = B; 61 | out[1] = A; 62 | } 63 | 64 | void gost_decrypt(uint32_t *out, const uint32_t *in) { 65 | uint32_t A = in[0]; 66 | uint32_t B = in[1]; 67 | for (int i = 31; i >= 0; i--) { 68 | uint32_t A1 = B ^ F(A, i); 69 | B = A; 70 | A = A1; 71 | } 72 | out[0] = B; 73 | out[1] = A; 74 | } 75 | 76 | void gost_init(const void* key){ 77 | const uint8_t *K = key; 78 | for (int i = 0; i < 8; i++) { 79 | RK[i] = K[4*i] << 24 | K[4*i+1] << 16 | K[4*i+2] << 8 | K[4*i+3]; 80 | RK[8+i] = RK[i]; 81 | RK[16+i] = RK[i]; 82 | RK[31-i] = RK[i]; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/magma.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * GOST R 34.12-2015 "MAGMA" block cipher implementation based on 4 | * official GOST R 34.12-2015 national standard of the Russian Federation 5 | * 6 | * Copyright ©2016 Dmitry Filimonchuk 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include "misc.h" 22 | #include "magma.h" 23 | 24 | #define rounds 32 25 | 26 | static uint32_t RK[32]; 27 | 28 | static const uint32_t S[] = { 29 | 0xC6BC7581, 0x4838FDE7, 0x62525F2E, 0x2381A65D, 30 | 0xA92D8960, 0x5AF41295, 0xB5AF6C18, 0x9CD6DAC3, 31 | 0xE1E70BF4, 0x8E10974F, 0xD47A38BA, 0x7745E106, 32 | 0x0BC3B4D9, 0x3D9E43AC, 0xF0692E3B, 0x1F0BC072, 33 | }; 34 | 35 | #pragma GCC diagnostic push 36 | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 37 | static uint32_t sbox(uint32_t in) { 38 | uint32_t out; 39 | for(int i = 0; i < 8; i++) { 40 | out <<= 4; 41 | out += (S[in >> 28] >> (i * 4)) & 0x0F; 42 | in <<= 4; 43 | } 44 | return out; 45 | } 46 | #pragma GCC diagnostic pop 47 | 48 | 49 | static uint32_t F(uint32_t data, uint32_t round) { 50 | return __rol32(sbox(data + RK[round]), 11); 51 | } 52 | 53 | void magma_encrypt(uint32_t *out, const uint32_t *in) { 54 | uint32_t A = BE32TOCPU(in[1]); 55 | uint32_t B = BE32TOCPU(in[0]); 56 | for (int i = 0; i < rounds; i++) { 57 | uint32_t A1 = B ^ F(A, i); 58 | B = A; 59 | A = A1; 60 | } 61 | out[1] = CPUTOBE32(B); 62 | out[0] = CPUTOBE32(A); 63 | } 64 | 65 | void magma_decrypt(uint32_t *out, const uint32_t *in) { 66 | uint32_t A = BE32TOCPU(in[1]); 67 | uint32_t B = BE32TOCPU(in[0]); 68 | for (int i = 31; i >= 0; i--) { 69 | uint32_t A1 = B ^ F(A, i); 70 | B = A; 71 | A = A1; 72 | } 73 | out[1] = CPUTOBE32(B); 74 | out[0] = CPUTOBE32(A); 75 | } 76 | 77 | void magma_init(const void* key){ 78 | for (int i = 0; i < 8; i++) { 79 | uint32_t K; 80 | memcpy(&K, key, sizeof(K)); 81 | K = BE32TOCPU(K); 82 | RK[0x00 + i] = K; 83 | RK[0x08 + i] = K; 84 | RK[0x10 + i] = K; 85 | RK[0x1F - i] = K; 86 | key += 4; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/raiden.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Raiden-CBC block cipher implementation based on original code developed by 4 | * Julio César Hernández Castro and Javier Polimón Olabarrieta 5 | * https://sourceforge.net/projects/raiden-cipher/ 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include "raiden.h" 23 | 24 | static uint32_t subkey[0x10]; 25 | 26 | void raiden_encrypt(uint32_t *out, const uint32_t *in) { 27 | uint32_t b0 = in[0]; 28 | uint32_t b1 = in[1]; 29 | for (int i = 0; i < 16; i++ ) { 30 | uint32_t sk = subkey[i]; 31 | b0 += ((sk+b1)<<9) ^ ((sk-b1)^((sk+b1)>>14)); 32 | b1 += ((sk+b0)<<9) ^ ((sk-b0)^((sk+b0)>>14)); 33 | } 34 | out[0] = b0; 35 | out[1] = b1; 36 | } 37 | 38 | void raiden_decrypt(uint32_t *out, const uint32_t *in) { 39 | uint32_t b0 = in[0]; 40 | uint32_t b1 = in[1]; 41 | for (int i = 15; i >= 0; i--) { 42 | uint32_t sk = subkey[i]; 43 | b1 -= ((sk+b0)<<9) ^ ((sk-b0)^((sk+b0)>>14)); 44 | b0 -= ((sk+b1)<<9) ^ ((sk-b1)^((sk+b1)>>14)); 45 | } 46 | out[0] = b0; 47 | out[1] = b1; 48 | } 49 | 50 | void raiden_init(const void* key) { 51 | uint32_t k[4]; 52 | memcpy(k, key, sizeof(k)); 53 | for (int i = 0; i < 16; i++) { 54 | uint32_t sk = ((k[0]+k[1])+((k[2]+k[3])^(k[0]<<(k[2] & 0x1F)))); 55 | k[i & 0x03] = sk; 56 | subkey[i] = sk; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/rc5.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * RC5-32/12/128-CBC block cipher implementation based on 4 | * Ronald L. Rivest "The RC5 Encryption Algorithm" 5 | * http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include "misc.h" 23 | #include "rc5.h" 24 | 25 | #define rounds 12 26 | #define c 4 27 | #define t 2 * (rounds + 1) 28 | 29 | #define Pw 0xb7e15163 30 | #define Qw 0x9e3779b9 31 | 32 | static uint32_t rc5_keys[t]; 33 | 34 | void rc5_encrypt (uint32_t *out, const uint32_t *in) { 35 | uint32_t A = in[0] + rc5_keys[0]; 36 | uint32_t B = in[1] + rc5_keys[1]; 37 | for (int i = 1; i <= rounds; i++) { 38 | A = __rol32((A ^ B), B) + rc5_keys[2 * i]; 39 | B = __rol32((B ^ A), A) + rc5_keys[2 * i + 1]; 40 | } 41 | out[0] = A; 42 | out[1] = B; 43 | } 44 | 45 | void rc5_decrypt (uint32_t *out, const uint32_t *in) { 46 | uint32_t A = in[0]; 47 | uint32_t B = in[1]; 48 | for (int i = rounds; i > 0; i--) { 49 | B = __ror32((B - rc5_keys[2 * i + 1]), A) ^ A; 50 | A = __ror32((A - rc5_keys[2 * i]), B) ^ B; 51 | } 52 | out[0] = A - rc5_keys[0]; 53 | out[1] = B - rc5_keys[1]; 54 | } 55 | 56 | void rc5_init (const void* key) { 57 | uint32_t L[4]; 58 | memcpy(L, key, 16); 59 | rc5_keys[0] = Pw; 60 | for (int i = 1; i < t; i++){ 61 | rc5_keys[i] = rc5_keys[i-1] + Qw; 62 | } 63 | for (uint32_t A = 0, B = 0, i = 0, j = 0, k = 3 * t; k > 0; k--) { 64 | A = rc5_keys[i] = __rol32(rc5_keys[i] + A + B, 3); 65 | B = L[j] = __rol32(L[j] + A + B, (A + B)); 66 | if (++i == t) i = 0; 67 | if (++j == c) j = 0; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/rc5a.S: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * RC5-32/12/128-CBC block cipher implementation based on 4 | * Ronald L. Rivest "The RC5 Encryption Algorithm" 5 | * http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | //#include "config.h" 21 | 22 | #define R 12 23 | #define T 2 * (R + 1) 24 | #define C 4 25 | #define PW 0xB7E15163 26 | #define QW 0x9E3779B9 27 | 28 | .syntax unified 29 | .cpu cortex-m0plus 30 | .thumb 31 | .section .text 32 | 33 | .globl _rc5_init 34 | .thumb_func 35 | .type _rc5_init, %function 36 | /* R0 <- key array 37 | */ 38 | _rc5_init: 39 | push {r4,r5,r6,r7, lr} 40 | sub sp, #0x14 41 | mov r2, sp 42 | /* copy key to L */ 43 | movs r1, #0x10 44 | .L_copy_key: 45 | subs r1, #0x01 46 | ldrb r3, [r0, r1] 47 | strb r3, [r2, r1] 48 | bne .L_copy_key 49 | /* R2 <- L[0] */ 50 | /* prepare S. Fill keyset */ 51 | ldr r0, =_rc5_keyset 52 | ldr r1, =#PW 53 | ldr r3, =#QW 54 | movs r4, #0x00 55 | .L_fill_keyset: 56 | str r1, [r0, r4] 57 | add r1, r3 58 | adds r4, #0x04 59 | cmp r4, #(T * 4) 60 | bne .L_fill_keyset 61 | /* mixing keyset */ 62 | /* R0 = S[0] */ 63 | /* R2 = L[0] */ 64 | /* R1 = counter */ 65 | /* R3 = A */ 66 | /* R4 = B */ 67 | /* R5 = TEMP */ 68 | /* R6 = i */ 69 | /* R7 = j */ 70 | movs r1, #(T * 3) 71 | movs r3, #0x00 72 | movs r4, #0x00 73 | movs r6, #0x00 74 | movs r7, #0x00 75 | .L_mix_keys: 76 | ldr r5, [r0, r6] 77 | add r3, r3, r4 //R3 <- A + B 78 | add r3, r5 //R3 <- S[i] + A + B 79 | movs r5, #29 80 | rors r3, r5 //R3 <- (S[i] + A + B) <<< 3 81 | str r3, [r0, r6] //A' -> S[i] 82 | adds r5, r4, r3 //R5 <- (A' + B) 83 | ldr r4, [r2, r7] 84 | add r4, r5 //R4 <- L[j] + A' + B 85 | rsbs r5, r5, #0 //R5 <- 0 - (A' + B) 86 | rors r4, r5 //R4 <- (L[j] + A' + B) <<< (A' + B) 87 | str r4, [r2, r7] //L[j] <- B' 88 | ldr r3, [r0, r6] //restore A' 89 | adds r6, #0x04 90 | cmp r6, #(T * 4) 91 | bne .L_chk_c 92 | movs r6, #0x00 93 | .L_chk_c: 94 | adds r7, #0x04 95 | cmp r7, #(C * 4) 96 | bne .L_chk_counter 97 | movs r7, #0x00 98 | .L_chk_counter: 99 | subs r1, #0x01 100 | bne .L_mix_keys 101 | add sp, #0x14 102 | pop {r4, r5, r6, r7, pc} 103 | .size _rc5_init, . - _rc5_init 104 | 105 | 106 | 107 | /* R0 <- destination pointer 108 | * R1 <- source pointer 109 | * R2 <- unused 110 | * R3 = A 111 | * R4 = B 112 | * R5 = S[] 113 | * R6 = rounds 114 | * R7 = TEMP 115 | */ 116 | .globl _rc5_encrypt 117 | .type _rc5_encrypt, %function 118 | .thumb_func 119 | _rc5_encrypt: 120 | push {r4, r5, r6, r7, lr} 121 | ldr r3, [r1] //A 122 | ldr r4, [r1, #0x04] //B 123 | /* start RC5 block */ 124 | ldr r5, =_rc5_keyset 125 | ldr r7, [r5] 126 | add r3, r7 //A + S[0] 127 | ldr r7, [r5, #0x04] 128 | add r4, r7 //B + S[1] 129 | movs r6, #0x08 130 | .L_enc_roundloop: 131 | eors r3, r4 //A ^ B 132 | rsbs r7, r4, #0x00 133 | rors r3, r7 // (A ^ B) >>> B 134 | ldr r7, [r5, r6] //R7 <- S[2*i] 135 | add r3, r7 // A' = ((A ^ B) <<< B) + S[2*i] 136 | eors r4, r3 // B ^ A' 137 | rsbs r7, r3, #0x00 138 | rors r4, r7 // (B ^ A') >>> A' 139 | adds r6, #0x04 140 | ldr r7, [r5, r6] //R7 <- S[2 * i + 1] 141 | add r4, r7 // B' = ((B ^ A') <<< A') + S[2*i +1] 142 | adds r6, #0x04 143 | cmp r6, #(T * 4) 144 | bne .L_enc_roundloop 145 | /* store encrypted */ 146 | str r3, [r0] 147 | str r4, [r0, #0x04] 148 | pop {r4, r5, r6, r7, pc} 149 | .size _rc5_encrypt, . - _rc5_encrypt 150 | 151 | 152 | .globl _rc5_decrypt 153 | .type _rc5_decrypt, %function 154 | .thumb_func 155 | _rc5_decrypt: 156 | push {r4, r5, r6, r7, lr} 157 | ldr r5, =_rc5_keyset 158 | ldr r3, [r1] //A 159 | ldr r4, [r1, #0x04] //B 160 | movs r6, #(T * 4 - 4) 161 | .L_dec_roundloop: 162 | ldr r7, [r5, r6] //R7 <- S[2*i - 1] 163 | subs r4, r7 //R4 <- B - S[2*i + 1] 164 | rors r4, r3 //R4 <- (B - S[2*i +1]) >>> A 165 | eors r4, r3 //R4 <- B' = ((B - S[2*i +1]) >>> A) ^ A 166 | subs r6, #0x04 167 | ldr r7, [r5, r6] //R7 <- S[2*i] 168 | subs r3, r7 //R3 <- (A - S[2*i]) 169 | rors r3, r4 //R3 <- (A - S[2*i]) >>> B') 170 | eors r3, r4 //R3 <- A' = (A - S[2*i]) >>> B') ^ B' 171 | subs r6, #0x04 172 | cmp r6, #0x04 173 | bne .L_dec_roundloop 174 | ldr r7, [r5, #0x04] 175 | subs r4, r7 176 | ldr r7, [r5, #0x00] 177 | subs r3, r7 178 | str r3, [r0, #0x00] 179 | str r4, [r0, #0x04] 180 | pop {r4, r5, r6, r7, pc} 181 | .size _rc5_decrypt, . - _rc5_decrypt 182 | 183 | .pool 184 | 185 | .section .bss 186 | .align 3 187 | _rc5_keyset: 188 | .space (T * 4) 189 | 190 | .end 191 | -------------------------------------------------------------------------------- /src/rc6.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * RC6-32/20/16 block cipher implementation based on 4 | * RonaldL.Rivest ,M.J.B.Robshaw ,R.Sidney ,andY.L.Yin "The RC6(TM) Block Cipher" 5 | * http://people.csail.mit.edu/rivest/pubs/RRSY98.pdf 6 | * 7 | * Copyright ©2020 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include "misc.h" 23 | #include "rc6.h" 24 | 25 | #define ROUNDS 20 26 | #define KW 4 27 | #define SW 2 * (ROUNDS + 2) 28 | #define LOGW 5 29 | 30 | #define Pw 0xb7e15163 31 | #define Qw 0x9e3779b9 32 | 33 | static uint32_t RK[SW]; 34 | 35 | void rc6_encrypt (uint32_t *out, const uint32_t *in) { 36 | uint32_t A = in[0]; 37 | uint32_t B = in[1] + RK[0]; 38 | uint32_t C = in[2]; 39 | uint32_t D = in[3] + RK[1]; 40 | for (int i = 2; i <= 2 * ROUNDS; i += 2) { 41 | uint32_t t, u; 42 | t = __rol32(B * (B + B + 1), LOGW); 43 | u = __rol32(D * (D + D + 1), LOGW); 44 | A = __rol32((A ^ t), u) + RK[i]; 45 | C = __rol32((C ^ u), t) + RK[i + 1]; 46 | t = A; 47 | A = B; 48 | B = C; 49 | C = D; 50 | D = t; 51 | } 52 | out[0] = A + RK[2 * ROUNDS + 2]; 53 | out[1] = B; 54 | out[2] = C + RK[2 * ROUNDS + 3]; 55 | out[3] = D; 56 | } 57 | 58 | void rc6_decrypt (uint32_t *out, const uint32_t *in) { 59 | uint32_t A = in[0] - RK[2 * ROUNDS + 2]; 60 | uint32_t B = in[1]; 61 | uint32_t C = in[2] - RK[2 * ROUNDS + 3]; 62 | uint32_t D = in[3]; 63 | for (int i = 2 * ROUNDS; i > 0; i -= 2) { 64 | uint32_t t, u; 65 | t = D; 66 | D = C; 67 | C = B; 68 | B = A; 69 | A = t; 70 | u = __rol32(D * (D + D + 1), LOGW); 71 | t = __rol32(B * (B + B + 1), LOGW); 72 | C = __ror32((C - RK[i + 1]), t) ^ u; 73 | A = __ror32((A - RK[i]), u) ^ t; 74 | } 75 | out[0] = A; 76 | out[1] = B - RK[0]; 77 | out[2] = C; 78 | out[3] = D - RK[1]; 79 | } 80 | 81 | void rc6_init (const void* key) { 82 | uint32_t L[KW]; 83 | memcpy(L, key, sizeof(L)); 84 | RK[0] = Pw; 85 | for (int i = 1; i < SW; i++){ 86 | RK[i] = RK[i-1] + Qw; 87 | } 88 | for (uint32_t A = 0, B = 0, i = 0, j = 0, k = 3 * SW; k > 0; k--) { 89 | A = RK[i] = __rol32(RK[i] + A + B, 3); 90 | B = L[j] = __rol32(L[j] + A + B, (A + B)); 91 | if (++i == SW) i = 0; 92 | if (++j == KW) j = 0; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/rc6a.S: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * RC6-32/20/16 block cipher implementation based on 4 | * RonaldL.Rivest ,M.J.B.Robshaw ,R.Sidney ,andY.L.Yin "The RC6(TM) Block Cipher" 5 | * http://people.csail.mit.edu/rivest/pubs/RRSY98.pdf 6 | * 7 | * Copyright ©2020 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #define ROUNDS 20 21 | #define T 2 * (ROUNDS + 2) 22 | #define C 4 23 | #define PW 0xB7E15163 24 | #define QW 0x9E3779B9 25 | 26 | .syntax unified 27 | .cpu cortex-m0plus 28 | .thumb 29 | 30 | .section .text.rc6a_init 31 | .globl rc6a_init 32 | .thumb_func 33 | .type rc6a_init, %function 34 | /* R0 <- key array 35 | */ 36 | rc6a_init: 37 | push {r4,r5,r6,r7, lr} 38 | sub sp, #0x14 39 | mov r2, sp 40 | /* copy key to L */ 41 | movs r1, #0x10 42 | .L_copy_key: 43 | subs r1, #0x01 44 | ldrb r3, [r0, r1] 45 | strb r3, [r2, r1] 46 | bne .L_copy_key 47 | /* R2 <- L[0] */ 48 | /* prepare S. Fill keyset */ 49 | ldr r0, =rc6_subkeys 50 | ldr r1, =#PW 51 | ldr r3, =#QW 52 | movs r4, #0x00 53 | .L_fill_keyset: 54 | str r1, [r0, r4] 55 | add r1, r3 56 | adds r4, #0x04 57 | cmp r4, #(T * 4) 58 | bne .L_fill_keyset 59 | /* mixing keyset */ 60 | /* R0 = S[0] */ 61 | /* R2 = L[0] */ 62 | /* R1 = counter */ 63 | /* R3 = A */ 64 | /* R4 = B */ 65 | /* R5 = TEMP */ 66 | /* R6 = i */ 67 | /* R7 = j */ 68 | movs r1, #(T * 3) 69 | movs r3, #0x00 70 | movs r4, #0x00 71 | movs r6, #0x00 72 | movs r7, #0x00 73 | .L_mix_keys: 74 | ldr r5, [r0, r6] 75 | add r3, r3, r4 //R3 <- A + B 76 | add r3, r5 //R3 <- S[i] + A + B 77 | movs r5, #29 78 | rors r3, r5 //R3 <- (S[i] + A + B) <<< 3 79 | str r3, [r0, r6] //A' -> S[i] 80 | adds r5, r4, r3 //R5 <- (A' + B) 81 | ldr r4, [r2, r7] 82 | add r4, r5 //R4 <- L[j] + A' + B 83 | rsbs r5, r5, #0 //R5 <- 0 - (A' + B) 84 | rors r4, r5 //R4 <- (L[j] + A' + B) <<< (A' + B) 85 | str r4, [r2, r7] //L[j] <- B' 86 | adds r6, #0x04 87 | cmp r6, #(T * 4) 88 | bne .L_chk_c 89 | movs r6, #0x00 90 | .L_chk_c: 91 | adds r7, #0x04 92 | cmp r7, #(C * 4) 93 | bne .L_chk_counter 94 | movs r7, #0x00 95 | .L_chk_counter: 96 | subs r1, #0x01 97 | bne .L_mix_keys 98 | add sp, #0x14 99 | pop {r4, r5, r6, r7, pc} 100 | .size rc6a_init, . - rc6a_init 101 | .pool 102 | 103 | 104 | /* R0 <- destination pointer 105 | * R1 <- source pointer 106 | */ 107 | .section .text.rc6a_encrypt 108 | .globl rc6a_encrypt 109 | .type rc6a_encrypt, %function 110 | .thumb_func 111 | rc6a_encrypt: 112 | push {r4-r7, lr} 113 | // A->R2, B->R3, C->R4, D->R5 114 | ldmia r1!, {r2,r3,r4,r5} 115 | ldr r1, =rc6_subkeys 116 | // B = B + S[0] 117 | ldmia r1!,{r6,r7} 118 | adds r3, r6 119 | // D = D + S[1] 120 | adds r5, r7 121 | movs r6, #ROUNDS 122 | .L_enc_round: 123 | push {r0, r1} 124 | // R0 t = (B*(2B + 1)) <<< 5 125 | movs r7, #27 126 | adds r0, r3, r3 127 | adds r0, #1 128 | muls r0, r3 129 | rors r0, r7 130 | // R1 u = (D*(2D + 1)) <<< 5 131 | adds r1, r5, r5 132 | adds r1, #1 133 | muls r1, r5 134 | rors r1, r7 135 | // A = ((A ^ t) <<< u) 136 | eors r2, r0 137 | rsbs r7, r1, #0 138 | rors r2, r7 139 | // C = ((C ^ u) <<< t) 140 | eors r4, r1 141 | rsbs r7, r0, #0 142 | rors r4, r7 143 | pop {r0, r1} 144 | // A = A + SK[2i] 145 | ldmia r1!, {r7} 146 | adds r2, r7 147 | // C = C + S[2i+1] 148 | ldmia r1!, {r7} 149 | adds r4, r7 150 | //(A,B,C,D) = (B,C,D,A) 151 | movs r7, r2 152 | movs r2, r3 153 | movs r3, r4 154 | movs r4, r5 155 | movs r5, r7 156 | subs r6, #0x01 157 | bne .L_enc_round 158 | // A = A + S[2R + 2] C = C + S[2R + 3] 159 | ldmia r1!, {r6,r7} 160 | add r2, r6 161 | add r4, r7 162 | //store outputs 163 | stmia r0!, {r2-r5} 164 | pop {r4-r7, pc} 165 | .size rc6a_encrypt, . - rc6a_encrypt 166 | .pool 167 | 168 | .section .text.rc6a_decrypt 169 | .globl rc6a_decrypt 170 | .type rc6a_decrypt, %function 171 | .thumb_func 172 | rc6a_decrypt: 173 | push {r4-r7, lr} 174 | // A->R2, B->R3, C->R4, D->R5 175 | ldmia r1!, {r2,r3,r4,r5} 176 | ldr r1, =(rc6_subkeys + 8 * ROUNDS) 177 | // A = A - S[2R + 2] 178 | ldr r7, [r1, #0x08] 179 | subs r2, r7 180 | // C = C - S[2R + 2] 181 | ldr r7, [r1, #0x0C] 182 | subs r4, r7 183 | movs r6, #ROUNDS 184 | .L_dec_round: 185 | // subs r1, #0x08 186 | //(A,B,C,D) = (D,A,B,C) 187 | movs r7, r5 188 | movs r5, r4 189 | movs r4, r3 190 | movs r3, r2 191 | movs r2, r7 192 | // A = A - S[2i] 193 | ldr r7, [r1, #0x00] 194 | subs r2, r7 195 | // C = C - S[2i+1] 196 | ldr r7, [r1, #0x04] 197 | subs r4, r7 198 | push {r0, r1} 199 | // R0 t = (B*(2B + 1)) <<< 5 200 | movs r7, #27 201 | adds r0, r3, r3 202 | adds r0, 1 203 | muls r0, r3 204 | rors r0, r7 205 | // R1 u = (D*(2D + 1)) <<< 5 206 | adds r1, r5, r5 207 | adds r1, 1 208 | muls r1, r5 209 | rors r1, r7 210 | // A = (A >>> u) ^ t 211 | rors r2, r1 212 | eors r2, r0 213 | // C = (C >> t) ^ u 214 | rors r4, r0 215 | eors r4, r1 216 | pop {r0, r1} 217 | subs r1, #0x08 218 | subs r6, #0x01 219 | bne .L_dec_round 220 | ldmia r1!,{r6,r7} 221 | // B = B + S[0] 222 | subs r3, r6 223 | // D = D + S[1] 224 | subs r5, r7 225 | 226 | stmia r0!, {r2-r5} 227 | pop {r4-r7, pc} 228 | .size rc6a_decrypt, . - rc6a_decrypt 229 | .pool 230 | 231 | .section .bss 232 | .align 2 233 | rc6_subkeys: 234 | .space (T * 4) 235 | .size rc6_subkeys, . - rc6_subkeys 236 | .end 237 | -------------------------------------------------------------------------------- /src/rijndael.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Rijndael AES-128/192/256 4 | * 5 | * Copyright ©2020 Dmitry Filimonchuk 6 | * Based on: https://github.com/kokke/tiny-AES-c 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include "rijndael.h" 22 | #include "misc.h" 23 | 24 | #if (RIJNDAEL_KEYSIZE == 128) 25 | #define ROUNDS 10 // The number of rounds in AES Cipher. 26 | #elif (RIJNDAEL_KEYSIZE == 192) 27 | #define ROUNDS 12 28 | #elif (RIJNDAEL_KEYSIZE == 256) 29 | #define ROUNDS 14 30 | #else 31 | #error "Unsupported AES key size" 32 | #endif 33 | 34 | #define KEYSIZE (RIJNDAEL_KEYSIZE / 8) 35 | #define KEYSIZE32 (RIJNDAEL_KEYSIZE / 32) 36 | #define RKSIZE32 (4 * (ROUNDS + 1)) 37 | 38 | // state - array holding the intermediate results during decryption. 39 | typedef uint8_t state_t[4][4]; 40 | 41 | // Roundkey storage 42 | static uint32_t roundkey[RKSIZE32]; 43 | 44 | // Basic GF2 math 45 | static uint8_t gmul2(uint8_t x) { 46 | if (x & 0x80) { 47 | return (x << 1) ^ 0x1B; 48 | } else { 49 | return (x << 1); 50 | } 51 | } 52 | 53 | #define gmul4(x) gmul2(gmul2(x)) 54 | #define gmul8(x) gmul2(gmul4(x)) 55 | 56 | #if (RIJNDAEL_ROM_SBOXES == 1) 57 | 58 | static const uint8_t sbox[256] = { 59 | //0 1 2 3 4 5 6 7 8 9 A B C D E F 60 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 61 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 62 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 63 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 64 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 65 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 66 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 67 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 68 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 69 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 70 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 71 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 72 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 73 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 74 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 75 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 76 | }; 77 | 78 | static const uint8_t rbox[256] = { 79 | 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 80 | 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 81 | 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 82 | 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 83 | 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 84 | 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 85 | 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 86 | 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 87 | 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 88 | 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 89 | 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 90 | 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 91 | 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 92 | 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 93 | 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 94 | 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d 95 | }; 96 | 97 | static void init_sbox(void) { } 98 | 99 | #else //USE_ROM_SBOXES 100 | 101 | static uint8_t sbox[256]; 102 | static uint8_t rbox[256]; 103 | 104 | static void init_sbox(void) { 105 | uint32_t p = 1, q = 1; 106 | /* loop invariant: p * q == 1 in the Galois field */ 107 | do { 108 | /* multiply p by 3 */ 109 | p ^= gmul2(p); 110 | /* divide q by 3 (equals multiplication by 0xf6) */ 111 | q ^= (q << 1); 112 | q ^= (q << 2); 113 | q ^= (q << 4); 114 | q &= 0xFF; 115 | if (q & 0x80) { 116 | q ^= 0x09; 117 | } 118 | /* compute the affine transformation */ 119 | uint32_t s = 0x63 ^ q ^ (q << 1) ^ (q << 2) ^ (q << 3) ^ (q << 4); 120 | s = 0xFF & (s ^ (s >> 8)); 121 | 122 | sbox[p] = (uint8_t)s; 123 | rbox[s] = (uint8_t)p; 124 | } while (p != 1); 125 | 126 | /* 0 is a special case since it has no inverse */ 127 | sbox[0x00] = 0x63; 128 | rbox[0x63] = 0x00; 129 | } 130 | 131 | #endif //USE_ROM_SBOXES 132 | 133 | static void sub_box(void *data, const uint8_t *box, size_t sz) { 134 | uint8_t *raw = data; 135 | for (size_t i = 0; i < sz; i++) { 136 | uint8_t x = raw[i]; 137 | raw[i] = box[x]; 138 | } 139 | } 140 | 141 | static void AddRoundKey(void *dst, const void *src, int round) { 142 | uint8_t *rk = (uint8_t*)roundkey + sizeof(state_t) * round; 143 | for (int i = 0; i < sizeof(state_t); i++) { 144 | ((uint8_t*)dst)[i] = ((uint8_t*)src)[i] ^ rk[i]; 145 | } 146 | } 147 | 148 | static void SubBytes(state_t* state) { 149 | sub_box(state, sbox, sizeof(state_t)); 150 | } 151 | 152 | static void ShiftRows(state_t* state) 153 | { 154 | uint8_t temp; 155 | // Rotate first row 1 columns to left 156 | temp = (*state)[0][1]; 157 | (*state)[0][1] = (*state)[1][1]; 158 | (*state)[1][1] = (*state)[2][1]; 159 | (*state)[2][1] = (*state)[3][1]; 160 | (*state)[3][1] = temp; 161 | 162 | // Rotate second row 2 columns to left 163 | temp = (*state)[0][2]; 164 | (*state)[0][2] = (*state)[2][2]; 165 | (*state)[2][2] = temp; 166 | 167 | temp = (*state)[1][2]; 168 | (*state)[1][2] = (*state)[3][2]; 169 | (*state)[3][2] = temp; 170 | 171 | // Rotate third row 3 columns to left 172 | temp = (*state)[0][3]; 173 | (*state)[0][3] = (*state)[3][3]; 174 | (*state)[3][3] = (*state)[2][3]; 175 | (*state)[2][3] = (*state)[1][3]; 176 | (*state)[1][3] = temp; 177 | } 178 | 179 | static void MixColumns(state_t* state) { 180 | uint8_t Tmp, Tm, t; 181 | for (int i = 0; i < 4; ++i) { 182 | t = (*state)[i][0]; 183 | Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; 184 | Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = gmul2(Tm); (*state)[i][0] ^= Tm ^ Tmp ; 185 | Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = gmul2(Tm); (*state)[i][1] ^= Tm ^ Tmp ; 186 | Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = gmul2(Tm); (*state)[i][2] ^= Tm ^ Tmp ; 187 | Tm = (*state)[i][3] ^ t ; Tm = gmul2(Tm); (*state)[i][3] ^= Tm ^ Tmp ; 188 | } 189 | } 190 | 191 | // Let "*" denotes polynomial multiplication modulo x4+1 over GF(2^8) 192 | // Let "+" denotes polynomyal addition over GF(2^8) (XOR) X + X = 0 193 | // A' = (A*8 + A*4 + A*2) + (B*8 + B*2 + B) + (C*8 + C*4 + C) + (D*8 + D) 194 | // B' = (A*8 + A) + (B*8 + B*4 + B*2) + (C*8 + C*2 + C) + (D*8 + D*4 + D) 195 | // C' = (A*8 + A*4 + A) + (B*8 + B) + (C*8 + C*4 + C*2) + (D*8 + D*2 + D) 196 | // D' = (A*8 + A*2 + A) + (B*8 + B*4 + B) + (C*8 + C) + (D*8 + D*4 + D*2) 197 | // Let 198 | // T = (A + B + C + D)*8 + (A + B + C + D) 199 | // Then 200 | // A' = T + (A + C)*4 + (A + B)*2 + A 201 | // B' = T + (B + D)*4 + (B + C)*2 + B 202 | // C' = T + (C + A)*4 + (C + D)*2 + C 203 | // D' = T + (D + B)*4 + (D + A)*2 + D 204 | // So (A + C)*4 = (C + A)* 4 and (B + D)*4 = (D + B)*4 205 | static void InvMixColumns(state_t* state) { 206 | for (int i = 0; i < 4; ++i) { 207 | uint8_t a = (*state)[i][0]; 208 | uint8_t b = (*state)[i][1]; 209 | uint8_t c = (*state)[i][2]; 210 | uint8_t d = (*state)[i][3]; 211 | uint8_t T, X; 212 | T = a ^ b ^ c ^ d; 213 | T ^= gmul8(T); 214 | X = gmul4(a ^ c); 215 | (*state)[i][0] = T ^ X ^ gmul2(a ^ b) ^ a; 216 | (*state)[i][2] = T ^ X ^ gmul2(c ^ d) ^ c; 217 | X = gmul4(b ^ d); 218 | (*state)[i][1] = T ^ X ^ gmul2(b ^ c) ^ b; 219 | (*state)[i][3] = T ^ X ^ gmul2(d ^ a) ^ d; 220 | } 221 | } 222 | 223 | static void InvSubBytes(state_t* state) { 224 | sub_box(state, rbox, sizeof(state_t)); 225 | } 226 | 227 | static void InvShiftRows(state_t* state) 228 | { 229 | uint8_t temp; 230 | 231 | // Rotate first row 1 columns to right 232 | temp = (*state)[3][1]; 233 | (*state)[3][1] = (*state)[2][1]; 234 | (*state)[2][1] = (*state)[1][1]; 235 | (*state)[1][1] = (*state)[0][1]; 236 | (*state)[0][1] = temp; 237 | 238 | // Rotate second row 2 columns to right 239 | temp = (*state)[0][2]; 240 | (*state)[0][2] = (*state)[2][2]; 241 | (*state)[2][2] = temp; 242 | 243 | temp = (*state)[1][2]; 244 | (*state)[1][2] = (*state)[3][2]; 245 | (*state)[3][2] = temp; 246 | 247 | // Rotate third row 3 columns to right 248 | temp = (*state)[0][3]; 249 | (*state)[0][3] = (*state)[1][3]; 250 | (*state)[1][3] = (*state)[2][3]; 251 | (*state)[2][3] = (*state)[3][3]; 252 | (*state)[3][3] = temp; 253 | } 254 | 255 | void rijndael_init(const void *key) { 256 | uint8_t rcon = 0x01; 257 | init_sbox(); 258 | memcpy(roundkey, key, KEYSIZE); 259 | for (int i = KEYSIZE32, j = 0; i < RKSIZE32; i++) { 260 | uint32_t temp = roundkey[i - 1]; 261 | if (j == 0) { 262 | temp = __ror32(temp, 8); 263 | sub_box(&temp, sbox, 4); 264 | temp ^= rcon; 265 | rcon = gmul2(rcon); 266 | } 267 | // 256-bit key special 268 | if (KEYSIZE == 32 && j == 4) { 269 | sub_box(&temp, sbox, 4); 270 | } 271 | if (++j == KEYSIZE32) { 272 | j = 0; 273 | } 274 | roundkey[i] = temp ^ roundkey[i - KEYSIZE32]; 275 | } 276 | } 277 | 278 | void rijndael_encrypt(uint32_t *out, const uint32_t *in) { 279 | state_t state; 280 | int round = 0; 281 | // Add the First round key to the state before starting the rounds. 282 | AddRoundKey(&state, in, round); 283 | for(;;) { 284 | round++; 285 | SubBytes(&state); 286 | ShiftRows(&state); 287 | if (round == ROUNDS) { 288 | break; 289 | } 290 | MixColumns(&state); 291 | AddRoundKey(&state, &state, round); 292 | } 293 | AddRoundKey(out, &state, round); 294 | } 295 | 296 | void rijndael_decrypt(uint32_t *out, const uint32_t *in) { 297 | state_t state; 298 | int round = ROUNDS; 299 | AddRoundKey(&state, in, round); 300 | for(;;) { 301 | round--; 302 | InvShiftRows(&state); 303 | InvSubBytes(&state); 304 | if (round == 0) { 305 | break; 306 | } 307 | AddRoundKey(&state, &state, round); 308 | InvMixColumns(&state); 309 | } 310 | AddRoundKey(out, &state, round); 311 | } 312 | -------------------------------------------------------------------------------- /src/rtea.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Ruptor's TEA or Repaired TEA 4 | * 5 | * Copyright ©2017 Dmitry Filimonchuk 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include "rtea.h" 21 | 22 | #define rounds 64 23 | 24 | static uint32_t K[8]; 25 | 26 | void rtea_encrypt(uint32_t *out, const uint32_t *in) { 27 | uint32_t A = in[0]; 28 | uint32_t B = in[1]; 29 | for (int32_t i = 0; i < rounds; i++) { 30 | B += A + ((A << 6) ^ (A >> 8)) + K[i & 0x07] + i; 31 | i++; 32 | A += B + ((B << 6) ^ (B >> 8)) + K[i & 0x07] + i; 33 | } 34 | out[0] = A; 35 | out[1] = B; 36 | } 37 | 38 | void rtea_decrypt(uint32_t *out, const uint32_t *in) { 39 | uint32_t A = in[0]; 40 | uint32_t B = in[1]; 41 | for (int32_t i = (rounds - 1); i >= 0; i--) { 42 | A -= B + ((B << 6) ^ (B >> 8)) + K[i & 0x07] + i; 43 | i--; 44 | B -= A + ((A << 6) ^ (A >> 8)) + K[i & 0x07] + i; 45 | } 46 | 47 | out[0] = A; 48 | out[1] = B; 49 | } 50 | 51 | void rtea_init(const void* key) { 52 | memcpy(K, key, sizeof(K)); 53 | } 54 | -------------------------------------------------------------------------------- /src/speck.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * SPECK 64/128-CBC block cipher implementation based on 4 | * "The Simon and Speck Families Of Lightwieght Block Ciphers" 5 | * http://eprint.iacr.org/2013/404.pdf 6 | * 7 | * Copyright ©2016 Dmitry Filimonchuk 8 | * 9 | * Licensed under the Apache License, Version 2.0 (the "License"); 10 | * you may not use this file except in compliance with the License. 11 | * You may obtain a copy of the License at 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include "misc.h" 23 | #include "config.h" 24 | #include "speck.h" 25 | 26 | #define ROUNDS 27 27 | 28 | static uint32_t roundkey[ROUNDS]; 29 | 30 | inline static void speck_round(uint32_t *a, uint32_t *b, const uint32_t key) { 31 | *a = key ^ (__ror32(*a, 8) + *b); 32 | *b = *a ^ __rol32(*b, 3); 33 | } 34 | 35 | inline static void speck_back(uint32_t *a, uint32_t *b, const uint32_t key) { 36 | *b = __ror32(*b ^ *a, 3); 37 | *a = __rol32((key ^ *a) - *b, 8); 38 | } 39 | 40 | void speck_encrypt(uint32_t *out, const uint32_t *in) { 41 | uint32_t A = in[0]; 42 | uint32_t B = in[1]; 43 | for (int i = 0; i < ROUNDS; i++) { 44 | speck_round(&B, &A, roundkey[i]); 45 | } 46 | out[0] = A; 47 | out[1] = B; 48 | } 49 | 50 | void speck_decrypt(uint32_t *out, const uint32_t *in) { 51 | uint32_t A = in[0]; 52 | uint32_t B = in[1]; 53 | for (int i = ROUNDS-1; i >= 0; i--) { 54 | speck_back(&B, &A, roundkey[i]); 55 | } 56 | out[0] = A; 57 | out[1] = B; 58 | } 59 | 60 | void speck_init(const void* key) { 61 | uint32_t K[4]; 62 | memcpy(K, key, 16); 63 | for (int i = 0, j = 0 ; i < ROUNDS; i++) { 64 | roundkey[i] = K[0]; 65 | if (++j > 3) j = 1; 66 | speck_round(&K[j], &K[0], i); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/xtea.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * eXtended TEA CBC block cipher based on: 4 | * "Tea extensions" Roger M. Needham and David J. Wheeler 5 | * http://www.cix.co.uk/~klockstone/xtea.pdf 6 | * "Extended TEA Algorithms" Tom St Denis 7 | * http://tomstdenis.tripod.com/xtea.pdf 8 | * 9 | * Copyright ©2017 Dmitry Filimonchuk 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | 22 | #include 23 | #include 24 | #include "misc.h" 25 | #include "xtea.h" 26 | 27 | #define rounds 32 28 | #define delta 0x9E3779B9 29 | 30 | #define RA(x, s, k) (((x << 4) ^ (x >> 5)) + x) ^ (s + k[s & 0x03]) 31 | #define RB(x, s, k) (((x << 4) ^ (x >> 5)) + x) ^ (s + k[(s >> 11) & 0x03]) 32 | 33 | static uint32_t K[4]; 34 | 35 | void xtea_encrypt(uint32_t *out, const uint32_t *in) { 36 | uint32_t A = in[0]; 37 | uint32_t B = in[1]; 38 | uint32_t S = 0; 39 | for (int i = 0; i < rounds; i++) { 40 | A += RA(B, S, K); 41 | S += delta; 42 | B += RB(A, S, K); 43 | } 44 | out[0] = A; 45 | out[1] = B; 46 | } 47 | 48 | void xtea_decrypt(uint32_t *out, const uint32_t *in) { 49 | uint32_t A = in[0]; 50 | uint32_t B = in[1]; 51 | uint32_t S = rounds * delta; 52 | for (int i = 0; i < rounds; i++) { 53 | B -= RB(A, S, K); 54 | S -= delta; 55 | A -= RA(B, S, K); 56 | } 57 | out[0] = A; 58 | out[1] = B; 59 | } 60 | 61 | void xtea_init(const void* key) { 62 | memcpy(K, key, sizeof(K)); 63 | } 64 | -------------------------------------------------------------------------------- /src/xtea1.c: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * eXtended TEA CBC block cipher based on: 4 | * "Tea extensions" Roger M. Needham and David J. Wheeler 5 | * http://www.cix.co.uk/~klockstone/xtea.pdf 6 | * "Extended TEA Algorithms" Tom St Denis 7 | * http://tomstdenis.tripod.com/xtea.pdf 8 | * 9 | * Copyright ©2017 Dmitry Filimonchuk 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); 12 | * you may not use this file except in compliance with the License. 13 | * You may obtain a copy of the License at 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * Unless required by applicable law or agreed to in writing, software 16 | * distributed under the License is distributed on an "AS IS" BASIS, 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | * See the License for the specific language governing permissions and 19 | * limitations under the License. 20 | */ 21 | 22 | #include 23 | #include 24 | #include "misc.h" 25 | #include "xtea.h" 26 | 27 | #define rounds 32 28 | #define delta 0x9E3779B9 29 | 30 | #define RA(x, s, k) ((x << 4) ^ (x >> 5)) + ( x ^ s) + __rol32(k[s & 0x03], x) 31 | #define RB(x, s, k) ((x << 4) ^ (x >> 5)) + ( x ^ s) + __rol32(k[(s >> 11) & 0x03], x) 32 | 33 | static uint32_t K[4]; 34 | 35 | void xtea1_encrypt(uint32_t *out, const uint32_t *in) { 36 | uint32_t A = in[0]; 37 | uint32_t B = in[1]; 38 | uint32_t S = 0; 39 | for (int i = 0; i < rounds; i++) { 40 | A += RA(B, S, K); 41 | S += delta; 42 | B += RB(A, S, K); 43 | } 44 | out[0] = A; 45 | out[1] = B; 46 | } 47 | 48 | void xtea1_decrypt(uint32_t *out, const uint32_t *in) { 49 | uint32_t A = in[0]; 50 | uint32_t B = in[1]; 51 | uint32_t S = rounds * delta; 52 | for (int i = 0; i < rounds; i++) { 53 | B -= RB(A, S, K); 54 | S -= delta; 55 | A -= RA(B, S, K); 56 | } 57 | out[0] = A; 58 | out[1] = B; 59 | } 60 | 61 | void xtea1_init(const void* key) { 62 | memcpy(K, key, sizeof(K)); 63 | } 64 | -------------------------------------------------------------------------------- /userconfig-example.h: -------------------------------------------------------------------------------- 1 | /* This file is the part of the STM32 secure bootloader 2 | * 3 | * Copyright ©2016 Dmitry Filimonchuk 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef _DFU_USERCONFIG_H_ 17 | #define _DFU_USERCONFIG_H_ 18 | 19 | /* DEFAULT CONFIG STARTS HERE */ 20 | /* Skip unwanted dfuDNLOAD_SYNC phase. Slightly improve speed, but don't meets DFU1.1 state diagram */ 21 | //#define DFU_DNLOAD_NOSYNC _ENABLE 22 | 23 | /** Add extra DFU interface for EEPROM */ 24 | //#define DFU_INTF_EEPROM _AUTO 25 | 26 | /** Firmware can be uploaded from device */ 27 | //#define DFU_CAN_UPLOAD _ENABLE 28 | 29 | /** Handle DFU_DETACH request in DFU mode. System reset will be issued. */ 30 | //#define DFU_DETACH _ENABLE 31 | 32 | /** Whether application image is checked by its vector table */ 33 | //#define DFU_VERIFY_VTABLE _ENABLE 34 | 35 | /** Whether application image is verified by a checksum algorithm */ 36 | //#define DFU_VERIFY_CHECKSUM _DISABLE 37 | 38 | /** Memory Readout Protection level **/ 39 | //#define DFU_SEAL_LEVEL 0 40 | 41 | /* USB VID & PID */ 42 | //#define DFU_VENDOR_ID 0x0483 43 | //#define DFU_DEVICE_ID 0xDF11 44 | 45 | /* USB manufacturer string */ 46 | //#define DFU_STR_MANUF "Your company name" 47 | 48 | /* USB product sting */ 49 | //#define DFU_STR_PRODUCT "Secure bootloader" 50 | 51 | /* USB string for DFU configuration string descriptor. */ 52 | //#define DFU_DSC_CONFIG _ENABLE 53 | //#define DFU_STR_CONFIG "DFU" 54 | 55 | /* USB string for DFU flash interface string descriptor. */ 56 | //#define DFU_DSC_FLASH _ENABLE 57 | //#define DFU_STR_FLASH "Internal flash" 58 | 59 | /* USB string for DFU EEPROM interface sreing descriptor */ 60 | //#define DFU_DSC_EEPROM _ENABLE 61 | //#define DFU_STR_EEPROM "Internal EEPROM" 62 | 63 | /* USB EP0 size. Must be 8 for USB FS */ 64 | //#define DFU_EP0_SIZE 8 65 | 66 | /* DFU properties */ 67 | //#define DFU_POLL_TIMEOUT 20 68 | //#define DFU_DETACH_TIMEOUT 200 69 | //#define DFU_BLOCKSZ 0x800 70 | 71 | /** Whether the RTC register is checked to enforce bootloader or user application mode */ 72 | //#define DFU_CHECK_RTC_MAGIC_NUMBER _ENABLE 73 | //#define RTC_MAGIC_NUMBER_BOOTLOADER 0x424c 74 | //#define RTC_MAGIC_NUMBER_USERAPP 0x424d 75 | 76 | /* 32 bit DFU bootkey value */ 77 | //#define DFU_BOOTKEY 0x157F32D4 78 | 79 | /* DFU bootkey address. Top of the ram by default. _AUTO, _DISABLE or set address. 80 | * May be enabled internally. */ 81 | //#define DFU_BOOTKEY_ADDR _AUTO 82 | 83 | /* DFU bootstrap port/pin settings. Set GPIOx or _DISABLE */ 84 | //#define DFU_BOOTSTRAP_GPIO GPIOA 85 | //#define DFU_BOOTSTRAP_PIN 0 86 | 87 | /* Active bootstrap pin logic level. _HIGH, _LOW */ 88 | //#define DFU_BOOTSTRAP_LEVEL _LOW 89 | 90 | /* Pullup or pulldown settings for the bootstrap pin _AUTO, _DISABLE, _HIGH, _LOW */ 91 | //#define DFU_BOOTSTRAP_PULL _AUTO 92 | 93 | /* Double reset waiting time in mS. _DISABLE or time in mS */ 94 | //#define DFU_DBLRESET_MS 300 95 | 96 | /* DFU bootstrap port/pin settings. Set GPIOx or _DISABLE */ 97 | //#define DFU_LED_GPIO GPIOC 98 | //#define DFU_LED_RCC 0x004 // (0x1UL << 'x'-'A') => A=0x001, B=0x002, C=0x004 etc 99 | //#define DFU_LED_PIN 13 100 | //#define DFU_LED_ON_LEVEL _LOW 101 | 102 | /* Exit the bootloader into the user application after this many "time units" */ 103 | /* (0 = never, 1 = instantly/fastboot, 6 = 0.5s/minimum, 680 = 60s, ...32bit) */ 104 | //#define DFU_TIMEOUT_DEFAULT 6 // = 0.5s: use dfu-util -w 105 | //#define DFU_TIMEOUT_RTC_MAGIC 35 // = 3s 106 | //#define DFU_TIMEOUT_UPDOWNLOAD 680 // = 60s 107 | 108 | /* Skip entering the bootloader after download even when fastboot is disabled */ 109 | //#define DFU_SKIP_BOOTLOADER_AFTER_DOWNLOAD _DISABLE 110 | 111 | /* User application address. _AUTO or page aligned address. 112 | * for _AUTO check __app_start address in output linker map file*/ 113 | //#define DFU_APP_START _AUTO 114 | 115 | /* User application size. _AUTO or required size in bytes. */ 116 | //#define DFU_APP_SIZE _AUTO 117 | 118 | /* Microsoft WCID allows automatic driver (WinUSB) installation on device 119 | * connection. Use _ENABLE to make your device likeable by Windows. */ 120 | //#define DFU_WCID _DISABLE 121 | 122 | /* Cipher to use. set _DISABLE or choose from implemented ciphers */ 123 | //#define DFU_CIPHER DFU_CIPHER_RC5 124 | //#define DFU_CIPHER_MODE DFU_CIPHER_CBC 125 | 126 | #endif // _DFU_USERCONFIG_H_ 127 | --------------------------------------------------------------------------------