├── .gitattributes ├── .gitmodules ├── .gitignore ├── inc ├── misc.h ├── usb_msft.h ├── flash.h ├── descriptors.h ├── arc4.h ├── rtea.h ├── chacha_a.h ├── chacha.h ├── rc5.h ├── speck.h ├── magma.h ├── rc6.h ├── rc5_a.h ├── raiden.h ├── crypto.h ├── rc6a.h ├── blowfish.h ├── xtea1.h ├── gost.h ├── rijndael.h ├── xtea.h ├── checksum.h └── getopt.h ├── .github └── workflows │ ├── test-build-lnx.yml │ ├── test-build-win.yml │ └── test-build-osx.yml ├── flow.md ├── src ├── arc4.c ├── rtea.c ├── xtea.c ├── raiden.c ├── xtea1.c ├── speck.c ├── rc5.c ├── gost.c ├── magma.c ├── chacha.c ├── rc6.c ├── blowfish.c ├── checksum.c ├── chacha_a.S ├── rc5a.S ├── rc6a.S ├── descriptors.c ├── bootloader.c ├── encrypter.c ├── rijndael.c └── ctest.c ├── ldscript.mk ├── config.h ├── CONFIG.md ├── README.md ├── LICENSE └── mcu ├── stm32f103.S └── stm32l4xx.S /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libusb_stm32"] 2 | path = usb 3 | url = http://github.com/dmitrystu/libusb_stm32.git 4 | branch = master 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #working subdirs 2 | obj/* 3 | bin/* 4 | build/* 5 | 6 | #EmBitz project files 7 | *.depend 8 | *.ebp 9 | *.elay 10 | 11 | #OpenOCD configuration 12 | openocd.cfg 13 | 14 | #sublime project files 15 | *.sublime-project 16 | *.sublime-workspace 17 | 18 | .vscode -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.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-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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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_ -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | static uint32_t sbox(uint32_t in) { 35 | uint32_t out = 0; 36 | for(int i = 0; i < 8; i++) { 37 | out <<= 4; 38 | out += (S[in >> 28] >> (i * 4)) & 0x0F; 39 | in <<= 4; 40 | } 41 | return out; 42 | } 43 | 44 | static uint32_t F(uint32_t data, uint32_t round) { 45 | return __rol32(sbox(data + RK[round]), 11); 46 | } 47 | 48 | void gost_encrypt(uint32_t *out, const uint32_t *in) { 49 | uint32_t A = in[0]; 50 | uint32_t B = in[1]; 51 | for (int i = 0; i < rounds; i++) { 52 | uint32_t A1 = B ^ F(A, i); 53 | B = A; 54 | A = A1; 55 | } 56 | out[0] = B; 57 | out[1] = A; 58 | } 59 | 60 | void gost_decrypt(uint32_t *out, const uint32_t *in) { 61 | uint32_t A = in[0]; 62 | uint32_t B = in[1]; 63 | for (int i = 31; i >= 0; i--) { 64 | uint32_t A1 = B ^ F(A, i); 65 | B = A; 66 | A = A1; 67 | } 68 | out[0] = B; 69 | out[1] = A; 70 | } 71 | 72 | void gost_init(const void* key){ 73 | const uint8_t *K = key; 74 | for (int i = 0; i < 8; i++) { 75 | RK[i] = K[4*i] << 24 | K[4*i+1] << 16 | K[4*i+2] << 8 | K[4*i+3]; 76 | RK[8+i] = RK[i]; 77 | RK[16+i] = RK[i]; 78 | RK[31-i] = RK[i]; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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 | 36 | static uint32_t sbox(uint32_t in) { 37 | uint32_t out = 0; 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 | 46 | 47 | static uint32_t F(uint32_t data, uint32_t round) { 48 | return __rol32(sbox(data + RK[round]), 11); 49 | } 50 | 51 | void magma_encrypt(uint32_t *out, const uint32_t *in) { 52 | uint32_t A = BE32TOCPU(in[1]); 53 | uint32_t B = BE32TOCPU(in[0]); 54 | for (int i = 0; i < rounds; i++) { 55 | uint32_t A1 = B ^ F(A, i); 56 | B = A; 57 | A = A1; 58 | } 59 | out[1] = CPUTOBE32(B); 60 | out[0] = CPUTOBE32(A); 61 | } 62 | 63 | void magma_decrypt(uint32_t *out, const uint32_t *in) { 64 | uint32_t A = BE32TOCPU(in[1]); 65 | uint32_t B = BE32TOCPU(in[0]); 66 | for (int i = 31; i >= 0; i--) { 67 | uint32_t A1 = B ^ F(A, i); 68 | B = A; 69 | A = A1; 70 | } 71 | out[1] = CPUTOBE32(B); 72 | out[0] = CPUTOBE32(A); 73 | } 74 | 75 | void magma_init(const void* key){ 76 | for (int i = 0; i < 8; i++) { 77 | uint32_t K; 78 | memcpy(&K, key, sizeof(K)); 79 | K = BE32TOCPU(K); 80 | RK[0x00 + i] = K; 81 | RK[0x08 + i] = K; 82 | RK[0x10 + i] = K; 83 | RK[0x1F - i] = K; 84 | key += 4; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | /** Add extra DFU interface for EEPROM */ 71 | #ifndef DFU_INTF_EEPROM 72 | #define DFU_INTF_EEPROM _AUTO 73 | #endif 74 | /** Firmware can be uploaded from device */ 75 | #ifndef DFU_CAN_UPLOAD 76 | #define DFU_CAN_UPLOAD _ENABLE 77 | #endif 78 | /** Handle DFU_DETACH request in DFU mode. System reset will be issued. */ 79 | #ifndef DFU_DETACH 80 | #define DFU_DETACH _ENABLE 81 | #endif 82 | /** Whether application image is verified by a checksum algorithm */ 83 | #ifndef DFU_VERIFY_CHECKSUM 84 | #define DFU_VERIFY_CHECKSUM _DISABLE 85 | #endif 86 | /** Memory Readout Protection level **/ 87 | #ifndef DFU_SEAL_LEVEL 88 | #define DFU_SEAL_LEVEL 0 89 | #endif 90 | /* USB VID */ 91 | #ifndef DFU_VENDOR_ID 92 | #define DFU_VENDOR_ID 0x0483 93 | #endif 94 | /* USB PID */ 95 | #ifndef DFU_DEVICE_ID 96 | #define DFU_DEVICE_ID 0xDF11 97 | #endif 98 | /* USB manufacturer string */ 99 | #ifndef DFU_STR_MANUF 100 | #define DFU_STR_MANUF "Your company name" 101 | #endif 102 | /* USB product sting */ 103 | #ifndef DFU_STR_PRODUCT 104 | #define DFU_STR_PRODUCT "Secure bootloader" 105 | #endif 106 | /* USB string for DFU configureation string descriptor. */ 107 | #ifndef DFU_DSC_CONFIG 108 | #define DFU_DSC_CONFIG _ENABLE 109 | #endif 110 | #ifndef DFU_STR_CONFIG 111 | #define DFU_STR_CONFIG "DFU" 112 | #endif 113 | /* USB string for DFU flash interface string descriptor. */ 114 | #ifndef DFU_DSC_FLASH 115 | #define DFU_DSC_FLASH _ENABLE 116 | #endif 117 | #ifndef DFU_STR_FLASH 118 | #define DFU_STR_FLASH "Internal flash" 119 | #endif 120 | /* USB string for DFU EEPROM interface sreing descriptor */ 121 | #ifndef DFU_DSC_EEPROM 122 | #define DFU_DSC_EEPROM _ENABLE 123 | #endif 124 | #ifndef DFU_STR_EEPROM 125 | #define DFU_STR_EEPROM "Internal EEPROM" 126 | #endif 127 | /* USB EP0 size. Must be 8 for USB FS */ 128 | #define DFU_EP0_SIZE 8 129 | /* DFU properties */ 130 | #ifndef DFU_POLL_TIMEOUT 131 | #define DFU_POLL_TIMEOUT 20 132 | #endif 133 | #ifndef DFU_DETACH_TIMEOUT 134 | #define DFU_DETACH_TIMEOUT 200 135 | #endif 136 | #ifndef DFU_BLOCKSZ 137 | #define DFU_BLOCKSZ 0x80 138 | #endif 139 | /* 32 bit DFU bootkey value */ 140 | #ifndef DFU_BOOTKEY 141 | #define DFU_BOOTKEY 0x157F32D4 142 | #endif 143 | /* DFU bootkey address. Top of the ram by default. _AUTO, _DISABLE or set address. 144 | * May be enabled internally. */ 145 | #ifndef DFU_BOOTKEY_ADDR 146 | #define DFU_BOOTKEY_ADDR _AUTO 147 | #endif 148 | /* DFU bootstrap port/pin settings. Set GPIOx or _DISABLE */ 149 | #ifndef DFU_BOOTSTRAP_GPIO 150 | #define DFU_BOOTSTRAP_GPIO GPIOA 151 | #endif 152 | #ifndef DFU_BOOTSTRAP_PIN 153 | #define DFU_BOOTSTRAP_PIN 1 154 | #endif 155 | /* Active bootstrap pin logic level. _HIGH, _LOW */ 156 | #ifndef DFU_BOOTSTRAP_LEVEL 157 | #define DFU_BOOTSTRAP_LEVEL _LOW 158 | #endif 159 | /* Pullup or pulldown settings for the bootstrap pin _AUTO, _DISABLE, _HIGH, _LOW */ 160 | #ifndef DFU_BOOTSTRAP_PULL 161 | #define DFU_BOOTSTRAP_PULL _AUTO 162 | #endif 163 | /* Double reset waiting time in mS. _DISABLE or time in mS */ 164 | #ifndef DFU_DBLRESET_MS 165 | #define DFU_DBLRESET_MS 300 166 | #endif 167 | /* User application address. _AUTO or page aligned address. 168 | * for _AUTO check __app_start address in output linker map file*/ 169 | #ifndef DFU_APP_START 170 | #define DFU_APP_START _AUTO 171 | #endif 172 | /* User application size. _AUTO or required size in bytes. */ 173 | #ifndef DFU_APP_SIZE 174 | #define DFU_APP_SIZE _AUTO 175 | #endif 176 | /* Microsoft WCID allows automatic driver (WinUSB) installation on device 177 | * connection. Use _ENABLE to make your device likeable by Windows. */ 178 | #ifndef DFU_WCID 179 | #define DFU_WCID _DISABLE 180 | #endif 181 | /* Cipher to use. set _DISABLE or choose from implemented ciphers */ 182 | #ifndef DFU_CIPHER 183 | #define DFU_CIPHER DFU_CIPHER_RC5 184 | #endif 185 | #ifndef DFU_CIPHER_MODE 186 | #define DFU_CIPHER_MODE DFU_CIPHER_CBC 187 | #endif 188 | /** DFU secure key. */ 189 | #define DFU_AES_KEY_A 0x2D, 0x4D, 0x61, 0x6B, 0x65, 0x4C, 0x6F, 0x76, \ 190 | 0x65, 0x4E, 0x6F, 0x74, 0x57, 0x61, 0x72, 0x2D 191 | #define DFU_AES_KEY_B 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, \ 192 | 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F 193 | #ifndef DFU_AES_KEY_128 194 | #define DFU_AES_KEY_128 DFU_AES_KEY_A 195 | #endif 196 | 197 | #ifndef DFU_AES_KEY_192 198 | #define DFU_AES_KEY_192 0x2D, 0x4D, 0x61, 0x6B, 0x65, 0x4C, 0x6F, 0x76, \ 199 | 0x65, 0x4E, 0x6F, 0x74, 0x57, 0x61, 0x72, 0x2D, \ 200 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 201 | #endif 202 | 203 | #ifndef DFU_AES_KEY_256 204 | #define DFU_AES_KEY_256 DFU_AES_KEY_A, DFU_AES_KEY_B 205 | #endif 206 | 207 | /** cipher initialization vector for block cipher and CHACHA */ 208 | #ifndef DFU_AES_IV_64 209 | #define DFU_AES_IV_64 0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55 210 | #endif 211 | 212 | #ifndef DFU_AES_IV_96 213 | #define DFU_AES_IV_96 0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55, \ 214 | 0xCC, 0xBB, 0xAA, 0x99 215 | #endif 216 | 217 | #ifndef DFU_AES_IV_128 218 | #define DFU_AES_IV_128 0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55,\ 219 | 0xCC, 0xBB, 0xAA, 0x99, 0x44, 0x33, 0x22, 0x11 220 | #endif 221 | 222 | #endif // _DFU_BOOTLOADER_H_ 223 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/bootloader.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 "config.h" 20 | #include "stm32.h" 21 | #include "usb.h" 22 | #include "usb_dfu.h" 23 | #include "descriptors.h" 24 | #include "flash.h" 25 | #include "crypto.h" 26 | 27 | /* Checking for the EEPROM */ 28 | #if defined(DATA_EEPROM_BASE) && defined(DATA_EEPROM_END) 29 | #define _EE_START DATA_EEPROM_BASE 30 | #define _EE_LENGTH (DATA_EEPROM_END - DATA_EEPROM_BASE + 1) 31 | #elif defined(DATA_EEPROM_BASE) && defined(DATA_EEPROM_BANK2_END) 32 | #define _EE_START DATA_EEPROM_BASE 33 | #define _EE_LENGTH (DATA_EEPROM_BANK2_END - DATA_EEPROM_BASE + 1) 34 | #elif defined(FLASH_EEPROM_BASE) 35 | #define _EE_START FLASH_EEPROM_BASE 36 | #define _EE_LENGTH (FLASH_EEPROM_END - FLASH_EEPROM_BASE + 1 ) 37 | #endif 38 | 39 | #if (DFU_INTF_EEPROM == _ENABLE) && !defined(_EE_START) 40 | #error No EEPROM found. Check config !! 41 | #elif ((DFU_INTF_EEPROM == _AUTO) || (DFU_INTF_EEPROM == _ENABLE)) && defined(_EE_START) 42 | #define _EEPROM_ENABLED 43 | #endif 44 | 45 | /* Checking for application start address */ 46 | #if (DFU_APP_START == _AUTO) 47 | #define _APP_START ((size_t)&__app_start) 48 | #elif ((DFU_APP_START & 0x000007FF) == 0) 49 | #define _APP_START DFU_APP_START 50 | #else 51 | #error DFU_APP_START must be 2k aligned. Check config !! 52 | #endif 53 | 54 | /* Checking for application size */ 55 | #if (DFU_APP_SIZE == _AUTO) 56 | #define _APP_LENGTH ((size_t)&__romend - _APP_START) 57 | #else 58 | #define _APP_LENGTH DFU_APP_SIZE 59 | #endif 60 | 61 | /* DFU request buffer size data + request header */ 62 | #define DFU_BUFSZ ((DFU_BLOCKSZ + 3 + 8) >> 2) 63 | 64 | extern uint8_t __app_start; 65 | extern uint8_t __romend; 66 | 67 | static uint32_t dfu_buffer[DFU_BUFSZ]; 68 | static usbd_device dfu; 69 | 70 | static struct dfu_data_s { 71 | uint8_t (*flash)(void *romptr, const void *buf, size_t blksize); 72 | void *dptr; 73 | size_t remained; 74 | uint8_t interface; 75 | uint8_t bStatus; 76 | uint8_t bState; 77 | } dfu_data; 78 | 79 | /** Processing DFU_SET_IDLE request */ 80 | static usbd_respond dfu_set_idle(void) { 81 | aes_init(); 82 | dfu_data.bState = USB_DFU_STATE_DFU_IDLE; 83 | dfu_data.bStatus = USB_DFU_STATUS_OK; 84 | switch (dfu_data.interface){ 85 | #if defined(_EEPROM_ENABLED) 86 | case 1: 87 | dfu_data.dptr = (void*)_EE_START; 88 | dfu_data.remained = _EE_LENGTH; 89 | dfu_data.flash = program_eeprom; 90 | break; 91 | #endif 92 | default: 93 | dfu_data.dptr = (void*)_APP_START; 94 | dfu_data.remained = _APP_LENGTH; 95 | dfu_data.flash = program_flash; 96 | break; 97 | } 98 | return usbd_ack; 99 | } 100 | 101 | extern void System_Reset(void); 102 | 103 | static usbd_respond dfu_err_badreq(void) { 104 | dfu_data.bState = USB_DFU_STATE_DFU_ERROR; 105 | dfu_data.bStatus = USB_DFU_STATUS_ERR_STALLEDPKT; 106 | return usbd_fail; 107 | } 108 | 109 | #if (DFU_CAN_UPLOAD == _ENABLE) 110 | static usbd_respond dfu_upload(usbd_device *dev, size_t blksize) { 111 | switch (dfu_data.bState) { 112 | case USB_DFU_STATE_DFU_IDLE: 113 | case USB_DFU_STATE_DFU_UPLOADIDLE: 114 | if (dfu_data.remained == 0) { 115 | dev->status.data_count = 0; 116 | return dfu_set_idle(); 117 | } else if (dfu_data.remained < DFU_BLOCKSZ) { 118 | blksize = dfu_data.remained; 119 | } 120 | aes_encrypt(dev->status.data_ptr, dfu_data.dptr, blksize); 121 | dev->status.data_count = blksize; 122 | dfu_data.remained -= blksize; 123 | dfu_data.dptr += blksize; 124 | return usbd_ack; 125 | default: 126 | return dfu_err_badreq(); 127 | } 128 | } 129 | #endif 130 | 131 | static usbd_respond dfu_dnload(void *buf, size_t blksize) { 132 | switch(dfu_data.bState) { 133 | case USB_DFU_STATE_DFU_DNLOADIDLE: 134 | case USB_DFU_STATE_DFU_DNLOADSYNC: 135 | case USB_DFU_STATE_DFU_IDLE: 136 | if (blksize == 0) { 137 | dfu_data.bState = USB_DFU_STATE_DFU_MANIFESTSYNC; 138 | return usbd_ack; 139 | } 140 | if (blksize > dfu_data.remained) { 141 | dfu_data.bStatus = USB_DFU_STATUS_ERR_ADDRESS; 142 | dfu_data.bState = USB_DFU_STATE_DFU_ERROR; 143 | return usbd_ack; 144 | } 145 | aes_decrypt(buf, buf, blksize ); 146 | dfu_data.bStatus = dfu_data.flash(dfu_data.dptr, buf, blksize); 147 | 148 | if (dfu_data.bStatus == USB_DFU_STATUS_OK) { 149 | dfu_data.dptr += blksize; 150 | dfu_data.remained -= blksize; 151 | #if (DFU_DNLOAD_NOSYNC == _ENABLE) 152 | dfu_data.bState = USB_DFU_STATE_DFU_DNLOADIDLE; 153 | #else 154 | dfu_data.bState = USB_DFU_STATE_DFU_DNLOADSYNC; 155 | #endif 156 | return usbd_ack; 157 | } else { 158 | dfu_data.bState = USB_DFU_STATE_DFU_ERROR; 159 | return usbd_ack; 160 | } 161 | default: 162 | return dfu_err_badreq(); 163 | } 164 | } 165 | 166 | static usbd_respond dfu_getstatus(void *buf) { 167 | /* make answer */ 168 | struct usb_dfu_status *stat = buf; 169 | stat->bStatus = dfu_data.bStatus; 170 | stat->bState = dfu_data.bState; 171 | stat->bPollTimeout = (DFU_POLL_TIMEOUT & 0xFF); 172 | stat->wPollTimeout = (DFU_POLL_TIMEOUT >> 8); 173 | stat->iString = NO_DESCRIPTOR; 174 | 175 | switch (dfu_data.bState) { 176 | case USB_DFU_STATE_DFU_IDLE: 177 | case USB_DFU_STATE_DFU_DNLOADIDLE: 178 | case USB_DFU_STATE_DFU_UPLOADIDLE: 179 | case USB_DFU_STATE_DFU_ERROR: 180 | return usbd_ack; 181 | case USB_DFU_STATE_DFU_DNLOADSYNC: 182 | dfu_data.bState = USB_DFU_STATE_DFU_DNLOADIDLE; 183 | return usbd_ack; 184 | case USB_DFU_STATE_DFU_MANIFESTSYNC: 185 | return dfu_set_idle(); 186 | default: 187 | return dfu_err_badreq(); 188 | } 189 | } 190 | 191 | static usbd_respond dfu_getstate(uint8_t *buf) { 192 | *buf = dfu_data.bState; 193 | return usbd_ack; 194 | } 195 | 196 | static usbd_respond dfu_abort() { 197 | switch (dfu_data.bState) { 198 | case USB_DFU_STATE_DFU_IDLE: 199 | case USB_DFU_STATE_DFU_DNLOADSYNC: 200 | case USB_DFU_STATE_DFU_DNLOADIDLE: 201 | case USB_DFU_STATE_DFU_MANIFESTSYNC: 202 | case USB_DFU_STATE_DFU_UPLOADIDLE: 203 | return dfu_set_idle(); 204 | default: 205 | return dfu_err_badreq(); 206 | } 207 | } 208 | 209 | static usbd_respond dfu_clrstatus() { 210 | if (dfu_data.bState == USB_DFU_STATE_DFU_ERROR) { 211 | return dfu_set_idle(); 212 | } else { 213 | return dfu_err_badreq(); 214 | } 215 | } 216 | 217 | static void dfu_reset(usbd_device *dev, uint8_t ev, uint8_t ep) { 218 | (void)dev; 219 | (void)ev; 220 | (void)ep; 221 | /** TODO : add firmware checkout */ 222 | System_Reset(); 223 | } 224 | 225 | static usbd_respond dfu_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) { 226 | (void)callback; 227 | if ((req->bmRequestType & (USB_REQ_TYPE | USB_REQ_RECIPIENT)) == (USB_REQ_STANDARD | USB_REQ_INTERFACE)) { 228 | switch (req->bRequest) { 229 | case USB_STD_SET_INTERFACE: 230 | if (req->wIndex != 0) return usbd_fail; 231 | switch (req->wValue) { 232 | case 0: break; 233 | #if defined(_EEPROM_ENABLED) 234 | case 1: break; 235 | #endif 236 | default: 237 | return usbd_fail; 238 | } 239 | dfu_data.interface = req->wValue; 240 | return dfu_set_idle(); 241 | case USB_STD_GET_INTERFACE: 242 | req->data[0] = dfu_data.interface; 243 | return usbd_ack; 244 | default: 245 | return usbd_fail; 246 | } 247 | } 248 | if ((req->bmRequestType & (USB_REQ_TYPE | USB_REQ_RECIPIENT)) == (USB_REQ_CLASS | USB_REQ_INTERFACE)) { 249 | switch (req->bRequest) { 250 | #if (DFU_DETACH == _ENABLE) 251 | case USB_DFU_DETACH: 252 | *callback = (usbd_rqc_callback)dfu_reset; 253 | return usbd_ack; 254 | #endif 255 | case USB_DFU_DNLOAD: 256 | if (req->wLength <= DFU_BLOCKSZ) { 257 | return dfu_dnload(req->data, req->wLength); 258 | } 259 | break; 260 | case USB_DFU_UPLOAD: 261 | #if (DFU_CAN_UPLOAD == _ENABLE) 262 | if (req->wLength <= DFU_BLOCKSZ) { 263 | return dfu_upload(dev, req->wLength); 264 | } 265 | #endif 266 | break; 267 | case USB_DFU_GETSTATUS: 268 | return dfu_getstatus(req->data); 269 | case USB_DFU_CLRSTATUS: 270 | return dfu_clrstatus(); 271 | case USB_DFU_GETSTATE: 272 | return dfu_getstate(req->data); 273 | case USB_DFU_ABORT: 274 | return dfu_abort(); 275 | default: 276 | break; 277 | } 278 | return dfu_err_badreq(); 279 | } 280 | #if (DFU_WCID != _DISABLE) 281 | if ((req->bmRequestType & USB_REQ_TYPE) == USB_REQ_VENDOR) { 282 | return dfu_get_vendor_descriptor(req, &dev->status.data_ptr, &dev->status.data_count); 283 | } 284 | #endif 285 | return usbd_fail; 286 | } 287 | 288 | 289 | static usbd_respond dfu_config(usbd_device *dev, uint8_t config) { 290 | switch (config) { 291 | case 0: 292 | usbd_reg_event(dev, usbd_evt_reset, 0); 293 | break; 294 | case 1: 295 | usbd_reg_event(dev, usbd_evt_reset, dfu_reset); 296 | break; 297 | default: 298 | return usbd_fail; 299 | } 300 | return usbd_ack; 301 | } 302 | 303 | 304 | static void dfu_init (void) { 305 | dfu_set_idle(); 306 | usbd_init(&dfu, &usbd_hw, DFU_EP0_SIZE, dfu_buffer, sizeof(dfu_buffer)); 307 | usbd_reg_config(&dfu, dfu_config); 308 | usbd_reg_control(&dfu, dfu_control); 309 | usbd_reg_descr(&dfu, dfu_get_descriptor); 310 | usbd_enable(&dfu, 1); 311 | usbd_connect(&dfu, 1); 312 | } 313 | 314 | int main (void) { 315 | dfu_init(); 316 | while(1) { 317 | usbd_poll(&dfu); 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /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 | static char *strsign(const void *data, size_t len) { 49 | static char s[0x100]; 50 | char *t = s; 51 | static const char *digits = "0123456789ABCDEF"; 52 | const uint8_t *buf = data; 53 | while(len--) { 54 | *t++ = digits[*buf >> 4]; 55 | *t++ = digits[*buf & 0x0F]; 56 | buf++; 57 | } 58 | *t = '\0'; 59 | return s; 60 | } 61 | 62 | static uint32_t get_vidpid(const char *data) { 63 | uint32_t vid, pid; 64 | if (2 == sscanf(data, "%x:%x", &vid, &pid)) { 65 | if (vid <= 0xFFFF && pid <= 0xFFFF) { 66 | return vid << 16 | pid; 67 | } 68 | } 69 | return 0; 70 | } 71 | 72 | static const uint32_t crc_table[] = { 73 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 74 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 75 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 76 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 77 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 78 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 79 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 80 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 81 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 82 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 83 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 84 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 85 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 86 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 87 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 88 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 89 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 90 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 91 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 92 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 93 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 94 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 95 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 96 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 97 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 98 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 99 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 100 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 101 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 102 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 103 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 104 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 105 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 106 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 107 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 108 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 109 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 110 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 111 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 112 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 113 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 114 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 115 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; 116 | 117 | 118 | static uint32_t compute_dfu_crc(const void *data, size_t length) { 119 | const uint8_t *src = data; 120 | uint32_t crc = 0xFFFFFFFFU; 121 | while(length--) { 122 | crc = crc_table[0xFFU & (crc ^ *src++)] ^ (crc >> 8); 123 | } 124 | return crc; 125 | } 126 | 127 | 128 | int main(int argc, char **argv) 129 | { 130 | int dir = 1; 131 | int crc = 1; 132 | int dry = 0; 133 | int enc = 1; 134 | char *infile = NULL; 135 | char *outfile = NULL; 136 | int c; 137 | uint32_t vidpid = 0; 138 | 139 | opterr = 0; 140 | 141 | while ((c = getopt(argc, argv, "edchnCi:o:v:")) != -1) 142 | switch (c) 143 | { 144 | case 'C': 145 | enc = 0; 146 | break; 147 | case 'e': 148 | dir = 1; 149 | break; 150 | case 'd': 151 | dir = 0; 152 | break; 153 | case 'c': 154 | crc = 0; 155 | break; 156 | case 'n': 157 | dry = 1; 158 | break; 159 | case 'i': 160 | infile = optarg; 161 | break; 162 | case 'o': 163 | outfile = optarg; 164 | break; 165 | case 'v': 166 | vidpid = get_vidpid(optarg); 167 | if (vidpid == 0) { 168 | printf("Error parsing VID:PID :\"%s\"\n", optarg); 169 | exit(-1); 170 | } 171 | break; 172 | case 'h': 173 | case '?': 174 | exithelp(); 175 | break; 176 | default: 177 | exit(-1); 178 | } 179 | 180 | if (infile == NULL) { 181 | exithelp(); 182 | } 183 | 184 | if (!enc && !crc) { 185 | printf("Nothing to do. Exiting.\n"); 186 | exit(0); 187 | } 188 | 189 | FILE *fi = fopen(infile, "rb"); 190 | if (fi == NULL) { 191 | printf("Failed to open file: %s\n", argv[optind]); 192 | exit(1); 193 | } 194 | 195 | fseek(fi, 0, SEEK_END); 196 | size_t length = ftell(fi); 197 | fseek(fi, 0, SEEK_SET); 198 | 199 | 200 | size_t blen = length + 0x1000; 201 | uint32_t *buf = malloc(blen); 202 | uint8_t *buf8 = (uint8_t*)buf; 203 | 204 | if (buf == NULL) { 205 | printf("Failed to allocate buffer. length %zd\n", blen); 206 | exit(3); 207 | } 208 | 209 | if (length != fread(buf, 1, length, fi)) { 210 | printf("Failed to read input file."); 211 | exit(4); 212 | } 213 | fclose(fi); 214 | 215 | aes_init(); 216 | if (dir) { 217 | #if (DFU_VERIFY_CHECKSUM != _DISABLE) 218 | if (crc) { 219 | size_t newlen = append_checksum(buf, length, blen); 220 | 221 | printf("Firmware length: %zd bytes, signature: (%s) %s\n", 222 | length, 223 | checksum_name, 224 | strsign(&buf8[length], checksum_length) 225 | ); 226 | 227 | printf("Validating firmware signature. "); 228 | size_t checked_length = validate_checksum(buf, blen); 229 | 230 | if (checked_length != length ) { 231 | printf("FAIL. Collision found at offset %zd\n", checked_length); 232 | exit(-3); 233 | } else { 234 | printf("OK.\n"); 235 | } 236 | length = newlen; 237 | } 238 | #endif 239 | 240 | #if(DFU_CIPHER != _DISABLE) 241 | if (enc) { 242 | if (length % aes_blksize) { 243 | length += (aes_blksize - (length % aes_blksize)); 244 | } 245 | printf("Encrypting %zd bytes using %s cipher.\n", length, aes_name); 246 | aes_encrypt(buf, buf, length); 247 | } else { 248 | printf("Skipping encryption.\n"); 249 | } 250 | #endif 251 | 252 | if (vidpid != 0) { 253 | printf("Appending DFU suffix\n"); 254 | dfu_suffix_t *dfu_suffix = (void*)(&((uint8_t*)buf)[length]); 255 | length += sizeof(dfu_suffix_t); 256 | dfu_suffix->bcdDevice = 0xFFFF; 257 | dfu_suffix->idProduct = vidpid; 258 | dfu_suffix->idVendor = vidpid >> 16; 259 | dfu_suffix->bcdDFU = 0x0101; 260 | dfu_suffix->ucDfuSignature[0] = 'U'; 261 | dfu_suffix->ucDfuSignature[1] = 'F'; 262 | dfu_suffix->ucDfuSignature[2] = 'D'; 263 | dfu_suffix->bLength = 16; 264 | dfu_suffix->dwCRC = compute_dfu_crc(buf, length - 4); 265 | } 266 | 267 | } else { 268 | 269 | #if(DFU_CIPHER != _DISABLE) 270 | if (enc) { 271 | printf("Decrypting %zd bytes using %s cipher.\n", length, aes_name); 272 | aes_decrypt(buf, buf, length); 273 | } else { 274 | printf("Skipping decryption.\n"); 275 | } 276 | #endif 277 | 278 | #if (DFU_VERIFY_CHECKSUM != _DISABLE) 279 | if (crc) { 280 | size_t checked_length = validate_checksum(buf, blen); 281 | if (checked_length == 0) { 282 | printf("No valid signature found.\n"); 283 | } else { 284 | printf("Valid signature (%s) %s found at offset %zd\n", 285 | checksum_name, 286 | strsign(&buf8[checked_length], checksum_length), 287 | checked_length 288 | ); 289 | length = checked_length; 290 | } 291 | } 292 | #endif 293 | 294 | } 295 | if (dry || outfile == NULL) { 296 | printf("Writing %zd bytes. Dry run.\n", length); 297 | } else { 298 | FILE *fo = fopen(outfile, "wb"); 299 | if (fo == NULL) { 300 | printf("Failed to open file: %s\n", argv[optind]); 301 | exit(2); 302 | } 303 | 304 | fwrite(buf, 1, length, fo); 305 | fclose(fo); 306 | } 307 | free(buf); 308 | return 0; 309 | } 310 | -------------------------------------------------------------------------------- /README.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 | | LIBUSB_PATH | ./usb | path to USB library | 78 | | LOADER_OUT | ./build/firmware.elf | output file for bootloader | 79 | | SCRAMBLER_OUT | ./build/fwcrypt | output file for scrambler | 80 | | OUTDIR | build | output folder for binaries (deprecated) | 81 | | FWNAME | firmware | name for bootloader binary (deprecated) | 82 | | SWNAME | fwcrypt | name for encrypter binary (deprecated) | 83 | 84 | 4. MCU targets 85 | 86 | | mcu_target | MCU | remarks | 87 | |---------------|----------------------------------------------------|-----------------| 88 | | stm32l100x6a | STM32L100C6-A | | 89 | | stm32l100x8a | STM32L100R8-A | | 90 | | stm32l100xba | STM32L100RB-A | | 91 | | stm32l100xc | STM32L100RC | tested | 92 | | stm32l151x6a | STM32L151C6-A, STM32L151R6-A | | 93 | | stm32l151x8a | STM32L151C8-A, STM32L151R8-A, STM31L151V8-A | | 94 | | stm32l151xba | STM32L151CB-A, STM32L151RB-A, STM31L151VB-A | | 95 | | stm32l151xc | STM32L151CC, STM32L151QC, SRM32L151RC, STM32L151UC | | 96 | | stm32l151xd | STM32L151QD, STM32L151RD, STM32L151VD, STM32L151ZD | | 97 | | stm32l151xe | STM32L151QE, STM32L151RE, STM32L151VE, STM32L151ZE | | 98 | | stm32l152x6a | STM32L152C6-A, STM32L152R6-A | | 99 | | stm32l152x8a | STM32L152C8-A, STM32L152R8-A, STM31L152V8-A | | 100 | | stm32l152xba | STM32L152CB-A, STM32L152RB-A, STM31L152VB-A | | 101 | | stm32l152xc | STM32L152CC, STM32L152QC, SRM32L152RC, STM32L152UC | | 102 | | stm32l152xd | STM32L152QD, STM32L152RD, STM32L152VD, STM32L152ZD | | 103 | | stm32l152xe | STM32L152QE, STM32L152RE, STM32L152VE, STM32L152ZE | | 104 | | stm32l162xc | STM32L162RC, STM32L162VC | | 105 | | stm32l162xd | STM32L162QD, STM32L156RD, STM32L162VD, STM32L162ZD | | 106 | | stm32l162xe | STM32L162QE, STM32L156RE, STM32L162VE, STM32L162ZE | | 107 | | stm32l052x6 | STM32L052K6, STM32L052T6, STM32L052C6, STM32L052R6 | | 108 | | stm32l052x8 | STM32L052K8, STM32L052T8, STM32L052C8, STM32L052R8 | tested, default | 109 | | stm32l053x6 | STM32L053C6, STM32L053R6 | | 110 | | stm32l053x8 | STM32L053C8, STM32L053R8 | | 111 | | stm32l062x8 | STM32L062K8 | | 112 | | stm32l063x8 | STM32L063C8, STM32L063R8 | | 113 | | stm32l072v8 | STM32L072V8 | | 114 | | stm32l072xb | STM32L072KB, STM32L072CB, STM32L072RB, STM32L072VB | tested | 115 | | stm32l072xz | STM32L072KZ, STM32L072CZ, STM32L072RZ, STM32L072VZ | | 116 | | stm32l073v8 | STM32L073V8 | | 117 | | stm32l073xb | STM32L073CB, STM32L073RB, STM32L073VB | | 118 | | stm32l073xz | STM32L073CZ, STM32L073RZ, STM32L073VZ | | 119 | | stm32l476xc | STM32L476RC, STM32L476VC | | 120 | | stm32l476xe | STM32L476RE, STM32L476JE, STM32L476ME, STM32L476VE | | 121 | | stm32l476xg | STM32L476RG, STM32L476JG, STM32L476MG, STM32L476VG | tested | 122 | | stm32f103x6 | STM32F103T6, STM32F103C6, STM32F103R6 | | 123 | | stm32f103x8 | STM32F103T8, STM32F103C8, STM32F103R8, STM32f103V8 | tested | 124 | | stm32f105xb | STM32F105RB, STM32F105VB | tested | 125 | | stm32f107xb | STM32F107RB, STM32F107VB | tested | 126 | | stm32l433xb | STM32L433CB, STM32L433RB | | 127 | | stm32l433xc | STM32L433CC, STM32L433RC, STM32L433VC | tested | 128 | | stm32f070x6 | STM32F070C6 | | 129 | | stm32f070xb | STM32F070CB | tested | 130 | | stm32f429xe | STM32F429xE series (single bank mode) | | 131 | | stm32f429xg | STM32F429xG series (single bank mode) | | 132 | | stm32f429xi | STM32F429xI series (single and dual bank) | tested | 133 | | stm32g431x6 | STM32G431x6, STM32G441x6 | | 134 | | stm32g431x8 | STM32G431x8, STM32G441x8 | | 135 | | stm32g431xb | STM32G431xB, STM32G441xB | tested G431RB | 136 | | stm32g474xb | STM32G471xB, STM32G473xB, STM32G474xB, STM32G483xB | | 137 | | stm32g474xc | STM32G471xC, STM32G473xC, STM32G474xC, STM32G483xC | | 138 | | stm32g474xe | STM32G471xE, STM32G473xE, STM32G474xE, STM32G483xE | tested G747RE | 139 | | stm32f303xe | STM32F303xE | tested | 140 | | stm32f373xc | STM32F373xC | tested | 141 | 142 | #### Adjusting user firmware 143 | + Check bootloader's linker map for the ````__app_start```` address. This is the new ROM origin for the user firmware (ISR vectors). 144 | + Adjust your linker script to set new ROM origin and ROM length. 145 | 146 | #### Utilizing usbd core and usbd driver from bootloader in the user firmware 147 | + 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. 148 | + Add address for usbd_driver structure to your linker script. For example ````usbd_drv = 0x08000040;```` 149 | + Add address for usbd_poll entry point to your linker script. For example ````usbd_poll = 0x08000074;```` 150 | + Add ````extern struct usbd_driver usbd_drv;```` driver declaration to your code. 151 | + Include at least "usbd_core.h" and "usb_std.h" to your code. 152 | 153 | 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. 154 | 155 | #### Activating bootloader 156 | + Write DFU_BOOTKEY at DFU_BOOTKEY_ADDR (RAM top by default) and make a software reset. 157 | + Assert DFU_BOOTSTRAP_PIN on DFU_BOOTSTRAP_PORT on startup (optional). 158 | + Make a double reset during the DFU_DBLRESET_MS period (optional). 159 | 160 | #### Encrypting user firmware 161 | We provide a utility for encryption and decryption of firmware images. At this moment, only raw binary files are supported. 162 | 163 | To encrypt: 164 | ```` 165 | fwcrypt -e -i infile.bin -o outfile.bin 166 | ```` 167 | To decrypt: 168 | ```` 169 | fwcrypt -d -i infile.bin -o outfile.bin 170 | ```` 171 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | } -------------------------------------------------------------------------------- /mcu/stm32f103.S: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #define FLASH_R_BASE 0x40022000 3 | #define FLASH_ACR 0x00 4 | #define FLASH_KEYR 0x04 5 | #define FLASH_OPTKEYR 0x08 6 | #define FLASH_SR 0x0C 7 | #define FLASH_CR 0x10 8 | #define FLASH_AR 0x14 9 | #define FLASH_OBR 0x1C 10 | #define FLASH_WRPR 0x20 11 | #define FLASH_OP_BASE 0x1FFFF800 12 | 13 | 14 | #define FLASH_KEY0 0x45670123 15 | #define FLASH_KEY1 0xCDEF89AB 16 | #define FLASH_PAGESZ 0x200 17 | 18 | #define RCC_BASE 0x40021000 19 | #define RCC_CR 0x00 20 | #define RCC_CFGR 0x04 21 | #define RCC_APB2RSTR 0x0C 22 | #define RCC_APB2ENR 0x18 23 | 24 | #define GPIOA 0x40010800 25 | #define GPIOB 0x40010C00 26 | #define GPIOC 0x40011000 27 | #define GPIOD 0x40011400 28 | #define GPIOE 0x40011800 29 | #define GPIOF 0x40011C00 30 | #define GPIOG 0x40012000 31 | 32 | #define GPIO_CRL 0x00 33 | #define GPIO_CRH 0x04 34 | #define GPIO_IDR 0x08 35 | #define GPIO_BSRR 0x10 36 | 37 | #define SCB 0xE000ED00 38 | #define SCB_VTOR 0x08 39 | #define SCB_AIRCR 0x0C 40 | 41 | #if (DFU_APP_START == _AUTO) 42 | #define _APP_START __app_start 43 | #else 44 | #define _APP_START DFU_APP_START 45 | #endif 46 | 47 | #if (DFU_BOOTKEY_ADDR == _AUTO) || (DFU_BOOTKEY_ADDR == _DISABLE) 48 | #define _KEY_ADDR __stack 49 | #else 50 | #define _KEY_ADDR DFU_BOOTKEY_ADDR 51 | #endif 52 | 53 | #if (DFU_BOOTSTRAP_GPIO == _DISABLE) 54 | #define BOOTSTRAP_RCC 0x00 55 | #elif (DFU_BOOTSTRAP_GPIO == GPIOA) 56 | #define BOOTSTRAP_RCC 0x04 57 | #elif (DFU_BOOTSTRAP_GPIO == GPIOB) 58 | #define BOOTSTRAP_RCC 0x08 59 | #elif (DFU_BOOTSTRAP_GPIO == GPIOC) 60 | #define BOOTSTRAP_RCC 0x10 61 | #elif (DFU_BOOTSTRAP_GPIO == GPIOD) 62 | #define BOOTSTRAP_RCC 0x20 63 | #elif (DFU_BOOTSTRAP_GPIO == GPIOE) 64 | #define BOOTSTRAP_RCC 0x40 65 | #elif (DFU_BOOTSTRAP_GPIO == GPIOF) 66 | #define BOOTSTRAP_RCC 0x80 67 | #else 68 | #error Incorrect GPIO settings. Check Config!! 69 | #endif 70 | 71 | #if (DFU_BOOTSTRAP_PIN >= 0) && (DFU_BOOTSTRAP_PIN <= 7) 72 | #define BOOTSTRAP_CRx GPIO_CRL 73 | #elif (DFU_BOOTSTRAP_PIN >= 8) && (DFU_BOOTSTRAP_PIN <= 15) 74 | #define BOOTSTRAP_CRx GPIO_CRH 75 | #elif ((DFU_BOOTSTRAP_GPIO != _DISABLE)) 76 | #error Incorrect DFU_BOOTSTRAP_PIN . Check config !! 77 | #endif 78 | 79 | .syntax unified 80 | .cpu cortex-m3 81 | .fpu softvfp 82 | .thumb 83 | 84 | .section .isr_vector 85 | .align 2 86 | .globl __isr_vector 87 | __isr_vector: 88 | .long __stack /* 0x000 Reset MSP value */ 89 | .long Reset_Handler /* 0x004 Reset */ 90 | .long NMI_Handler /* 0x008 NMI */ 91 | 92 | .word HardFault_Handler /* 0x00C All class of fault */ 93 | .word MemManage_Handler /* 0x010 Memory management */ 94 | .word BusFault_Handler /* 0x014 Pre-fetch fault, memory access fault */ 95 | .word UsageFault_Handler /* 0x018 Undefined instruction or illegal state */ 96 | .word 0 /* 0x01C Reserved */ 97 | .word 0 /* 0x020 Reserved */ 98 | .word 0 /* 0x024 Reserved */ 99 | .word 0 /* 0x028 Reserved */ 100 | .word SVC_Handler /* 0x02C System service call via SWI instruction */ 101 | .word DebugMon_Handler /* 0x030 Debug monitor */ 102 | .word 0 /* 0x034 Reserved */ 103 | .word PendSV_Handler 104 | .word SysTick_Handler 105 | /* Peripheral interrupts are not used */ 106 | .size __isr_vector, . - __isr_vector 107 | 108 | .section .text 109 | .thumb_func 110 | 111 | .globl System_Reset 112 | .type System_Reset, %function 113 | 114 | .globl Reset_Handler 115 | .type Reset_Handler, %function 116 | Reset_Handler: 117 | /* pulling down GPIOA12 GPIOA11 (USB-DP)*/ 118 | /* this will force re-enumeration. Very useful if no DP control pin used */ 119 | ldr r5, = RCC_BASE 120 | movs r2, 0x04 121 | strb r2, [r5, RCC_APB2ENR] 122 | ldr r1, = GPIOA 123 | ldr r2, [r1, GPIO_CRH] 124 | ldr r3, = 0x000FF000 125 | bics r2, r3 126 | ldr r3, = 0x00022000 127 | orrs r2, r3 128 | str r2, [r1, GPIO_CRH] 129 | ldr r2, = 0x18000000 130 | str r2, [r1, GPIO_BSRR] 131 | /* Check key */ 132 | ldr r1, = _KEY_ADDR 133 | ldr r2, = DFU_BOOTKEY 134 | movs r3, 0x00 135 | ldr r4, [r1] 136 | str r3, [r1] 137 | eors r4, r2 //R4: 0xFFFFFFFF - force APP; 0x00000000 - force BOOT 138 | 139 | /* Storing DFU_BOOTKEY at DFU_BOOTKEY_ADDR and do a delay. 140 | * STM32F103 startup clock is 8.0MHz HSI 141 | * so, we need T(mS)*8000 ticks to make a required delay 142 | * In case of RESET at this time bootloader will start from code above. 143 | */ 144 | #if (DFU_DBLRESET_MS != DISABLE) 145 | str r2, [r1] 146 | #endif 147 | /* At least 20 ms delay with pulled low DP+ DP- */ 148 | #if (DFU_DBLRESET_MS > 20) 149 | #define USB_RST_MS DFU_DBLRESET_MS 150 | #else 151 | #define USB_RST_MS 20 152 | #endif 153 | ldr r3, = (USB_RST_MS * 8000 / 3) 154 | .L_rst_delay: 155 | subs r3, 1 //+1 tick 156 | bne .L_rst_delay //+2 ticks, 3 ticks/cycle 157 | str r3, [r1] 158 | /* Reset GPIOA */ 159 | movs r2, 0x04 160 | strb r2, [r5, RCC_APB2RSTR] 161 | strb r3, [r5, RCC_APB2RSTR] //R3 = 0 162 | /* Continue with key */ 163 | mvns r0, r4 164 | bne .L_check_boot 165 | /* jump to user section */ 166 | ldr r0, = _APP_START 167 | ldr r1, = SCB 168 | str r0, [r1, SCB_VTOR] //set VTOR 169 | ldr r1, [r0, 0x00] //load new MSP 170 | msr MSP, r1 //set MSP 171 | ldr r3, [r0, 0x04] //load reet vector 172 | bx r3 //jump to user_app 173 | .L_check_boot: 174 | /* Setup clock 48Mhz HSI PLL for USB */ 175 | /* set flash latency 1 */ 176 | ldr r3, = FLASH_R_BASE 177 | movs r0, 0x31 178 | str r0, [r3, FLASH_ACR] 179 | /* setup RCC */ 180 | movs r2, 0x68 // PLLMIL12 | USB_PRE 181 | strb r2, [r5, RCC_CFGR + 2] 182 | movs r2, 0x01 183 | strb r2, [r5, RCC_CR + 3] 184 | .L_wait_PLL: 185 | ldr r0, [r5, RCC_CR] 186 | lsrs r0, 26 // PLLRDY -> CF 187 | bcc .L_wait_PLL 188 | /* switch to PLL */ 189 | movs r2, 0x02 190 | strb r2, [r5, RCC_CFGR + 0] 191 | cbz r4, .L_start_boot 192 | 193 | #if (DFU_BOOTSTRAP_GPIO != _DISABLE) 194 | /* checking bootstrap pin */ 195 | movs r2, BOOTSTRAP_RCC 196 | strb r2, [r5, RCC_APB2ENR] 197 | ldr r1, = DFU_BOOTSTRAP_GPIO 198 | ldr r3, = (0x0F << ((DFU_BOOTSTRAP_PIN & 0x07) << 2)) 199 | #if (DFU_BOOTSTRAP_PULL == _DISABLE) 200 | ldr r2, = (0x00 << ((DFU_BOOTSTRAP_PIN & 0x07) << 2)) 201 | #else 202 | ldr r2, = (0x08 << ((DFU_BOOTSTRAP_PIN & 0x07) << 2)) 203 | #endif 204 | ldr r4, [r1, BOOTSTRAP_CRx] 205 | bics r4, r3 206 | orrs r4, r2 207 | str r4, [r1, BOOTSTRAP_CRx] 208 | #if ((DFU_BOOTSTRAP_PULL == _LOW) || ((DFU_BOOTSTRAP_PULL == _AUTO) && (DFU_BOOTSTRAP_LEVEL == _HIGH))) 209 | ldr r2, = (0x01 << (DFU_BOOTSTRAP_PIN * 2)) //pulldown 210 | #else 211 | ldr r2, = (0x01 << DFU_BOOTSTRAP_PIN) //pullup 212 | #endif 213 | str r2, [r1, GPIO_BSRR] 214 | movs r4, 0x08 215 | .L_scan_bootstrap: 216 | ldr r2, [r1, GPIO_IDR] 217 | lsrs r2, (DFU_BOOTSTRAP_PIN + 1) //Pin -> CF 218 | sbcs r3, r3 219 | movs r2, 0x01 220 | orrs r2, r3 221 | #if (DFU_BOOTSTRAP_LEVEL == _HIGH) 222 | subs r4, r2 223 | #else 224 | adds r4, r2 225 | #endif 226 | beq .L_start_boot 227 | cmp r4, 0x10 228 | bne .L_scan_bootstrap 229 | #endif 230 | 231 | #if (DFU_VERIFY_CHECKSUM != _DISABLE) 232 | ldr r0, = _APP_START 233 | ldr r1, = __romend 234 | subs r1, r0 235 | bl validate_checksum 236 | cbz r0, .L_start_boot 237 | #endif 238 | /* Reset and start app */ 239 | ldr r1, = _KEY_ADDR 240 | ldr r2, = DFU_BOOTKEY 241 | mvns r2, r2 242 | str r2, [r1] 243 | System_Reset: 244 | dsb 245 | ldr r1, = SCB 246 | ldr r2, = 0x05FA0004; 247 | str r2, [r1, SCB_AIRCR] 248 | b . 249 | 250 | /* jump to bootloader */ 251 | .L_start_boot: 252 | /* do copy data */ 253 | ldr r1, = __etext 254 | ldr r2, = __data_start__ 255 | ldr r3, = __data_end__ 256 | .L_copy_data: 257 | ldr r0, [r1], 0x04 258 | str r0, [r2], 0x04 259 | cmp r3, r2 260 | bhi .L_copy_data 261 | .L_clear_bss: 262 | movs r0, 0x00 263 | ldr r2, = __bss_start__ 264 | ldr r3, = __bss_end__ 265 | .L_clear_bss_loop: 266 | str r0, [r2], 0x04 267 | cmp r3, r2 268 | bhi .L_clear_bss_loop 269 | 270 | #if (DFU_SEAL_LEVEL != 0) 271 | ldr r3, = seal_flash 272 | blx r3 273 | #endif 274 | bl main 275 | .size Reset_Handler, .-Reset_Handler 276 | 277 | 278 | .thumb_func 279 | .type _default_handler, %function 280 | _default_handler: 281 | b . 282 | .size _default_handler, . - _default_handler 283 | 284 | 285 | .pool 286 | 287 | .macro def_irq_handler handler_name 288 | .weak \handler_name 289 | .thumb_set \handler_name, _default_handler 290 | .endm 291 | 292 | 293 | def_irq_handler NMI_Handler 294 | def_irq_handler HardFault_Handler 295 | def_irq_handler MemManage_Handler 296 | def_irq_handler BusFault_Handler 297 | def_irq_handler UsageFault_Handler 298 | def_irq_handler SVC_Handler 299 | def_irq_handler DebugMon_Handler 300 | def_irq_handler PendSV_Handler 301 | def_irq_handler SysTick_Handler 302 | 303 | .section .data 304 | .align 2 305 | .thumb_func 306 | .globl program_flash 307 | .type program_flash, %function 308 | /* R0 <- address to flash 309 | * R1 <- buffer 310 | * R2 <- block size (nonzero less than 0x40) 311 | * R0 -> DFU_STATUS 312 | */ 313 | program_flash: 314 | push {r4, r5, lr} 315 | /* checking halfword alignment */ 316 | lsrs r4, r0, 0x01 317 | bcs Err_unaligned 318 | /* unlocking flash */ 319 | ldr r3, = FLASH_R_BASE 320 | ldr r4, = FLASH_KEY0 321 | ldr r5, = FLASH_KEY1 322 | str r4, [r3, FLASH_KEYR] 323 | str r5, [r3, FLASH_KEYR] 324 | /* main flash loop */ 325 | .L_flash_loop: 326 | subs r2, 0x02 327 | blt Err_done 328 | #if defined(STM32F103xE) 329 | /* check for the page start (2k page) on STM32F103xC/D/E devices*/ 330 | lsls r4, r0, 21 331 | #else 332 | /* check for the page start (1k page)*/ 333 | lsls r4, r0, 22 334 | #endif 335 | bne .L_do_write 336 | /* erasing page */ 337 | movs r4, 0x02 // PER 338 | str r4, [r3, FLASH_CR] 339 | str r0, [r3, FLASH_AR] 340 | movs r4, 0x42 // PER + START 341 | str r4, [r3, FLASH_CR] 342 | bl wait_prog_done 343 | bcc Err_erase 344 | .L_do_write: 345 | mov r4, 0x01 // PG 346 | str r4, [r3, FLASH_CR] 347 | ldrh r5, [r1] 348 | strh r5, [r0] 349 | bl wait_prog_done 350 | bcc Err_prog 351 | ldrh r4, [r0] 352 | cmp r5, r4 353 | bne Err_verify 354 | adds r0, 0x02 355 | adds r1, 0x02 356 | b .L_flash_loop 357 | Err_done: 358 | movs r0, 0x00 //OK 359 | b .L_exit 360 | Err_unaligned: 361 | movs r0, 0x03 //errWRITE (unaligned access) 362 | b .L_exit 363 | Err_erase: 364 | movs r0, 0x04 //errERASE 365 | b .L_exit 366 | Err_prog: 367 | movs r0, 0x06 //errPROG 368 | b .L_exit 369 | Err_verify: 370 | movs r0, 0x07 //errVERIFY 371 | .L_exit: 372 | /* clear FLASH_SR */ 373 | movs r4, 0x34 374 | str r4, [r3, FLASH_SR] 375 | /* locking flash */ 376 | movs r4, 0x80 377 | str r4, [r3, FLASH_CR] 378 | pop {r4, r5, pc} 379 | .size program_flash, . - program_flash 380 | 381 | 382 | .thumb_func 383 | .type wait_prog_done, %function 384 | wait_prog_done: 385 | ldr r4, [r3, FLASH_SR] 386 | lsrs r4, 0x01 //BSY -> CF 387 | bcs wait_prog_done //wait BSY low 388 | lsrs r4, 0x05 //EOP -> CF 389 | ldr r4, [r3, FLASH_SR] 390 | str r4, [r3, FLASH_SR] // clean FLASH_SR 391 | bx lr 392 | 393 | 394 | #if (DFU_SEAL_LEVEL != 0) 395 | .thumb_func 396 | .type seal_flash, %function 397 | /* R0 -> DFU_STATUS */ 398 | seal_flash: 399 | ldr r3, = FLASH_R_BASE 400 | ldr r0, [r3, FLASH_OBR] 401 | lsrs r0, 2 //RDPRT -> CF 402 | bcc .L_seal 403 | bx lr 404 | .L_seal: 405 | /* unlocking flash */ 406 | ldr r1, = FLASH_KEY0 407 | ldr r2, = FLASH_KEY1 408 | str r1, [r3, FLASH_KEYR] 409 | str r2, [r3, FLASH_KEYR] 410 | /* unlocking OPTION programming */ 411 | str r1, [r3, FLASH_OPTKEYR] 412 | str r2, [r3, FLASH_OPTKEYR] 413 | /* erasing OPTION data. */ 414 | movs r1, 0x20 // OPTER 415 | str r1, [r3, FLASH_CR] 416 | movs r1, 0x60 // START + OPTER 417 | str r1, [r3, FLASH_CR] 418 | bl wait_prog_done 419 | /* set RDP */ 420 | movs r1, 0x10 421 | str r1, [r3, FLASH_CR] 422 | ldr r0, = FLASH_OP_BASE 423 | ldr r1, = 0x33CC 424 | strh r1, [r0, 0x00] 425 | bl wait_prog_done 426 | /* reset */ 427 | ldr r3, = SCB 428 | ldr r1, = 0x05FA0004 429 | str r1, [r3, SCB_AIRCR] 430 | b . //loop forever till reset 431 | .size seal_flash, . - seal_flash 432 | #endif 433 | 434 | .pool 435 | 436 | 437 | .end 438 | -------------------------------------------------------------------------------- /mcu/stm32l4xx.S: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #define FLASH_R_BASE 0x40022000 3 | #define FLASH_ACR 0x00 4 | #define FLASH_KEYR 0x08 5 | #define FLASH_OPTKEYR 0x0C 6 | #define FLASH_SR 0x10 7 | #define FLASH_CR 0x14 8 | #define FLASH_OPTR 0x20 9 | #define FLASH_PRGKEY0 0x45670123 10 | #define FLASH_PRGKEY1 0xCDEF89AB 11 | #define FLASH_OPTKEY0 0x08192A3B 12 | #define FLASH_OPTKEY1 0x4C5D6E7F 13 | 14 | #define RCC_BASE 0x40021000 15 | #define RCC_CR 0x00 16 | #define RCC_AHB2RSTR 0x2C 17 | #define RCC_AHB2ENR 0x4C 18 | #define RCC_APB1ENR1 0x58 19 | #define RCC_CCIPR 0x88 20 | 21 | #define PWR_BASE 0x40007000 22 | #define PWR_CR1 0x00 23 | #define PWR_CR2 0x04 24 | #define PWR_SR2 0x14 25 | 26 | #define GPIOA 0x48000000 27 | #define GPIOB 0x48000400 28 | #define GPIOC 0x48000800 29 | #define GPIOD 0x48000C00 30 | #define GPIOE 0x48001000 31 | #define GPIOF 0x48001400 32 | #define GPIOG 0x48001800 33 | #define GPIOH 0x48001C00 34 | 35 | #define GPIO_MODER 0x00 36 | #define GPIO_PUPDR 0x0C 37 | #define GPIO_IDR 0x10 38 | #define GPIO_AFRL 0x20 39 | #define GPIO_AFRH 0x24 40 | 41 | #define SCB 0xE000ED00 42 | #define SCB_VTOR 0x08 43 | #define SCB_AIRCR 0x0C 44 | 45 | #if (DFU_APP_START == _AUTO) 46 | #define _APP_START __app_start 47 | #else 48 | #define _APP_START DFU_APP_START 49 | #endif 50 | 51 | #if (DFU_BOOTKEY_ADDR == _AUTO) || (DFU_BOOTKEY_ADDR == _DISABLE) 52 | #define _KEY_ADDR __stack 53 | #else 54 | #define _KEY_ADDR DFU_BOOTKEY_ADDR 55 | #endif 56 | 57 | #if (DFU_BOOTSTRAP_GPIO == _DISABLE) 58 | #define BOOTSTRAP_RCC 0x00 59 | #elif (DFU_BOOTSTRAP_GPIO == GPIOA) 60 | #define BOOTSTRAP_RCC 0x01 61 | #elif (DFU_BOOTSTRAP_GPIO == GPIOB) 62 | #define BOOTSTRAP_RCC 0x02 63 | #elif (DFU_BOOTSTRAP_GPIO == GPIOC) 64 | #define BOOTSTRAP_RCC 0x04 65 | #elif (DFU_BOOTSTRAP_GPIO == GPIOD) 66 | #define BOOTSTRAP_RCC 0x08 67 | #elif (DFU_BOOTSTRAP_GPIO == GPIOE) 68 | #define BOOTSTRAP_RCC 0x10 69 | #elif (DFU_BOOTSTRAP_GPIO == GPIOH) 70 | #define BOOTSTRAP_RCC 0x20 71 | #elif (DFU_BOOTSTRAP_GPIO == GPIOF) 72 | #define BOOTSTRAP_RCC 0x40 73 | #elif (DFU_BOOTSTRAP_GPIO == GPIOG) 74 | #define BOOTSTRAP_RCC 0x80 75 | #else 76 | #error Incorrect DFU_BOOTSTRAP_GPIO. Check Config!! 77 | #endif 78 | 79 | #if ((DFU_BOOTSTRAP_PIN < 0) || (DFU_BOOTSTRAP_PIN > 15)) && (DFU_BOOTSTRAP_GPIO != _DISABLE) 80 | #error Incorrect DFU_BOOTSTRAP_PIN. Check config !! 81 | #endif 82 | 83 | .syntax unified 84 | .cpu cortex-m4 85 | .thumb 86 | 87 | .section .isr_vector 88 | .align 2 89 | .globl __isr_vector 90 | __isr_vector: 91 | .long __stack 92 | .long Reset_Handler 93 | .long NMI_Handler 94 | .long HardFault_Handler 95 | .long MemManage_Handler 96 | .long BusFault_Handler 97 | .long UsageFault_Handler 98 | .long 0 99 | .long 0 100 | .long 0 101 | .long 0 102 | .long SVC_Handler 103 | .long DebugMon_Handler 104 | .long 0 105 | .long PendSV_Handler 106 | .long SysTick_Handler 107 | /* Peripheral interrupts are not used */ 108 | .size __isr_vector, . - __isr_vector 109 | 110 | .section .text 111 | .thumb_func 112 | 113 | .globl System_Reset 114 | .type System_Reset, %function 115 | 116 | .globl Reset_Handler 117 | .type Reset_Handler, %function 118 | Reset_Handler: 119 | ldr r1, = _KEY_ADDR 120 | ldr r2, = DFU_BOOTKEY 121 | movs r3, 0x00 122 | ldr r4, [r1] 123 | str r3, [r1] 124 | eors r4, r2 //R4: 0xFFFFFFFF - force APP; 0x00000000 - force BOOT 125 | mvns r0, r4 126 | bne .L_check_boot 127 | /* jump to user section */ 128 | ldr r0, = _APP_START 129 | ldr r1, = SCB 130 | str r0, [r1, SCB_VTOR] //set VTOR 131 | ldr r1, [r0, 0x00] //load new MSP 132 | msr MSP, r1 //set MSP 133 | ldr r3, [r0, 0x04] //load reet vector 134 | bx r3 //jump to user_app 135 | .L_check_boot: 136 | #if (DFU_DBLRESET_MS != _DISABLE) 137 | /* Storing DFU_BOOTKEY at DFU_BOOTKEY_ADDR and do a delay. 138 | * In case of RESET at this time bootloader will start from code above. */ 139 | str r2, [r1] 140 | /* STM32L4 startup clock is about 4.0MHz MSI 141 | * so, we need T(mS)*4000 ticks to make a required delay */ 142 | ldr r0, = (DFU_DBLRESET_MS * 4000 / 3) 143 | .L_rst_delay: 144 | subs r0, 1 //+1 tick 145 | bhs .L_rst_delay //+2 ticks, 3 ticks/cycle 146 | /* Clearing bootkey and continue */ 147 | str r3, [r1] 148 | #endif 149 | /* Setup clock */ 150 | /* Enabling PWR interface */ 151 | ldr r5, = RCC_BASE 152 | mov r1, (1 << 28) /* PWREN */ 153 | str r1, [r5, RCC_APB1ENR1] 154 | ldr r6, = PWR_BASE 155 | /* Setting power Range 1 */ 156 | lsrs r1, 19 /* Range 1 */ 157 | str r1, [r6, PWR_CR1] 158 | .L_wait_pw_set: 159 | ldr r1, [r6, PWR_SR2] 160 | lsrs r1, 11 /* VOSF -> CF */ 161 | bcs .L_wait_pw_set 162 | /* Adjusting flash latency */ 163 | ldr r0, = FLASH_R_BASE 164 | movs r1, 2 165 | str r1, [r0, FLASH_ACR] 166 | /* Set 48Mhz MSI clock */ 167 | movs r1, 0xB9 168 | strb r1, [r5, RCC_CR] 169 | cbz r4, .L_start_boot 170 | 171 | #if (DFU_BOOTSTRAP_GPIO != _DISABLE) 172 | /* checking bootstrap pin */ 173 | ldr r1, = DFU_BOOTSTRAP_GPIO 174 | movs r2, BOOTSTRAP_RCC 175 | strb r2, [r5, RCC_AHB2ENR] 176 | movs r2, 0x03 177 | lsls r2, (DFU_BOOTSTRAP_PIN * 2) 178 | ldr r3, [r1, GPIO_MODER] 179 | bics r3, r2 180 | str r3, [r1, GPIO_MODER] 181 | ldr r3, [r1, GPIO_PUPDR] 182 | bics r3, r2 183 | #if (DFU_BOOTSTRAP_PULL == _DISABLE) 184 | movs r2, 0x00 185 | #elif ((DFU_BOOTSTRAP_PULL == _LOW) || ((DFU_BOOTSTRAP_PULL == _AUTO) && (DFU_BOOTSTRAP_LEVEL == _HIGH))) 186 | movs r2, 0x02 //pulldown 187 | #else 188 | movs r2, 0x01 //pullup 189 | #endif 190 | lsls r2, (DFU_BOOTSTRAP_PIN * 2) 191 | orrs r3, r2 192 | str r3, [r1, GPIO_PUPDR] 193 | movs r4, 0x08 194 | .L_scan_bootstrap: 195 | ldr r2, [r1, GPIO_IDR] 196 | lsrs r2, (DFU_BOOTSTRAP_PIN + 1) //Pin -> CF 197 | sbcs r3, r3 198 | movs r2, 0x01 199 | orrs r2, r3 200 | #if (DFU_BOOTSTRAP_LEVEL == _HIGH) 201 | subs r4, r2 202 | #else 203 | adds r4, r2 204 | #endif 205 | beq .L_reset_gpio 206 | cmp r4, 0x10 207 | bne .L_scan_bootstrap 208 | .L_reset_gpio: 209 | movs r2, BOOTSTRAP_RCC 210 | strb r2, [r5, RCC_AHB2RSTR] 211 | movs r2, 0x00 212 | strb r2, [r5, RCC_AHB2RSTR] 213 | strb r2, [r5, RCC_AHB2ENR] 214 | cbz r4, .L_start_boot 215 | #endif 216 | 217 | #if (DFU_VERIFY_CHECKSUM != _DISABLE) 218 | ldr r0, = _APP_START 219 | ldr r1, = __romend 220 | sub r1, r0 221 | bl validate_checksum 222 | cbz r0, .L_start_boot 223 | #endif 224 | /* Force reset with APP */ 225 | ldr r1, = _KEY_ADDR 226 | ldr r2, = DFU_BOOTKEY 227 | mvn r2, r2 228 | str r2, [r1] 229 | System_Reset: 230 | dsb 231 | ldr r1, = SCB 232 | ldr r2, = 0x05FA0004; 233 | str r2, [r1, SCB_AIRCR] 234 | b . 235 | 236 | /* starting bootloader */ 237 | .L_start_boot: 238 | ldr r1, = __etext 239 | ldr r2, = __data_start__ 240 | ldr r3, = __data_end__ 241 | subs r3, r2 242 | ble .L_clear_bss 243 | .L_copy_data: 244 | subs r3, 0x04 245 | ldr r0, [r1, r3] 246 | str r0, [r2, r3] 247 | bgt .L_copy_data 248 | .L_clear_bss: 249 | ldr r1, = __bss_start__ 250 | ldr r2, = __bss_end__ 251 | movs r3, 0 252 | .L_bss_loop: 253 | str r3, [r1] 254 | adds r1, 0x04 255 | cmp r1, r2 256 | bcc .L_bss_loop 257 | 258 | #if defined(STM32L433xx) 259 | /* Disabling Vusb isolation for L433 */ 260 | mov r1, (1 << 10) /* USV */ 261 | str r1, [r6, PWR_CR2] 262 | #endif 263 | 264 | /* Set MSI clock as USB clock */ 265 | movs r1, 0x0C 266 | strb r1, [r5, RCC_CCIPR + 3] 267 | /* Enabling USB pins GPIOA11 GPIO12 AF10*/ 268 | mov r1, 0x01 269 | strb r1, [r5, RCC_AHB2ENR] 270 | ldr r0, = GPIOA 271 | ldr r1, [r0, GPIO_MODER] 272 | movs r2, 0xAA 273 | bfi r1, r2, 22, 4 274 | str r1, [r0, GPIO_MODER] 275 | lsls r2, 12 276 | str r2, [r0, GPIO_AFRH] 277 | #if (DFU_SEAL_LEVEL != 0) 278 | ldr r3, = seal_flash 279 | blx r3 280 | #endif 281 | /* jump to bootloader */ 282 | bl main 283 | 284 | .size Reset_Handler, . - Reset_Handler 285 | 286 | _default_handler: 287 | b . 288 | .size _default_handler, . - _default_handler 289 | 290 | 291 | .pool 292 | 293 | .macro def_irq_handler handler_name 294 | .weak \handler_name 295 | .thumb_set \handler_name, _default_handler 296 | .endm 297 | 298 | def_irq_handler NMI_Handler 299 | def_irq_handler HardFault_Handler 300 | def_irq_handler MemManage_Handler 301 | def_irq_handler BusFault_Handler 302 | def_irq_handler UsageFault_Handler 303 | def_irq_handler SVC_Handler 304 | def_irq_handler DebugMon_Handler 305 | def_irq_handler PendSV_Handler 306 | def_irq_handler SysTick_Handler 307 | 308 | /* using RAM for this functions */ 309 | .section .data 310 | .align 2 311 | .thumb_func 312 | .globl program_flash 313 | .type program_flash, %function 314 | /* R0 <- addrss to flash 315 | * R1 <- buffer 316 | * R2 <- block size 317 | * R0 -> DFU_STATUS 318 | */ 319 | program_flash: 320 | push {r4, r5, r6, lr} 321 | /* checking doubleword alignment */ 322 | movs r4, 0x07 323 | tst r4, r0 324 | bne Err_unaligned 325 | /* unlocking flash */ 326 | ldr r3, = FLASH_R_BASE 327 | .L_flash_unlock: 328 | ldr r4, [r3, FLASH_SR] 329 | lsls r4, 16 /* BSY->CF */ 330 | bcs .L_flash_unlock 331 | ldr r4, = FLASH_PRGKEY0 332 | ldr r5, = FLASH_PRGKEY1 333 | str r4, [r3, FLASH_KEYR] 334 | str r5, [r3, FLASH_KEYR] 335 | movs r6, 0 336 | .L_flash_loop: 337 | /* checking end of block */ 338 | cmp r6, r2 339 | bhs .L_do_verify 340 | /* clean FLASH_SR */ 341 | ldr r4, [r3, FLASH_SR] 342 | str r4, [r3, FLASH_SR] 343 | /* check for the page start (2k page)*/ 344 | mov r4, r6 345 | adds r4, r0 346 | lsls r5, r4, 21 347 | bne .L_do_write 348 | /* erasing page */ 349 | /* calculating PNB[7:0] and BKER */ 350 | lsls r4, 12 351 | lsrs r4, 23 352 | lsls r4, 3 353 | /* set PER */ 354 | adds r4, 0x02 355 | str r4, [r3, FLASH_CR] 356 | movs r4, 0x01 357 | strh r4, [r3, FLASH_CR + 0x02] /* set STRT */ 358 | bl wait_flash_ready 359 | bne Err_erase 360 | /* perform doubleword write */ 361 | .L_do_write: 362 | movs r4, 0x01 /* set PG */ 363 | str r4, [r3, FLASH_CR] 364 | ldr r4, [r1, r6] 365 | str r4, [r0, r6] 366 | adds r6, 0x04 367 | ldr r4, [r1, r6] 368 | str r4, [r0, r6] 369 | adds r6, 0x04 370 | bl wait_flash_ready 371 | bne Err_prog 372 | b .L_flash_loop /* if no errors */ 373 | .L_do_verify: 374 | /* disabling programming */ 375 | movs r4, 0x00 376 | str r4, [r3, FLASH_CR] 377 | .L_verify_loop: 378 | subs r2, 1 379 | bcc Err_done 380 | ldrb r4, [r0, r2] 381 | ldrb r5, [r1, r2] 382 | cmp r4, r5 383 | bne Err_verify 384 | b .L_verify_loop 385 | /* all done */ 386 | Err_done: 387 | movs r0, 0x00 //OK 388 | b .L_exit 389 | Err_unaligned: 390 | movs r0, 0x03 // errWRITE (unaligned access) 391 | b .L_exit 392 | Err_erase: 393 | movs r0, 0x04 //errERASE 394 | b .L_exit 395 | Err_prog: 396 | movs r0, 0x06 //errPROG 397 | b .L_exit 398 | Err_verify: 399 | movs r0, 0x07 //errVERIFY 400 | .L_exit: 401 | movs r4, 0x03 402 | lsls r4, 30 403 | str r4, [r3, FLASH_CR] // locking flash 404 | pop {r4, r5, r6, pc} 405 | .size program_flash, . - program_flash 406 | 407 | 408 | .thumb_func 409 | .type wait_flash_ready, %function 410 | wait_flash_ready: 411 | ldr r4, [r3, FLASH_SR] 412 | lsls r4, 16 //BSY->CF 413 | bcs wait_flash_ready 414 | lsrs r4, 17 //EOP->CF 415 | bx lr 416 | .size wait_flash_ready, . - wait_flash_ready 417 | 418 | #if (DFU_SEAL_LEVEL != 0) 419 | .thumb_func 420 | .globl seal_flash 421 | .type seal_flash, %function 422 | seal_flash: 423 | push {r4, r5, r6, lr} 424 | ldr r3, = FLASH_R_BASE 425 | ldrb r1, [r3, FLASH_OPTR] 426 | #if (DFU_SEAL_LEVEL == 2) 427 | #warning Protection Level 2 is an irreversible !! 428 | cmp r1, 0xCC 429 | beq Err_done 430 | movs r0, 0xCC 431 | #else 432 | cmp r1, 0xAA 433 | bne Err_done 434 | movs r0, 0x18 435 | #endif 436 | ldr r4, = FLASH_PRGKEY0 437 | ldr r5, = FLASH_PRGKEY1 438 | str r4, [r3, FLASH_KEYR] 439 | str r5, [r3, FLASH_KEYR] 440 | ldr r4, = FLASH_OPTKEY0 441 | ldr r5, = FLASH_OPTKEY1 442 | str r4, [r3, FLASH_OPTKEYR] 443 | str r5, [r3, FLASH_OPTKEYR] 444 | /* clean FLASH_SR */ 445 | ldr r4, [r3, FLASH_SR] 446 | str r4, [r3, FLASH_SR] 447 | /* modify OPTR */ 448 | strb r0, [r3, FLASH_OPTR] 449 | /* set OPT_STRT */ 450 | movs r4, 0x02 451 | strb r4, [r3, FLASH_CR + 0x02] 452 | bl wait_flash_ready 453 | bne Err_prog 454 | b Err_done 455 | .size seal_flash, . - seal_flash 456 | #endif 457 | 458 | .pool 459 | .end 460 | --------------------------------------------------------------------------------