├── .gitmodules ├── contrib ├── astyle_2.05.1_linux.tar.gz └── git │ └── pre-commit ├── src ├── version.h ├── version.h.in ├── ripemd160.h ├── hmac.h ├── CMakeLists.txt ├── led.h ├── systick.h ├── random.h ├── sd.h ├── base58.h ├── base64.h ├── sham.h ├── systick.c ├── pbkdf2.h ├── utils.h ├── bip32.h ├── hmac.c ├── touch.h ├── led.c ├── ataes132.h ├── commander.h ├── wallet.h ├── sha2.h ├── sham.c ├── random.c ├── pbkdf2.c ├── memory.h ├── uECC.h ├── bip32.c ├── aes.h ├── touch.c ├── base64.c ├── flags.h ├── base58.c ├── utils.c ├── ataes132.c ├── sd.c ├── ripemd160.c ├── wallet.c └── memory.c ├── .gitignore ├── .travis.yml ├── LICENSE ├── tests ├── CMakeLists.txt ├── tests_cmdline.c ├── utest.h └── tests_openssl.c ├── README.md └── CMakeLists.txt /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/yajl"] 2 | path = src/yajl 3 | url = https://github.com/digitalbitbox/yajl.git 4 | -------------------------------------------------------------------------------- /contrib/astyle_2.05.1_linux.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasschnelli/mcu/master/contrib/astyle_2.05.1_linux.tar.gz -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #ifndef VERSION_H 2 | #define VERSION_H 3 | 4 | const char *DIGITAL_BITBOX_VERSION = "v1.0.2-13-g3d1fc49"; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/version.h.in: -------------------------------------------------------------------------------- 1 | #ifndef VERSION_H 2 | #define VERSION_H 3 | 4 | const char *DIGITAL_BITBOX_VERSION = "@VERSION_STRING@"; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | tests* 3 | !/tests 4 | !tests_mcu.h 5 | !*.c 6 | tests.c 7 | backup 8 | *.bak 9 | .DS_Store 10 | .ycm* 11 | *.o 12 | *.swp 13 | *.swo 14 | -------------------------------------------------------------------------------- /src/ripemd160.h: -------------------------------------------------------------------------------- 1 | #ifndef __RIPEMD160_H__ 2 | #define __RIPEMD160_H__ 3 | 4 | #include 5 | 6 | void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t *hash); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/hmac.h: -------------------------------------------------------------------------------- 1 | #ifndef __HMAC_H__ 2 | #define __HMAC_H__ 3 | 4 | #include 5 | 6 | void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, 7 | const uint32_t msglen, uint8_t *hmac); 8 | void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, 9 | const uint32_t msglen, uint8_t *hmac); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(C-SOURCES 2 | aes.c 3 | base58.c 4 | base64.c 5 | bip32.c 6 | commander.c 7 | hmac.c 8 | led.c 9 | memory.c 10 | pbkdf2.c 11 | random.c 12 | ripemd160.c 13 | sha2.c 14 | sham.c 15 | uECC.c 16 | utils.c 17 | wallet.c 18 | ) 19 | 20 | set(C-HW-SOURCES 21 | ataes132.c 22 | sd.c 23 | systick.c 24 | touch.c 25 | ) 26 | 27 | 28 | set(YAJL-SOURCES 29 | yajl/src/yajl.c 30 | yajl/src/yajl_lex.c 31 | yajl/src/yajl_parser.c 32 | yajl/src/yajl_buf.c 33 | yajl/src/yajl_encode.c 34 | yajl/src/yajl_gen.c 35 | yajl/src/yajl_alloc.c 36 | yajl/src/yajl_tree.c 37 | yajl/src/yajl_version.c 38 | ) 39 | 40 | include_directories(SYSTEM) 41 | 42 | add_library(bitbox 43 | SHARED 44 | ${C-SOURCES} 45 | #${C-HW-SOURCES} 46 | ${YAJL-SOURCES} 47 | ) 48 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | sudo: false 3 | os: 4 | - osx 5 | - linux 6 | 7 | compiler: 8 | - clang 9 | - gcc 10 | 11 | matrix: 12 | exclude: 13 | - os: osx 14 | compiler: gcc 15 | fast_finish: 16 | - true 17 | 18 | before_install: 19 | - tar xfv contrib/astyle_2.05.1_linux.tar.gz 20 | - cd astyle/build/gcc && make 21 | - export PATH=$PATH:$PWD/bin/ 22 | 23 | before_script: 24 | - cd $TRAVIS_BUILD_DIR 25 | - if astyle --style=stroustrup --indent-switches --indent-labels --pad-oper --pad-header --align-pointer=name --add-brackets --convert-tabs --max-code-length=90 --break-after-logical --suffix=none *.c *.h --recursive --exclude=astyle --exclude=src/yajl --dry-run -Q | grep "Formatted" ; then exit 1 ; fi 26 | 27 | script: 28 | - mkdir build && cd build 29 | - cmake .. -DCONTINUOUS_INTEGRATION=1 && make 30 | - make test 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Douglas J. Bakkum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | */ 24 | 25 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(../src) 2 | 3 | #----------------------------------------------------------------------------- 4 | # Build tests_unit 5 | add_executable(tests_unit tests_unit.c) 6 | target_link_libraries(tests_unit bitbox) 7 | 8 | 9 | #----------------------------------------------------------------------------- 10 | # Build tests_openssl 11 | include_directories(${OPENSSL_INCLUDE_DIR}) 12 | add_executable(tests_openssl tests_openssl.c) 13 | target_link_libraries(tests_openssl bitbox ${OPENSSL_LIBRARIES}) 14 | 15 | 16 | #----------------------------------------------------------------------------- 17 | # Build tests_cmdline 18 | add_executable(tests_cmdline tests_cmdline.c) 19 | target_link_libraries(tests_cmdline bitbox) 20 | 21 | 22 | #----------------------------------------------------------------------------- 23 | # Build tests_api 24 | if(NOT CONTINUOUS_INTEGRATION) 25 | include_directories(${HIDAPI_INCLUDE_DIR}) 26 | endif() 27 | 28 | add_executable(tests_api tests_api.c) 29 | 30 | if(NOT CONTINUOUS_INTEGRATION) 31 | target_link_libraries(tests_api bitbox ${HIDAPI_LIBRARY}) 32 | else() 33 | target_link_libraries(tests_api bitbox) 34 | endif() 35 | -------------------------------------------------------------------------------- /src/led.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | 29 | #ifndef _LED_H_ 30 | #define _LED_H_ 31 | 32 | void led_off(void); 33 | void led_on(void); 34 | void led_toggle(void); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/systick.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #ifndef _SYSTICK_H_ 29 | #define _SYSTICK_H_ 30 | 31 | 32 | void systick_update_time(void); 33 | void systick_init(void); 34 | 35 | 36 | #endif -------------------------------------------------------------------------------- /contrib/git/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | hasFormattingIssues=0 4 | 5 | if ! command -v astyle >/dev/null ; then 6 | echo -n "error: please install astyle in order to be able" 7 | echo " to use this pre-commit git-hook" 8 | exit 1 9 | fi 10 | 11 | if git rev-parse --verify HEAD >/dev/null 2>&1; then 12 | against=HEAD 13 | else 14 | # Initial commit: diff against an empty tree object 15 | against=2caab4551b305ab1e9e4b05145a4da5f51331e0d 16 | fi 17 | 18 | # Redirect output to stderr. 19 | exec 1>&2 20 | 21 | files=$(git diff --cached --name-only --diff-filter=AM $against | \ 22 | grep -E '^(src|tests)' | grep -E '(c|h)$') 23 | 24 | for file in $files; do 25 | astyle --style=stroustrup --indent-switches --indent-labels --pad-oper --pad-header --align-pointer=name --add-brackets --convert-tabs --max-code-length=90 --break-after-logical -Q $file 26 | if [ -e "$file.orig" ]; then 27 | mv $file "$file.formated" 28 | mv "$file.orig" $file 29 | git diff --no-index "$file" "$file.formated" | cat 30 | 31 | isDiff=$(diff --brief "$file.formated" $file) 32 | if [ "$isDiff" != "" ] ; then 33 | hasFormattingIssues=1 34 | fi 35 | rm "$file.formated" 36 | fi 37 | done 38 | 39 | 40 | if [ $hasFormattingIssues -eq 1 ] ; then 41 | echo Found code style formatting issues. 42 | exit 1 43 | fi 44 | -------------------------------------------------------------------------------- /src/random.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #ifndef _RANDOM_H_ 29 | #define _RANDOM_H_ 30 | 31 | #include 32 | #include 33 | 34 | void random_init(void); 35 | int random_bytes(uint8_t *buf, uint32_t len, uint8_t update_seed); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/sd.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #ifndef _SD_H_ 29 | #define _SD_H_ 30 | 31 | uint8_t sd_list(void); 32 | uint8_t sd_erase(void); 33 | char *sd_load(const char *f, uint16_t f_len); 34 | uint8_t sd_write(const char *f, uint16_t f_len, const char *text, uint16_t t_len, 35 | uint8_t replace); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/base58.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef __BASE58_H__ 25 | #define __BASE58_H__ 26 | 27 | #include 28 | 29 | int base58_encode_check(const uint8_t *data, int len, char *str, int strsize); 30 | int base58_decode_check(const char *str, uint8_t *data, int datalen); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 2014 Douglas J Bakkum 3 | * Split into .h and .c files. 4 | */ 5 | 6 | /* 7 | 8 | https://github.com/superwills/NibbleAndAHalf 9 | base64.h -- Fast base64 encoding and decoding. 10 | version 1.0.0, April 17, 2013 143a 11 | 12 | Copyright (C) 2013 William Sherif 13 | 14 | This software is provided 'as-is', without any express or implied 15 | warranty. In no event will the authors be held liable for any damages 16 | arising from the use of this software. 17 | 18 | Permission is granted to anyone to use this software for any purpose, 19 | including commercial applications, and to alter it and redistribute it 20 | freely, subject to the following restrictions: 21 | 22 | 1. The origin of this software must not be misrepresented; you must not 23 | claim that you wrote the original software. If you use this software 24 | in a product, an acknowledgment in the product documentation would be 25 | appreciated but is not required. 26 | 2. Altered source versions must be plainly marked as such, and must not be 27 | misrepresented as being the original software. 28 | 3. This notice may not be removed or altered from any source distribution. 29 | 30 | William Sherif 31 | will.sherif@gmail.com 32 | 33 | YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz 34 | 35 | */ 36 | #ifndef _BASE64_H_ 37 | #define _BASE64_H_ 38 | 39 | 40 | // Converts binary data of length=len to base64 characters. 41 | // Length of the resultant string is stored in flen 42 | // (you must pass pointer flen). 43 | char *base64( const void *binaryData, int len, int *flen ); 44 | unsigned char *unbase64( const char *ascii, int len, int *flen ); 45 | 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/sham.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #ifndef _SHAM_H_ 29 | #define _SHAM_H_ 30 | 31 | 32 | #include 33 | 34 | 35 | void delay_ms(int delay); 36 | uint8_t sd_write(const char *f, uint16_t f_len, const char *t, uint16_t t_len, 37 | uint8_t replace); 38 | char *sd_load(const char *f, uint16_t f_len); 39 | uint8_t sd_list(void); 40 | uint8_t sd_erase(void); 41 | void touch_button_parameters(uint16_t timeout, uint16_t threshold); 42 | uint8_t touch_button_press(int long_touch); 43 | uint8_t flash_read_unique_id(uint32_t *serial, uint32_t len); 44 | 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/systick.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | #include "systick.h" 31 | #include "mcu.h" 32 | 33 | volatile uint16_t systick_current_time_ms = 0u; 34 | volatile uint8_t systick_time_updated = 0u; 35 | uint16_t systick_measurement_period_msec = 25u; 36 | 37 | 38 | void systick_update_time(void) 39 | { 40 | systick_time_updated = 1u; 41 | systick_current_time_ms += systick_measurement_period_msec; 42 | } 43 | 44 | 45 | // Configure timer ISR to fire regularly 46 | void systick_init(void) 47 | { 48 | SysTick_Config((sysclk_get_cpu_hz() / 1000) * systick_measurement_period_msec); 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/pbkdf2.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef __PBKDF2_H__ 25 | #define __PBKDF2_H__ 26 | 27 | #include 28 | 29 | // salt needs to have 4 extra bytes available beyond saltlen 30 | void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, 31 | uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, 32 | uint32_t total)); 33 | // salt needs to have 4 extra bytes available beyond saltlen 34 | void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, 35 | uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, 36 | uint32_t total)); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #ifndef _UTILS_H_ 29 | #define _UTILS_H_ 30 | 31 | 32 | #include 33 | #include 34 | #include "memory.h" 35 | 36 | #define TO_UINT8_HEX_BUF_LEN 2048 37 | #define VARINT_LEN 20 38 | 39 | #define strlens(s) (s == NULL ? 0 : strlen(s)) 40 | 41 | void utils_clear_buffers(void); 42 | uint8_t *utils_hex_to_uint8(const char *str); 43 | char *utils_uint8_to_hex(const uint8_t *bin, size_t l); 44 | 45 | void utils_reverse_hex(char *h, int len); 46 | void utils_uint64_to_varint(char *vi, int *l, uint64_t i); 47 | int utils_varint_to_uint64(const char *vi, uint64_t *i); 48 | 49 | char *utils_read_decrypted_report(void); 50 | void utils_decrypt_report(const char *report); 51 | void utils_send_cmd(const char *instruction, PASSWORD_ID enc_id); 52 | #ifdef TESTING 53 | void utils_send_print_cmd(const char *command, PASSWORD_ID enc_id); 54 | #endif 55 | 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/bip32.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * Copyright (c) 2015 Douglas J. Bakkumk 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining 7 | * a copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, including without limitation 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the 11 | * Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included 14 | * in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 20 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | * OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | 26 | #ifndef _BIP32_H_ 27 | #define _BIP32_H_ 28 | 29 | 30 | #include 31 | 32 | 33 | typedef struct { 34 | uint32_t depth; 35 | uint32_t fingerprint; 36 | uint32_t child_num; 37 | uint8_t chain_code[32]; 38 | uint8_t private_key[32]; 39 | uint8_t public_key[33]; 40 | } HDNode; 41 | 42 | 43 | #define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000)) 44 | 45 | 46 | int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out); 47 | int hdnode_private_ckd(HDNode *inout, uint32_t i); 48 | void hdnode_fill_public_key(HDNode *node); 49 | void hdnode_serialize_public(const HDNode *node, char *str, int strsize); 50 | void hdnode_serialize_private(const HDNode *node, char *str, int strsize); 51 | int hdnode_deserialize(const char *str, HDNode *node); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/hmac.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hmac.h" 3 | #include "sha2.h" 4 | 5 | void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, 6 | const uint32_t msglen, uint8_t *hmac) 7 | { 8 | int i; 9 | uint8_t buf[SHA256_BLOCK_LENGTH], o_key_pad[SHA256_BLOCK_LENGTH], 10 | i_key_pad[SHA256_BLOCK_LENGTH]; 11 | SHA256_CTX ctx; 12 | 13 | memset(buf, 0, SHA256_BLOCK_LENGTH); 14 | if (keylen > SHA256_BLOCK_LENGTH) { 15 | sha256_Raw(key, keylen, buf); 16 | } else { 17 | memcpy(buf, key, keylen); 18 | } 19 | 20 | for (i = 0; i < SHA256_BLOCK_LENGTH; i++) { 21 | o_key_pad[i] = buf[i] ^ 0x5c; 22 | i_key_pad[i] = buf[i] ^ 0x36; 23 | } 24 | 25 | sha256_Init(&ctx); 26 | sha256_Update(&ctx, i_key_pad, SHA256_BLOCK_LENGTH); 27 | sha256_Update(&ctx, msg, msglen); 28 | sha256_Final(buf, &ctx); 29 | 30 | sha256_Init(&ctx); 31 | sha256_Update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH); 32 | sha256_Update(&ctx, buf, SHA256_DIGEST_LENGTH); 33 | sha256_Final(hmac, &ctx); 34 | } 35 | 36 | void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, 37 | const uint32_t msglen, uint8_t *hmac) 38 | { 39 | int i; 40 | uint8_t buf[SHA512_BLOCK_LENGTH], o_key_pad[SHA512_BLOCK_LENGTH], 41 | i_key_pad[SHA512_BLOCK_LENGTH]; 42 | SHA512_CTX ctx; 43 | 44 | memset(buf, 0, SHA512_BLOCK_LENGTH); 45 | if (keylen > SHA512_BLOCK_LENGTH) { 46 | sha512_Raw(key, keylen, buf); 47 | } else { 48 | memcpy(buf, key, keylen); 49 | } 50 | 51 | for (i = 0; i < SHA512_BLOCK_LENGTH; i++) { 52 | o_key_pad[i] = buf[i] ^ 0x5c; 53 | i_key_pad[i] = buf[i] ^ 0x36; 54 | } 55 | 56 | sha512_Init(&ctx); 57 | sha512_Update(&ctx, i_key_pad, SHA512_BLOCK_LENGTH); 58 | sha512_Update(&ctx, msg, msglen); 59 | sha512_Final(buf, &ctx); 60 | 61 | sha512_Init(&ctx); 62 | sha512_Update(&ctx, o_key_pad, SHA512_BLOCK_LENGTH); 63 | sha512_Update(&ctx, buf, SHA512_DIGEST_LENGTH); 64 | sha512_Final(hmac, &ctx); 65 | } 66 | -------------------------------------------------------------------------------- /src/touch.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #ifndef _TOUCH_H_ 29 | #define _TOUCH_H_ 30 | 31 | #include 32 | 33 | #ifndef TESTING 34 | #define TOUCH_CHANNEL CHANNEL_9 35 | #define QTOUCH_LIB_TYPE_MASK 0x01 36 | #define QTOUCH_LIB_COMPILER_OFFSET 2 37 | #define QTOUCH_LIB_COMPILER_MASK 0x01 38 | #define QTOUCH_LIB_MAX_CHANNEL_OFFSET 3 39 | #define QTOUCH_LIB_MAX_CHANNEL_MASK 0x7F 40 | #define QTOUCH_LIB_KEY_ONLY_OFFSET 10 41 | #define QTOUCH_LIB_KEY_ONLY_MASK 0x01 42 | #define QTOUCH_LIB_ROTOR_NUM_OFFSET 11 43 | #define QTOUCH_LIB_ROTOR_NUM_MASK 0x1F 44 | #define GET_SENSOR_STATE(SENSOR_NUMBER) (qt_measure_data.qt_touch_status.sensor_states[(SENSOR_NUMBER/8)] & (1 << (SENSOR_NUMBER % 8))) 45 | #endif 46 | 47 | 48 | void touch_button_parameters(uint16_t timeout, uint16_t threshold); 49 | void touch_init(void); 50 | uint8_t touch_button_press(int long_touch); 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/led.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | 29 | #include 30 | 31 | #include "led.h" 32 | #include "memory.h" 33 | #include "commander.h" 34 | #ifndef TESTING 35 | #include 36 | #include 37 | #include 38 | #else 39 | #include "sham.h" 40 | 41 | #define LED_0_PIN 0 42 | #define IOPORT_PIN_LEVEL_LOW 1 43 | #define IOPORT_PIN_LEVEL_HIGH 0 44 | 45 | void ioport_set_pin_level(int led, int level); 46 | int ioport_get_pin_level(int led); 47 | 48 | 49 | void ioport_set_pin_level(int led, int level) 50 | { 51 | (void)led; 52 | (void)level; 53 | } 54 | int ioport_get_pin_level(int led) 55 | { 56 | (void)led; 57 | return 0; 58 | } 59 | 60 | #endif 61 | 62 | 63 | void led_off(void) 64 | { 65 | ioport_set_pin_level(LED_0_PIN, IOPORT_PIN_LEVEL_HIGH); 66 | } 67 | 68 | void led_on(void) 69 | { 70 | ioport_set_pin_level(LED_0_PIN, IOPORT_PIN_LEVEL_LOW); 71 | } 72 | 73 | void led_toggle(void) 74 | { 75 | ioport_set_pin_level(LED_0_PIN, !ioport_get_pin_level(LED_0_PIN)); 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/ataes132.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #ifndef _AES132_H_ 29 | #define _AES132_H_ 30 | 31 | #include 32 | 33 | #define AES_DEVICE_ADDR 0x50u 34 | #define AES_MEM_ADDR_LEN 2 35 | #define AES_MEM_ADDR_IO 0xFE00 36 | #define AES_MEM_ADDR_STATUS 0xFFF0 37 | #define AES_MEM_ADDR_RESET 0xFFE0 38 | #define AES_TWI TWI0 39 | #define AES_TWI_ID ID_TWI0 40 | #define AES_TWI_SPEED 10000 41 | 42 | void aes_init(void); 43 | uint8_t aes_eeprom_write(uint32_t u32_start_address, uint16_t u16_length, 44 | uint8_t const *p_wr_buffer); 45 | uint32_t aes_eeprom_read(uint32_t u32_start_address, uint16_t u16_length, 46 | uint8_t *p_rd_buffer); 47 | void aes_calculate_crc(uint8_t length, const uint8_t *data, uint8_t *crc); 48 | void aes_process(uint8_t const *command, uint16_t cmd_len, uint8_t *response_block, 49 | uint16_t response_len); 50 | void aes_eeprom(uint16_t LEN, uint32_t ADDR, uint8_t *userdata_read, 51 | const uint8_t *userdata_write); 52 | 53 | 54 | #endif -------------------------------------------------------------------------------- /tests/tests_cmdline.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | 29 | #include 30 | #include 31 | 32 | #include "utils.h" 33 | #include "random.h" 34 | #include "memory.h" 35 | #include "commander.h" 36 | 37 | 38 | void usage(char *argv[]); 39 | 40 | 41 | void usage(char *argv[]) 42 | { 43 | printf("\nExample code to run the Digital Bitbox MCU code.\n"); 44 | printf(" Usage:\n\t%s json_commands\n\n", argv[0]); 45 | printf(" Example:\n\t./tests_cmdline \"{ \\\"seed\\\":{\\\"source\\\":\\\"create\\\"} }\"\n\n" ); 46 | printf( "See the online API documentation for a list of JSON commands at\ndigitalbitbox.com.\n\n\n"); 47 | } 48 | 49 | 50 | int main ( int argc, char *argv[] ) 51 | { 52 | if (argc != 2) { 53 | usage(argv); 54 | } else { 55 | random_init(); 56 | memory_setup(); 57 | // A password is required before sending commands. 58 | // Refer to the API documentation for more details. 59 | utils_send_print_cmd("{\"password\":\"standard_password\"}", PASSWORD_NONE); 60 | utils_send_print_cmd(argv[1], PASSWORD_STAND); 61 | } 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/commander.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #ifndef _COMMANDER_H_ 29 | #define _COMMANDER_H_ 30 | 31 | 32 | #include 33 | #include "memory.h" 34 | #ifndef TESTING 35 | #include "conf_usb.h" 36 | 37 | 38 | #define COMMANDER_REPORT_SIZE UDI_HID_REPORT_OUT_SIZE 39 | #else 40 | #define COMMANDER_REPORT_SIZE 2048 41 | #endif 42 | #define VERIFYPASS_FILENAME "verification.txt" 43 | #define COMMANDER_MAX_ATTEMPTS 5// max attempts before device reset 44 | 45 | #define AUTOBACKUP_FILENAME "autobackup_" 46 | #define AUTOBACKUP_ENCRYPT "yes" 47 | #define AUTOBACKUP_NUM 10 48 | 49 | char *aes_cbc_b64_encrypt(const unsigned char *in, int inlen, int *out_b64len, 50 | PASSWORD_ID id); 51 | char *aes_cbc_b64_decrypt(const unsigned char *in, int inlen, int *decrypt_len, 52 | PASSWORD_ID id); 53 | 54 | void commander_clear_report(void); 55 | void commander_fill_report(const char *attr, const char *val, int err); 56 | int commander_fill_signature(const uint8_t *sig, const uint8_t *pubkey); 57 | void commander_force_reset(void); 58 | void commander_create_verifypass(void); 59 | int commander_test_static_functions(void); 60 | char *commander(const char *command); 61 | 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/digitalbitbox/mcu.svg?branch=master)](https://travis-ci.org/digitalbitbox/mcu) 2 | [![License](http://img.shields.io/:License-MIT-yellow.svg)](LICENSE) 3 | 4 | 5 | **MCU code for the [Digital Bitbox](https://digitalbitbox.com) hardware wallet.** 6 | 7 | All communication to the hardware wallet enters and exits a single gateway `char *commander(const char *command)` that receives an encrypted command and returns an encrypted reply. The communication protocol is desribed in the [API](https://digitalbitbox.com/api.html). 8 | 9 | See the `tests_cmdline.c` code for a simple example and the `tests_api.c` code to test the API. The tests can be compiled and run locally without the need for a device. The `tests_api.c` code will also test a live device if one is plugged into a USB slot. This requires installation of the [hidapi library](http://www.signal11.us/oss/hidapi/) for USB communication, a micro SD card in the device, and a number of touch button presses (to permit `erase` and `sign` commands). 10 | 11 | ECDSA signatures are performed using a simplified version of the [micro ECC library](https://github.com/kmackay/micro-ecc). The micro ECC library is designed for microcontrollers, resistant to known side channel attacks, and does not use dynamic memory allocation. In the simplified version, non-secp256k1 ECDSA curves were removed and RFC6979 (deterministic k) and convenience functions were added. 12 | 13 | **Standardized functions:** 14 | 15 | Cryptographic: secp256k1, AES-256-CBC, SHA2, HMAC, PBKDF2, RIPEMD160 16 | Encoding: Base-64, Base-58-check, JSON 17 | Bitcoin: BIP32, BIP39, BIP44 18 | 19 | 20 | 21 | ## Build Instructions 22 | Dependencies: 23 | 24 | - https://github.com/signal11/hidapi 25 | 26 | OSX: 27 | 28 | brew install hidapi 29 | 30 | -------------- 31 | 32 | Basic build steps: 33 | 34 | mkdir build 35 | cd build 36 | cmake .. 37 | make 38 | 39 | 40 | 41 | ## Contributing 42 | Please do *NOT* use an editor that automatically reformats. 43 | 44 | Use the coding style set by astyle (http://astyle.sourceforge.net/) with the following parameteres: 45 | > astyle --style=stroustrup --indent-switches --indent-labels --pad-oper --pad-header --align-pointer=name --add-brackets --convert-tabs --max-code-length=90 --break-after-logical --suffix=none *.c *.h --recursive 46 | 47 | 48 | #### astyle Git hook 49 | 50 | For convenience, enable a Git hook to trigger the `astyle` styling whenever a `git commit` operation is performed. This is done by typing in the repository directory: 51 | 52 | cd .git/hooks 53 | ln -s ../../contrib/git/pre-commit 54 | 55 | -------------------------------------------------------------------------------- /src/wallet.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | 29 | #ifndef _WALLET_H_ 30 | #define _WALLET_H_ 31 | 32 | 33 | #include 34 | #include "bip32.h" 35 | 36 | 37 | #define BIP39_PBKDF2_ROUNDS 2048 38 | #define MAX_SEED_WORDS 25// 24 mnemonic words + 1 for NULL ending 39 | #define SALT_LEN_MAX 256// 24 mnemonic words + 1 for NULL ending 40 | 41 | 42 | /* BIP32 */ 43 | int wallet_split_seed(char **seed_words, const char *message); 44 | const char **wallet_mnemonic_wordlist(void); 45 | uint16_t *wallet_index_from_mnemonic(const char *mnemo); 46 | char *wallet_mnemonic_from_index(const uint16_t *index); 47 | int wallet_master_from_mnemonic(char *mnemo, int m_len, const char *salt, int s_len); 48 | int wallet_check_pubkey(const char *pubkeyhash, const char *keypath, int keypath_len); 49 | int wallet_sign(const char *message, int msg_len, const char *keypath, int keypath_len); 50 | void wallet_report_xpub(const char *keypath, int keypath_len, char *xpub); 51 | int wallet_generate_key(HDNode *node, const char *keypath, int keypath_len, 52 | const uint8_t *privkeymaster, const uint8_t *chaincode); 53 | char *wallet_mnemonic_from_data(const uint8_t *data, int len); 54 | int wallet_mnemonic_check(const char *mnemo); 55 | void wallet_mnemonic_to_seed(const char *mnemo, const char *passphrase, 56 | uint8_t s[512 / 8], 57 | void (*progress_callback)(uint32_t current, uint32_t total)); 58 | /* Bitcoin formats */ 59 | void wallet_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash); 60 | void wallet_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw); 61 | void wallet_get_address(const uint8_t *pub_key, uint8_t version, char *addr, 62 | int addrsize); 63 | void wallet_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize); 64 | 65 | 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/sha2.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2000-2001 Aaron D. Gifford 3 | * Copyright (c) 2013 Pavol Rusnak 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of the copyright holder nor the names of contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __SHA2_H__ 32 | #define __SHA2_H__ 33 | 34 | #include 35 | #include 36 | 37 | #define SHA256_BLOCK_LENGTH 64 38 | #define SHA256_DIGEST_LENGTH 32 39 | #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) 40 | #define SHA512_BLOCK_LENGTH 128 41 | #define SHA512_DIGEST_LENGTH 64 42 | #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) 43 | 44 | typedef struct _SHA256_CTX { 45 | uint32_t state[8]; 46 | uint64_t bitcount; 47 | uint8_t buffer[SHA256_BLOCK_LENGTH]; 48 | } SHA256_CTX; 49 | typedef struct _SHA512_CTX { 50 | uint64_t state[8]; 51 | uint64_t bitcount[2]; 52 | uint8_t buffer[SHA512_BLOCK_LENGTH]; 53 | } SHA512_CTX; 54 | 55 | void sha256_Init(SHA256_CTX *); 56 | void sha256_Update(SHA256_CTX *, const uint8_t *, size_t); 57 | void sha256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX *); 58 | char *sha256_End(SHA256_CTX *, char[SHA256_DIGEST_STRING_LENGTH]); 59 | void sha256_Raw(const uint8_t *, size_t, uint8_t[SHA256_DIGEST_LENGTH]); 60 | char *sha256_Data(const uint8_t *, size_t, char[SHA256_DIGEST_STRING_LENGTH]); 61 | 62 | void sha512_Init(SHA512_CTX *); 63 | void sha512_Update(SHA512_CTX *, const uint8_t *, size_t); 64 | void sha512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX *); 65 | char *sha512_End(SHA512_CTX *, char[SHA512_DIGEST_STRING_LENGTH]); 66 | void sha512_Raw(const uint8_t *, size_t, uint8_t[SHA512_DIGEST_LENGTH]); 67 | char *sha512_Data(const uint8_t *, size_t, char[SHA512_DIGEST_STRING_LENGTH]); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/sham.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "sham.h" 32 | #include "commander.h" 33 | #include "flags.h" 34 | 35 | 36 | static char sd_filename[64] = {0}; 37 | static char sd_text[512] = {0}; 38 | 39 | void delay_ms(int delay) 40 | { 41 | (void) delay; 42 | } 43 | 44 | 45 | uint8_t sd_write(const char *f, uint16_t f_len, const char *t, uint16_t t_len, 46 | uint8_t replace) 47 | { 48 | (void) replace; 49 | memset(sd_filename, 0, sizeof(sd_filename)); 50 | memset(sd_text, 0, sizeof(sd_text)); 51 | snprintf(sd_filename, sizeof(sd_filename), "%.*s", f_len, f); 52 | snprintf(sd_text, sizeof(sd_text), "%.*s", t_len, t); 53 | commander_fill_report("sd_write", FLAG_ERR_NO_MCU, STATUS_SUCCESS); 54 | return STATUS_SUCCESS; 55 | } 56 | 57 | 58 | char *sd_load(const char *f, uint16_t f_len) 59 | { 60 | static char text[512]; 61 | memcpy(text, sd_text, 512); 62 | commander_fill_report("sd_load", FLAG_ERR_NO_MCU, STATUS_SUCCESS); 63 | if (!strncmp(sd_filename, f, f_len)) { 64 | return text; 65 | } 66 | return NULL; 67 | } 68 | 69 | 70 | uint8_t sd_list(void) 71 | { 72 | commander_fill_report("sd_list", FLAG_ERR_NO_MCU, STATUS_SUCCESS); 73 | if (sd_filename[0]) { 74 | commander_fill_report("backup", sd_filename, STATUS_SUCCESS); 75 | } 76 | return STATUS_SUCCESS; 77 | } 78 | 79 | 80 | uint8_t sd_erase(void) 81 | { 82 | commander_fill_report("sd_erase", FLAG_ERR_NO_MCU, STATUS_SUCCESS); 83 | memset(sd_filename, 0, sizeof(sd_filename)); 84 | memset(sd_text, 0, sizeof(sd_text)); 85 | return STATUS_SUCCESS; 86 | } 87 | 88 | 89 | uint8_t touch_button_press(int long_touch) 90 | { 91 | (void) long_touch; 92 | commander_fill_report("touchbutton", FLAG_ERR_NO_MCU, STATUS_SUCCESS); 93 | return STATUS_TOUCHED; 94 | } 95 | 96 | 97 | void touch_button_parameters(uint16_t timeout, uint16_t threshold) 98 | { 99 | (void)timeout; 100 | (void)threshold; 101 | commander_fill_report("touchbutton", FLAG_ERR_NO_MCU, STATUS_SUCCESS); 102 | } 103 | 104 | 105 | uint8_t flash_read_unique_id(uint32_t *serial, uint32_t len) 106 | { 107 | memset(serial, 1, len); 108 | return 0; // success 109 | } 110 | -------------------------------------------------------------------------------- /src/random.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | #include "random.h" 31 | #include "flags.h" 32 | 33 | 34 | #ifdef TESTING 35 | 36 | static FILE *f; 37 | static int f_open = 0; 38 | void random_init(void) 39 | { 40 | if (!f_open) { 41 | f = fopen("/dev/urandom", "r"); 42 | f_open = 1; 43 | } 44 | } 45 | int random_bytes(uint8_t *buf, uint32_t len, uint8_t update_seed) 46 | { 47 | (void) update_seed; 48 | if (fread(buf, 1, len, f) != len) { 49 | return STATUS_ERROR; 50 | } 51 | return STATUS_SUCCESS; 52 | } 53 | 54 | #else 55 | 56 | #include "ataes132.h" 57 | #include "memory.h" 58 | 59 | void random_init(void) { }; 60 | int random_bytes(uint8_t *buf, uint32_t len, uint8_t update_seed) 61 | { 62 | const uint8_t ataes_cmd[] = {0x02, 0x02, 0x00, 0x00, 0x00, 0x00}; // pseudo RNG 63 | const uint8_t ataes_cmd_up[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; // true RNG - writes to EEPROM 64 | uint8_t ataes_ret[20] = {0}; // Random command return packet [Count(1) || Return Code (1) | Data(16) || CRC (2)] 65 | 66 | uint32_t cnt = 0; 67 | while (len > cnt) { 68 | if (update_seed) { 69 | aes_process(ataes_cmd_up, sizeof(ataes_cmd_up), ataes_ret, sizeof(ataes_ret)); 70 | update_seed = 0; 71 | } else { 72 | aes_process(ataes_cmd, sizeof(ataes_cmd), ataes_ret, sizeof(ataes_ret)); 73 | } 74 | if (ataes_ret[0]) { 75 | memcpy(buf + cnt, ataes_ret + 2, (len - cnt) < 16 ? (len - cnt) : 16); 76 | } else { 77 | return STATUS_ERROR; 78 | } 79 | cnt += 16; 80 | } 81 | 82 | // add ataes independent entropy 83 | uint8_t *entropy = memory_read_aeskey(PASSWORD_MEMORY); 84 | for (uint32_t i = 0; i < len; i++) { 85 | buf[i] = buf[i] ^ entropy[i % MEM_PAGE_LEN]; 86 | } 87 | 88 | return STATUS_SUCCESS; 89 | } 90 | 91 | #endif 92 | 93 | 94 | /* 95 | Adapted from: 96 | http://benpfaff.org/writings/clc/shuffle.html 97 | */ 98 | /* 99 | void random_shuffle(int *array, size_t n) 100 | { 101 | int r_len = 15; 102 | uint8_t r[r_len + 1]; 103 | random_bytes(r, r_len + 1, 0); 104 | if (n > 1) { 105 | size_t i; 106 | for (i = 0; i < n - 1; i++) { 107 | size_t j = i + (r[i % r_len] + (r[i % r_len + 1] << 8)) / (65536 / (n - i) + 1); 108 | int t = array[j]; 109 | array[j] = array[i]; 110 | array[i] = t; 111 | } 112 | } 113 | } 114 | */ 115 | -------------------------------------------------------------------------------- /tests/utest.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2015 Douglas J. Bakkum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | */ 24 | 25 | 26 | /* 27 | 28 | // 29 | // Macros for light weight unit testing based on 30 | // minunit.h from http://www.jera.com/techinfo/jtns/jtn002.html 31 | // 32 | // Example code: 33 | // 34 | 35 | #include "utest.h" 36 | 37 | int U_TESTS_RUN = 0; 38 | int U_TESTS_FAIL = 0; 39 | 40 | static void test_str(void) { 41 | char * str = "hello"; 42 | u_assert_str_eq(str, "hello"); 43 | u_assert_str_eq(str, "hellooo"); 44 | return; 45 | } 46 | 47 | static void test_int(void) { 48 | int i = 7; 49 | u_assert_int_eq(i, 7); 50 | u_assert_int_eq(i, 8); 51 | return; 52 | } 53 | 54 | static void test_mem(void) { 55 | char * str = "hello"; 56 | u_assert_mem_eq(str, "hello", 5); 57 | u_assert_mem_eq(str, "hellooo", 5); 58 | u_assert_mem_eq(str, "helooo", 5); 59 | return; 60 | } 61 | 62 | 63 | int main(void) 64 | { 65 | u_run_test(test_str); 66 | u_run_test(test_mem); 67 | u_run_test(test_int); 68 | if (!U_TESTS_FAIL) { 69 | printf("\nALL TESTS PASSED\n\n"); 70 | } 71 | return U_TESTS_FAIL; 72 | } 73 | */ 74 | 75 | 76 | #ifndef _UTEST_H_ 77 | #define _UTEST_H_ 78 | 79 | #include 80 | #include 81 | 82 | #define u_run_test(TEST) do {\ 83 | int f_ = U_TESTS_FAIL; \ 84 | TEST(); U_TESTS_RUN++; \ 85 | if (f_ == U_TESTS_FAIL) { \ 86 | printf("PASSED - %s()\n", #TEST); };\ 87 | } while (0) 88 | 89 | #define u_assert_int_eq(R,E) {\ 90 | int r_ = (R); \ 91 | int e_ = (E); \ 92 | do { if (r_!=e_) { \ 93 | printf("FAILED - %s:%d - %s()\n", __FILE__, __LINE__, __func__);\ 94 | printf("\tExpected:\t%d\n", e_);\ 95 | printf("\tReceived:\t%d\n", r_);\ 96 | U_TESTS_FAIL++; }; \ 97 | } while(0); } 98 | 99 | #define u_assert_str_eq(R,E) {\ 100 | const char * r_ = (R); \ 101 | const char * e_ = (E); \ 102 | do { if (strcmp(r_,e_)) { \ 103 | printf("FAILED - %s:%d - %s()\n", __FILE__, __LINE__, __func__);\ 104 | printf("\tExpected:\t%s\n", e_);\ 105 | printf("\tReceived:\t%s\n", r_);\ 106 | U_TESTS_FAIL++; }; \ 107 | } while(0); } 108 | 109 | #define u_assert_mem_eq(R,E,L) {\ 110 | const void * r_ = (R); \ 111 | const void * e_ = (E); \ 112 | size_t l_ = (L); \ 113 | do { if (memcmp(r_,e_,l_)) { \ 114 | printf("FAILED - %s:%d - %s()\n", __FILE__, __LINE__, __func__);\ 115 | printf("\tExpected:\t%s\n", utils_uint8_to_hex(e_,l_));\ 116 | printf("\tReceived:\t%s\n", utils_uint8_to_hex(r_,l_));\ 117 | U_TESTS_FAIL++; }; \ 118 | } while(0); } 119 | 120 | extern int U_TESTS_RUN; 121 | extern int U_TESTS_FAIL; 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /src/pbkdf2.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include "pbkdf2.h" 26 | #include "hmac.h" 27 | 28 | void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, 29 | uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, 30 | uint32_t total)) 31 | { 32 | const uint32_t HMACLEN = 256 / 8; 33 | uint32_t i, j, k; 34 | uint8_t f[HMACLEN], g[HMACLEN]; 35 | uint32_t blocks = keylen / HMACLEN; 36 | if (keylen & (HMACLEN - 1)) { 37 | blocks++; 38 | } 39 | for (i = 1; i <= blocks; i++) { 40 | salt[saltlen ] = (i >> 24) & 0xFF; 41 | salt[saltlen + 1] = (i >> 16) & 0xFF; 42 | salt[saltlen + 2] = (i >> 8) & 0xFF; 43 | salt[saltlen + 3] = i & 0xFF; 44 | hmac_sha256(pass, passlen, salt, saltlen + 4, g); 45 | memcpy(f, g, HMACLEN); 46 | for (j = 1; j < iterations; j++) { 47 | hmac_sha256(pass, passlen, g, HMACLEN, g); 48 | for (k = 0; k < HMACLEN; k++) { 49 | f[k] ^= g[k]; 50 | } 51 | if (progress_callback && (j % 256 == 255)) { 52 | progress_callback(j + 1, iterations); 53 | } 54 | } 55 | if (i == blocks && (keylen & (HMACLEN - 1))) { 56 | memcpy(key + HMACLEN * (i - 1), f, keylen & (HMACLEN - 1)); 57 | } else { 58 | memcpy(key + HMACLEN * (i - 1), f, HMACLEN); 59 | } 60 | } 61 | } 62 | 63 | void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, uint8_t *salt, int saltlen, 64 | uint32_t iterations, uint8_t *key, int keylen, void (*progress_callback)(uint32_t current, 65 | uint32_t total)) 66 | { 67 | const uint32_t HMACLEN = 512 / 8; 68 | uint32_t i, j, k; 69 | uint8_t f[HMACLEN], g[HMACLEN]; 70 | uint32_t blocks = keylen / HMACLEN; 71 | if (keylen & (HMACLEN - 1)) { 72 | blocks++; 73 | } 74 | for (i = 1; i <= blocks; i++) { 75 | salt[saltlen ] = (i >> 24) & 0xFF; 76 | salt[saltlen + 1] = (i >> 16) & 0xFF; 77 | salt[saltlen + 2] = (i >> 8) & 0xFF; 78 | salt[saltlen + 3] = i & 0xFF; 79 | hmac_sha512(pass, passlen, salt, saltlen + 4, g); 80 | memcpy(f, g, HMACLEN); 81 | for (j = 1; j < iterations; j++) { 82 | hmac_sha512(pass, passlen, g, HMACLEN, g); 83 | for (k = 0; k < HMACLEN; k++) { 84 | f[k] ^= g[k]; 85 | } 86 | if (progress_callback && (j % 256 == 255)) { 87 | progress_callback(j + 1, iterations); 88 | } 89 | } 90 | if (i == blocks && (keylen & (HMACLEN - 1))) { 91 | memcpy(key + HMACLEN * (i - 1), f, keylen & (HMACLEN - 1)); 92 | } else { 93 | memcpy(key + HMACLEN * (i - 1), f, HMACLEN); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | 29 | #ifndef _MEMORY_H_ 30 | #define _MEMORY_H_ 31 | 32 | #include 33 | 34 | #define MEM_PAGE_LEN 32 35 | 36 | // User Zones: 0x0000 to 0x0FFF 37 | #define MEM_TOUCH_TIMEOUT_ADDR 0x0022// Zone 0 38 | #define MEM_TOUCH_THRESH_ADDR 0x0024 39 | #define MEM_TOUCH_ENABLE_ADDR 0x0026 40 | #define MEM_ERASED_ADDR 0x0028 41 | #define MEM_SETUP_ADDR 0x0030 42 | #define MEM_ACCESS_ERR_ADDR 0x0032 43 | #define MEM_UNLOCKED_ADDR 0x0034 44 | #define MEM_AESKEY_MEMSEED_ADDR 0x0036 45 | #define MEM_NAME_ADDR 0x0100// Zone 1 46 | #define MEM_MASTER_BIP32_ADDR 0x0200// Zone 2 47 | #define MEM_MASTER_BIP32_CHAIN_ADDR 0x0300// Zone 3 48 | #define MEM_MNEMONIC_BIP32_ADDR_0 0x0400// Zone 4 49 | #define MEM_MNEMONIC_BIP32_ADDR_1 0x0500// Zone 5 50 | #define MEM_AESKEY_STAND_ADDR 0x0600// Zone 6 51 | #define MEM_AESKEY_VERIFY_ADDR 0x0700// Zone 7 52 | #define MEM_AESKEY_CRYPT_ADDR 0x0800// Zone 8 53 | 54 | // Default settings 55 | #define DEFAULT_unlocked_ 0xFF 56 | #define DEFAULT_erased_ 0xFF 57 | #define DEFAULT_setup_ 0xFF 58 | #define DEFAULT_access_err_ STATUS_ACCESS_INITIALIZE 59 | #define DEFAULT_touch_timeout_ 3000// msec 60 | #define DEFAULT_touch_thresh_ 15//v0_4 25//v0_3x 61 | 62 | 63 | typedef enum PASSWORD_ID { 64 | PASSWORD_STAND, 65 | PASSWORD_VERIFY, 66 | PASSWORD_MEMORY, 67 | PASSWORD_CRYPT, 68 | PASSWORD_2FA, /* only kept in RAM */ 69 | PASSWORD_NONE /* keep last */ 70 | } PASSWORD_ID; 71 | 72 | 73 | void memory_erase(void); 74 | void memory_erase_seed(void); 75 | void memory_setup(void); 76 | void memory_clear_variables(void); 77 | void memory_mempass(void); 78 | 79 | int memory_aeskey_is_erased(PASSWORD_ID id); 80 | int memory_write_aeskey(const char *password, int len, PASSWORD_ID id); 81 | uint8_t *memory_read_aeskey(PASSWORD_ID id); 82 | uint8_t *memory_name(const char *name); 83 | uint8_t *memory_master(const uint8_t *master_priv_key); 84 | uint8_t *memory_chaincode(const uint8_t *chain_code); 85 | uint16_t *memory_mnemonic(const uint16_t *index); 86 | 87 | uint8_t *memory_read_memseed(void); 88 | uint16_t memory_read_touch_timeout(void); 89 | uint16_t memory_read_touch_thresh(void); 90 | uint8_t memory_read_erased(void); 91 | uint8_t memory_read_setup(void); 92 | uint8_t memory_read_unlocked(void); 93 | 94 | void memory_write_memseed(const uint8_t *s); 95 | void memory_write_touch_timeout(const uint16_t t); 96 | void memory_write_touch_thresh(const uint16_t t); 97 | void memory_write_erased(const uint8_t erase); 98 | void memory_write_setup(const uint8_t setup); 99 | void memory_write_unlocked(const uint8_t u); 100 | 101 | uint16_t memory_access_err_count(const uint8_t access); 102 | uint16_t memory_read_access_err_count(void); 103 | 104 | 105 | #endif // _MEMORY_H_ 106 | -------------------------------------------------------------------------------- /src/uECC.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ 2 | /* Copyright 2015, Douglas J Bakkum - removed non secp256k1 curves; added supporting functions */ 3 | 4 | #ifndef _MICRO_ECC_H_ 5 | #define _MICRO_ECC_H_ 6 | 7 | #include 8 | 9 | /* Platform selection options. 10 | If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros. 11 | Possible values for uECC_PLATFORM are defined below: */ 12 | #define uECC_arch_other 0 13 | #define uECC_x86 1 14 | #define uECC_x86_64 2 15 | #define uECC_arm 3 16 | #define uECC_arm_thumb 4 17 | #define uECC_avr 5 18 | #define uECC_arm_thumb2 6 19 | 20 | /* Inline assembly options. 21 | uECC_asm_none - Use standard C99 only. 22 | uECC_asm_small - Use GCC inline assembly for the target platform (if available), optimized for minimum size. 23 | uECC_asm_fast - Use GCC inline assembly optimized for maximum speed. */ 24 | #define uECC_asm_none 0 25 | #define uECC_asm_small 1 26 | #define uECC_asm_fast 2 27 | #define uECC_ASM uECC_asm_fast 28 | 29 | /* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be used for (scalar) squaring 30 | instead of the generic multiplication function. This will make things faster by about 8% but increases the code size. */ 31 | #define uECC_SQUARE_FUNC 1 32 | 33 | #define uECC_secp256k1 4 34 | #define uECC_CURVE uECC_secp256k1 35 | #define uECC_WORD_SIZE 4 36 | #define uECC_BYTES 32 37 | 38 | #define uECC_CONCAT1(a, b) a##b 39 | #define uECC_CONCAT(a, b) uECC_CONCAT1(a, b) 40 | 41 | 42 | // Generate an ECDSA signature for a given hash value. 43 | // Returns 0 always. 44 | int uECC_sign_digest(const uint8_t p_privateKey[uECC_BYTES], 45 | const uint8_t p_hash[uECC_BYTES], 46 | uint8_t p_signature[uECC_BYTES * 2]); 47 | 48 | // Performs sha256 hash on msg before signing. 49 | // Returns 0 if the signature generated successfully, 1 if an error occurred. 50 | int uECC_sign(const uint8_t *p_privateKey, const uint8_t *msg, 51 | uint32_t msg_len, uint8_t *p_signature); 52 | 53 | // Performs double sha256 hash on msg before signing. 54 | // Returns 0 if the signature generated successfully, 1 if an error occurred. 55 | int uECC_sign_double(const uint8_t *p_privateKey, const uint8_t *msg, 56 | uint32_t msg_len, uint8_t *p_signature); 57 | 58 | // Verify an ECDSA signature. 59 | // Returns 0 if the signature is valid, 1 if it is invalid. 60 | int uECC_verify_digest(const uint8_t p_publicKey[uECC_BYTES * 2], 61 | const uint8_t p_hash[uECC_BYTES], 62 | const uint8_t p_signature[uECC_BYTES * 2]); 63 | 64 | // Performs sha256 hash on msg before verification 65 | int uECC_verify(const uint8_t *p_publicKey, const uint8_t *p_signature, 66 | const uint8_t *msg, uint32_t msg_len); 67 | 68 | // Performs double sha256 hash on msg before verification 69 | int uECC_verify_double(const uint8_t *p_publicKey, const uint8_t *p_signature, 70 | const uint8_t *msg, uint32_t msg_len); 71 | 72 | // Get a child private key 73 | // child = (master + z) % order 74 | void uECC_generate_private_key(uint8_t *p_privateChild, 75 | const uint8_t *p_privateMaster, 76 | const uint8_t *z); 77 | 78 | // Check if the private key is not equal to 0 and less than the order 79 | // Returns 1 if valid 80 | int uECC_isValid(uint8_t *p_key); 81 | 82 | // Deterministic signatures following RFC6979 83 | int generate_k_rfc6979_test(uint8_t *secret, const uint8_t *priv_key, 84 | const uint8_t *hash); 85 | 86 | // Get the public key from the private key 87 | void uECC_get_public_key65(const uint8_t p_privateKey[uECC_BYTES], 88 | uint8_t p_publicKey[uECC_BYTES * 2 + 1]); 89 | void uECC_get_public_key64(const uint8_t p_privateKey[uECC_BYTES], 90 | uint8_t p_publicKey[uECC_BYTES * 2]); 91 | void uECC_get_public_key33(const uint8_t p_privateKey[uECC_BYTES], 92 | uint8_t p_publicKey[uECC_BYTES + 1]); 93 | 94 | 95 | #endif /* _MICRO_ECC_H_ */ 96 | -------------------------------------------------------------------------------- /tests/tests_openssl.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * Copyright (c) 2015 Douglas J. Bakkum 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining 7 | * a copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, including without limitation 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the 11 | * Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included 14 | * in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 20 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | * OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "uECC.h" 32 | #include "random.h" 33 | #include "utils.h" 34 | 35 | 36 | int main(int argc, char *argv[]) 37 | { 38 | uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], buffer[1000], 39 | hash[32], msg_len = 0, *p; 40 | uint32_t i, j, p_len = 0; 41 | SHA256_CTX sha256; 42 | EC_GROUP *ecgroup; 43 | int cnt = 0, err = 0; 44 | 45 | random_init(); 46 | ecgroup = EC_GROUP_new_by_curve_name(NID_secp256k1); 47 | 48 | unsigned long max_iterations = -1; 49 | if (argc == 2) { 50 | sscanf(argv[1], "%lu", &max_iterations); 51 | } else if (argc > 2) { 52 | puts("Zero or one command-line arguments only, exiting...."); 53 | } 54 | unsigned long iterations = 0; 55 | while (argc == 1 || iterations < max_iterations) { 56 | 57 | // random message len between 1 and 256 58 | random_bytes(msg, 1 , 0); 59 | msg_len = msg[0]; 60 | 61 | // create random message 62 | random_bytes(msg, msg_len, 0); 63 | 64 | // new ECDSA key 65 | EC_KEY *eckey = EC_KEY_new(); 66 | EC_KEY_set_group(eckey, ecgroup); 67 | 68 | // generate the key 69 | EC_KEY_generate_key(eckey); 70 | // copy key to buffer 71 | p = buffer; 72 | p_len = i2d_ECPrivateKey(eckey, &p); 73 | 74 | // size of the key is in buffer[8] and the key begins right after that 75 | i = buffer[8]; 76 | // extract key data 77 | if (i > 32) { 78 | for (j = 0; j < 32; j++) { 79 | priv_key[j] = buffer[j + i - 23]; 80 | } 81 | } else { 82 | for (j = 0; j < 32 - i; j++) { 83 | priv_key[j] = 0; 84 | } 85 | for (j = 0; j < i; j++) { 86 | priv_key[j + 32 - i] = buffer[j + 9]; 87 | } 88 | } 89 | 90 | // use our ECDSA signer to sign the message with the key 91 | if (uECC_sign(priv_key, msg, msg_len, sig)) { 92 | printf("signing failed\n"); 93 | err++; 94 | break; 95 | } 96 | 97 | // generate public key from private key 98 | uECC_get_public_key33(priv_key, pub_key33); 99 | uECC_get_public_key65(priv_key, pub_key65); 100 | 101 | // verify the message signature 102 | if (uECC_verify(pub_key65, sig, msg, msg_len)) { 103 | printf("verification failed (pub_key_len = 65)\n"); 104 | err++; 105 | break; 106 | } 107 | if (uECC_verify(pub_key33, sig, msg, msg_len)) { 108 | printf("verification failed (pub_key_len = 33)\n"); 109 | err++; 110 | break; 111 | } 112 | 113 | // copy signature to the OpenSSL struct 114 | ECDSA_SIG *signature = ECDSA_SIG_new(); 115 | BN_bin2bn(sig, 32, signature->r); 116 | BN_bin2bn(sig + 32, 32, signature->s); 117 | 118 | // compute the digest of the message 119 | SHA256_Init(&sha256); 120 | SHA256_Update(&sha256, msg, msg_len); 121 | SHA256_Final(hash, &sha256); 122 | 123 | // verify all went well, i.e. we can decrypt our signature with OpenSSL 124 | if (ECDSA_do_verify(hash, 32, signature, eckey) != 1) { 125 | printf("OpenSSL verification failed\n"); 126 | err++; 127 | break; 128 | } 129 | ECDSA_SIG_free(signature); 130 | EC_KEY_free(eckey); 131 | cnt++; 132 | if ((cnt % 100) == 0) { 133 | printf("Passed ... %d\n", cnt); 134 | } 135 | ++iterations; 136 | } 137 | 138 | if (err) { 139 | printf("message to sign:\n%s\n\n", utils_uint8_to_hex(msg, msg_len)); 140 | printf("eckey dump:\n%.*s\n\n", p_len, utils_uint8_to_hex(p, sizeof(buffer))); 141 | //printf("eckey dump:\n%s\n\n", utils_uint8_to_hex(p, sizeof(buffer))); 142 | } 143 | 144 | EC_GROUP_free(ecgroup); 145 | return err; 146 | } 147 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(mcu) 3 | 4 | 5 | #----------------------------------------------------------------------------- 6 | # Create version header file 7 | 8 | find_package(Git) 9 | if(GIT_FOUND) 10 | execute_process(COMMAND git "describe" "--tags" OUTPUT_VARIABLE GIT_COMMIT_HASH WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_STRIP_TRAILING_WHITESPACE) 11 | else() 12 | set(GIT_COMMIT_HASH "Git not found.") 13 | endif() 14 | set(VERSION_STRING "${GIT_COMMIT_HASH}") 15 | 16 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in 17 | ${CMAKE_CURRENT_SOURCE_DIR}/src/version.h) 18 | set(version_file "${CMAKE_CURRENT_SOURCE_DIR}/src/version.h") 19 | 20 | 21 | #----------------------------------------------------------------------------- 22 | # Options for building 23 | 24 | option(BUILD_TESTS "Build the unit tests." ON) 25 | #option(BUILD_DOCUMENTATION "Build the Doxygen documentation." ON) 26 | 27 | set(CMAKE_VERBOSE_MAKEFILE ON) 28 | 29 | 30 | #----------------------------------------------------------------------------- 31 | # Print system information and build options 32 | 33 | message(STATUS "General -------------------------------------") 34 | message(STATUS "mcu version: ${VERSION_STRING}") 35 | message(STATUS "Git Commit Hash: ${GIT_COMMIT_HASH}") 36 | message(STATUS "CMake version: ${CMAKE_VERSION}") 37 | message(STATUS "System: ${CMAKE_SYSTEM}") 38 | message(STATUS "Processor: ${CMAKE_SYSTEM_PROCESSOR}") 39 | 40 | message(STATUS "Verbose: ${CMAKE_VERBOSE_MAKEFILE}") 41 | message(STATUS "Testing: ${BUILD_TESTS}") 42 | #message(STATUS "Documentation: ${BUILD_DOCUMENTATION}") 43 | 44 | 45 | #----------------------------------------------------------------------------- 46 | # Collect all binaries into bin subdirectory 47 | 48 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin) 49 | set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib) 50 | 51 | 52 | #----------------------------------------------------------------------------- 53 | # Compiler flags 54 | 55 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") 56 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Os") 57 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -W -Wall -Wextra -Werror -pedantic -Wredundant-decls -Wstrict-prototypes -Wundef -Wshadow -Wpointer-arith -Wmultichar -Wformat-nonliteral -Winit-self -Wformat-security -Wold-style-definition -Wmissing-include-dirs -Wbad-function-cast -Winline -Wnested-externs -Wfloat-equal -Wmissing-declarations -Wswitch-default -Wwrite-strings -Wcast-qual -Wmissing-prototypes") 58 | 59 | if(APPLE) 60 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations") 61 | set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -framework AppKit -framework IOKit") 62 | set(CMAKE_MACOSX_RPATH ON) 63 | endif() 64 | 65 | #if(${CMAKE_C_COMPILER_ID} MATCHES GNU) 66 | #elseif(${CMAKE_CXX_COMPILER_ID} MATCHES Clang) 67 | #endif() 68 | 69 | message(STATUS "C Compiler ID: ${CMAKE_C_COMPILER_ID}") 70 | message(STATUS "C Flags: ${CMAKE_C_FLAGS}") 71 | message(STATUS "C link flags: ${CMAKE_C_LINK_FLAGS}") 72 | 73 | 74 | #----------------------------------------------------------------------------- 75 | # Get submodules 76 | 77 | execute_process(COMMAND git "submodule" "update" "--init" "--recursive" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) 78 | 79 | 80 | #----------------------------------------------------------------------------- 81 | # Third party libraries 82 | 83 | if(BUILD_TESTS) 84 | find_package(OpenSSL REQUIRED) 85 | 86 | if(NOT CONTINUOUS_INTEGRATION) 87 | find_library(HIDAPI_LIBRARY 88 | NAMES hidapi hidapi-libusb) 89 | 90 | find_path(HIDAPI_INCLUDE_DIR 91 | NAMES hidapi.h 92 | PATH_SUFFIXES 93 | hidapi) 94 | 95 | if(!HIDAPI_FOUND) 96 | message(FATAL_ERROR "hidapi not found.") 97 | endif() 98 | endif() 99 | endif() 100 | 101 | 102 | #----------------------------------------------------------------------------- 103 | # Force out-of-source build 104 | 105 | if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) 106 | message(FATAL_ERROR "CMake generation is not allowed within the source directory! 107 | Remove the CMakeCache.txt file and try again from another folder, e.g.: 108 | 109 | rm CMakeCache.txt 110 | mkdir build 111 | cd build 112 | cmake .. 113 | ") 114 | endif() 115 | 116 | 117 | #----------------------------------------------------------------------------- 118 | # Default to Release build 119 | 120 | if(NOT CMAKE_BUILD_TYPE) 121 | set(CMAKE_BUILD_TYPE Release CACHE STRING 122 | "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." 123 | FORCE) 124 | endif() 125 | 126 | 127 | #----------------------------------------------------------------------------- 128 | # Build Documentation 129 | 130 | #if(BUILD_DOCUMENTATION) 131 | # set(DOC_GRAPHS "YES" CACHE STRING "Create dependency graphs (needs graphviz)") 132 | # set(DOC_FULLGRAPHS "NO" CACHE STRING "Create call/callee graphs (large)") 133 | # 134 | # find_program(DOT_PATH dot) 135 | # 136 | # if (DOT_PATH STREQUAL "DOT_PATH-NOTFOUND") 137 | # message("Doxygen: graphviz not found - graphs disabled") 138 | # set(DOC_GRAPHS "NO") 139 | # endif() 140 | # 141 | # find_package(Doxygen) 142 | # if(DOXYGEN_FOUND) 143 | # configure_file("cmake/Doxyfile.in" "Doxyfile" @ONLY) 144 | # configure_file("cmake/Doxygen.extra.css.in" "Doxygen.extra.css" @ONLY) 145 | # add_custom_target(doc 146 | # ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 147 | # WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 148 | # COMMENT "Generating API documentation with Doxygen.." VERBATIM) 149 | # endif() 150 | #endif() 151 | 152 | 153 | #----------------------------------------------------------------------------- 154 | # Source Definitions 155 | 156 | if(CONTINUOUS_INTEGRATION) 157 | add_definitions(-DCONTINUOUS_INTEGRATION) 158 | endif() 159 | 160 | if(BUILD_TESTS) 161 | add_definitions(-DTESTING) 162 | endif() 163 | 164 | 165 | #----------------------------------------------------------------------------- 166 | # Build source 167 | 168 | add_subdirectory(src) 169 | 170 | if(BUILD_TESTS) 171 | add_subdirectory(tests) 172 | add_test(NAME tests_unit COMMAND tests_unit) 173 | add_test(NAME tests_openssl COMMAND tests_openssl 200) 174 | add_test(NAME tests_api COMMAND tests_api) 175 | enable_testing() 176 | endif() 177 | -------------------------------------------------------------------------------- /src/bip32.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2013-2014 Tomas Dzetkulic 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * Copyright (c) 2015 Douglas J. Bakkumk 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining 7 | * a copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, including without limitation 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the 11 | * Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included 14 | * in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 20 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | * OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | 26 | #include 27 | 28 | #include "ripemd160.h" 29 | #include "base58.h" 30 | #include "bip32.h" 31 | #include "flags.h" 32 | #include "uECC.h" 33 | #include "sha2.h" 34 | #include "hmac.h" 35 | 36 | 37 | // write 4 big endian bytes 38 | static void write_be(uint8_t *data, uint32_t x) 39 | { 40 | data[0] = x >> 24; 41 | data[1] = x >> 16; 42 | data[2] = x >> 8; 43 | data[3] = x; 44 | } 45 | 46 | 47 | // read 4 big endian bytes 48 | static uint32_t read_be(const uint8_t *data) 49 | { 50 | return (((uint32_t)data[0]) << 24) | 51 | (((uint32_t)data[1]) << 16) | 52 | (((uint32_t)data[2]) << 8) | 53 | (((uint32_t)data[3])); 54 | } 55 | 56 | 57 | int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) 58 | { 59 | uint8_t I[32 + 32]; 60 | memset(out, 0, sizeof(HDNode)); 61 | out->depth = 0; 62 | out->fingerprint = 0x00000000; 63 | out->child_num = 0; 64 | hmac_sha512((const uint8_t *)"Bitcoin seed", 12, seed, seed_len, I); 65 | memcpy(out->private_key, I, 32); 66 | 67 | if (!uECC_isValid(out->private_key)) { 68 | memset(I, 0, sizeof(I)); 69 | return STATUS_ERROR; 70 | } 71 | 72 | memcpy(out->chain_code, I + 32, 32); 73 | hdnode_fill_public_key(out); 74 | memset(I, 0, sizeof(I)); 75 | return STATUS_SUCCESS; 76 | } 77 | 78 | 79 | int hdnode_private_ckd(HDNode *inout, uint32_t i) 80 | { 81 | uint8_t data[1 + 32 + 4]; 82 | uint8_t I[32 + 32]; 83 | uint8_t fingerprint[32]; 84 | uint8_t p[32], z[32]; 85 | 86 | if (i & 0x80000000) { // private derivation 87 | data[0] = 0; 88 | memcpy(data + 1, inout->private_key, 32); 89 | } else { // public derivation 90 | memcpy(data, inout->public_key, 33); 91 | } 92 | write_be(data + 33, i); 93 | 94 | sha256_Raw(inout->public_key, 33, fingerprint); 95 | ripemd160(fingerprint, 32, fingerprint); 96 | inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + 97 | (fingerprint[2] << 8) + fingerprint[3]; 98 | 99 | memcpy(p, inout->private_key, 32); 100 | 101 | hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); 102 | memcpy(inout->chain_code, I + 32, 32); 103 | memcpy(inout->private_key, I, 32); 104 | 105 | memcpy(z, inout->private_key, 32); 106 | 107 | if (!uECC_isValid(z)) { 108 | memset(data, 0, sizeof(data)); 109 | memset(I, 0, sizeof(I)); 110 | return STATUS_ERROR; 111 | } 112 | 113 | 114 | uECC_generate_private_key(inout->private_key, p, z); 115 | 116 | if (!uECC_isValid(inout->private_key)) { 117 | memset(data, 0, sizeof(data)); 118 | memset(I, 0, sizeof(I)); 119 | return STATUS_ERROR; 120 | } 121 | 122 | inout->depth++; 123 | inout->child_num = i; 124 | 125 | hdnode_fill_public_key(inout); // very slow 126 | 127 | memset(data, 0, sizeof(data)); 128 | memset(I, 0, sizeof(I)); 129 | return STATUS_SUCCESS; 130 | } 131 | 132 | 133 | void hdnode_fill_public_key(HDNode *node) 134 | { 135 | uECC_get_public_key33(node->private_key, node->public_key); 136 | } 137 | 138 | 139 | static void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, 140 | char *str, int strsize) 141 | { 142 | uint8_t node_data[78]; 143 | write_be(node_data, version); 144 | node_data[4] = node->depth; 145 | write_be(node_data + 5, node->fingerprint); 146 | write_be(node_data + 9, node->child_num); 147 | memcpy(node_data + 13, node->chain_code, 32); 148 | if (use_public) { 149 | memcpy(node_data + 45, node->public_key, 33); 150 | } else { 151 | node_data[45] = 0; 152 | memcpy(node_data + 46, node->private_key, 32); 153 | } 154 | base58_encode_check(node_data, 78, str, strsize); 155 | } 156 | 157 | 158 | void hdnode_serialize_public(const HDNode *node, char *str, int strsize) 159 | { 160 | hdnode_serialize(node, 0x0488B21E, 1, str, strsize); 161 | } 162 | 163 | 164 | void hdnode_serialize_private(const HDNode *node, char *str, int strsize) 165 | { 166 | hdnode_serialize(node, 0x0488ADE4, 0, str, strsize); 167 | } 168 | 169 | 170 | // check for validity of curve point in case of public data not performed 171 | int hdnode_deserialize(const char *str, HDNode *node) 172 | { 173 | uint8_t node_data[78]; 174 | memset(node, 0, sizeof(HDNode)); 175 | if (!base58_decode_check(str, node_data, sizeof(node_data))) { 176 | return STATUS_ERROR; 177 | } 178 | uint32_t version = read_be(node_data); 179 | if (version == 0x0488B21E) { // public node 180 | memcpy(node->public_key, node_data + 45, 33); 181 | } else if (version == 0x0488ADE4) { // private node 182 | if (node_data[45]) { // invalid data 183 | return STATUS_ERROR; 184 | } 185 | memcpy(node->private_key, node_data + 46, 32); 186 | hdnode_fill_public_key(node); 187 | } else { 188 | return STATUS_ERROR; // invalid version 189 | } 190 | node->depth = node_data[4]; 191 | node->fingerprint = read_be(node_data + 5); 192 | node->child_num = read_be(node_data + 9); 193 | memcpy(node->chain_code, node_data + 13, 32); 194 | return STATUS_SUCCESS; 195 | } 196 | -------------------------------------------------------------------------------- /src/aes.h: -------------------------------------------------------------------------------- 1 | /* 2 | --------------------------------------------------------------------------- 3 | Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. 4 | 5 | LICENSE TERMS 6 | 7 | The redistribution and use of this software (with or without changes) 8 | is allowed without the payment of fees or royalties provided that: 9 | 10 | 1. source code distributions include the above copyright notice, this 11 | list of conditions and the following disclaimer; 12 | 13 | 2. binary distributions include the above copyright notice, this list 14 | of conditions and the following disclaimer in their documentation; 15 | 16 | 3. the name of the copyright holder is not used to endorse products 17 | built using this software without specific written permission. 18 | 19 | DISCLAIMER 20 | 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 25 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | * OTHER DEALINGS IN THE SOFTWARE. 28 | 29 | --------------------------------------------------------------------------- 30 | Issue 09/09/2006 31 | 32 | This is an AES implementation that uses only 8-bit byte operations on the 33 | cipher state. 34 | */ 35 | 36 | #ifndef AES_H 37 | #define AES_H 38 | 39 | #if 1 40 | # define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */ 41 | #endif 42 | #if 1 43 | # define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */ 44 | #endif 45 | #if 0 46 | # define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */ 47 | #endif 48 | #if 0 49 | # define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */ 50 | #endif 51 | #if 0 52 | # define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */ 53 | #endif 54 | #if 0 55 | # define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */ 56 | #endif 57 | 58 | #define N_ROW 4 59 | #define N_COL 4 60 | #define N_BLOCK (N_ROW * N_COL) 61 | #define N_MAX_ROUNDS 14 62 | 63 | typedef unsigned char uint_8t; 64 | 65 | typedef uint_8t return_type; 66 | 67 | /* Warning: The key length for 256 bit keys overflows a byte 68 | (see comment below) 69 | */ 70 | 71 | typedef uint_8t length_type; 72 | 73 | typedef struct { 74 | uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK]; 75 | uint_8t rnd; 76 | } aes_context; 77 | 78 | /* The following calls are for a precomputed key schedule 79 | 80 | NOTE: If the length_type used for the key length is an 81 | unsigned 8-bit character, a key length of 256 bits must 82 | be entered as a length in bytes (valid inputs are hence 83 | 128, 192, 16, 24 and 32). 84 | */ 85 | 86 | #if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) 87 | 88 | return_type aes_set_key( const unsigned char key[], 89 | length_type keylen, 90 | aes_context ctx[1] ); 91 | #endif 92 | 93 | #if defined( AES_ENC_PREKEYED ) 94 | 95 | return_type aes_encrypt( const unsigned char in[N_BLOCK], 96 | unsigned char out[N_BLOCK], 97 | const aes_context ctx[1] ); 98 | 99 | return_type aes_cbc_encrypt( const unsigned char *in, 100 | unsigned char *out, 101 | int n_block, 102 | unsigned char iv[N_BLOCK], 103 | const aes_context ctx[1] ); 104 | #endif 105 | 106 | #if defined( AES_DEC_PREKEYED ) 107 | 108 | return_type aes_decrypt( const unsigned char in[N_BLOCK], 109 | unsigned char out[N_BLOCK], 110 | const aes_context ctx[1] ); 111 | 112 | return_type aes_cbc_decrypt( const unsigned char *in, 113 | unsigned char *out, 114 | int n_block, 115 | unsigned char iv[N_BLOCK], 116 | const aes_context ctx[1] ); 117 | #endif 118 | 119 | /* The following calls are for 'on the fly' keying. In this case the 120 | encryption and decryption keys are different. 121 | 122 | The encryption subroutines take a key in an array of bytes in 123 | key[L] where L is 16, 24 or 32 bytes for key lengths of 128, 124 | 192, and 256 bits respectively. They then encrypts the input 125 | data, in[] with this key and put the reult in the output array 126 | out[]. In addition, the second key array, o_key[L], is used 127 | to output the key that is needed by the decryption subroutine 128 | to reverse the encryption operation. The two key arrays can 129 | be the same array but in this case the original key will be 130 | overwritten. 131 | 132 | In the same way, the decryption subroutines output keys that 133 | can be used to reverse their effect when used for encryption. 134 | 135 | Only 128 and 256 bit keys are supported in these 'on the fly' 136 | modes. 137 | */ 138 | 139 | #if defined( AES_ENC_128_OTFK ) 140 | void aes_encrypt_128( const unsigned char in[N_BLOCK], 141 | unsigned char out[N_BLOCK], 142 | const unsigned char key[N_BLOCK], 143 | uint_8t o_key[N_BLOCK] ); 144 | #endif 145 | 146 | #if defined( AES_DEC_128_OTFK ) 147 | void aes_decrypt_128( const unsigned char in[N_BLOCK], 148 | unsigned char out[N_BLOCK], 149 | const unsigned char key[N_BLOCK], 150 | unsigned char o_key[N_BLOCK] ); 151 | #endif 152 | 153 | #if defined( AES_ENC_256_OTFK ) 154 | void aes_encrypt_256( const unsigned char in[N_BLOCK], 155 | unsigned char out[N_BLOCK], 156 | const unsigned char key[2 * N_BLOCK], 157 | unsigned char o_key[2 * N_BLOCK] ); 158 | #endif 159 | 160 | #if defined( AES_DEC_256_OTFK ) 161 | void aes_decrypt_256( const unsigned char in[N_BLOCK], 162 | unsigned char out[N_BLOCK], 163 | const unsigned char key[2 * N_BLOCK], 164 | unsigned char o_key[2 * N_BLOCK] ); 165 | #endif 166 | 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /src/touch.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | #include "led.h" 31 | #include "flags.h" 32 | #include "touch.h" 33 | #include "memory.h" 34 | #include "systick.h" 35 | #include "commander.h" 36 | 37 | 38 | extern volatile uint16_t systick_current_time_ms; 39 | 40 | volatile uint16_t status_flag = 0u; 41 | volatile uint16_t burst_flag = 0u; 42 | uint16_t qt_holdtime_ms = 1000u; 43 | uint16_t qt_timeout_ms_min = 1000u; 44 | 45 | 46 | #ifndef TESTING 47 | #include "mcu.h" 48 | #include "touch_api.h" 49 | 50 | 51 | void touch_init(void) 52 | { 53 | qt_reset_sensing(); 54 | qt_enable_key(TOUCH_CHANNEL, AKS_GROUP_1, 4u, HYST_6_25); 55 | qt_init_sensing(); 56 | 57 | qt_config_data.qt_di = DEF_QT_DI; 58 | qt_config_data.qt_neg_drift_rate = DEF_QT_NEG_DRIFT_RATE; 59 | qt_config_data.qt_pos_drift_rate = DEF_QT_POS_DRIFT_RATE; 60 | qt_config_data.qt_max_on_duration = DEF_QT_MAX_ON_DURATION; 61 | qt_config_data.qt_drift_hold_time = DEF_QT_DRIFT_HOLD_TIME; 62 | qt_config_data.qt_recal_threshold = DEF_QT_RECAL_THRESHOLD; 63 | qt_config_data.qt_pos_recal_delay = DEF_QT_POS_RECAL_DELAY; 64 | 65 | qt_filter_callback = 0; 66 | } 67 | #endif 68 | 69 | 70 | uint8_t touch_button_press(int long_touch) 71 | { 72 | int pushed = STATUS_NOT_TOUCHED; 73 | int status = STATUS_ERROR; 74 | char message[128]; 75 | int16_t touch_snks; 76 | int16_t touch_sns; 77 | uint16_t exit_time_ms; 78 | 79 | uint16_t qt_timeout_ms = memory_read_touch_timeout(); 80 | uint16_t qt_sensor_thresh = memory_read_touch_thresh(); 81 | 82 | led_on(); 83 | 84 | // Make high priority so that we can timeout 85 | NVIC_SetPriority(SysTick_IRQn, 0); 86 | 87 | systick_current_time_ms = 0; 88 | exit_time_ms = systick_current_time_ms + qt_timeout_ms; 89 | while (systick_current_time_ms < exit_time_ms || long_touch) { 90 | do { 91 | status_flag = qt_measure_sensors(systick_current_time_ms); 92 | burst_flag = status_flag & QTLIB_BURST_AGAIN; 93 | } while (burst_flag); 94 | 95 | touch_snks = qt_measure_data.channel_references[TOUCH_CHANNEL]; 96 | touch_sns = qt_measure_data.channel_signals[TOUCH_CHANNEL]; 97 | 98 | if ((touch_snks - touch_sns ) > qt_sensor_thresh) { 99 | // Touched 100 | led_off(); 101 | exit_time_ms = systick_current_time_ms + qt_timeout_ms; 102 | while (systick_current_time_ms < exit_time_ms) { 103 | do { 104 | status_flag = qt_measure_sensors(systick_current_time_ms); 105 | burst_flag = status_flag & QTLIB_BURST_AGAIN; 106 | } while (burst_flag); 107 | 108 | touch_snks = qt_measure_data.channel_references[TOUCH_CHANNEL]; 109 | touch_sns = qt_measure_data.channel_signals[TOUCH_CHANNEL]; 110 | 111 | // If released before exit_time_ms for long_touch, answer is 'reject' 112 | if (long_touch && (touch_snks - touch_sns ) < (qt_sensor_thresh / 2)) { 113 | pushed = STATUS_ERROR; 114 | break; 115 | } else if (!long_touch) { 116 | pushed = STATUS_TOUCHED; 117 | break; 118 | } else { 119 | pushed = STATUS_TOUCHED; 120 | } 121 | } 122 | break; 123 | } 124 | } 125 | 126 | // Reset lower priority 127 | NVIC_SetPriority(SysTick_IRQn, 15); 128 | if (pushed == STATUS_TOUCHED) { 129 | sprintf(message, "accept"); 130 | status = STATUS_SUCCESS; 131 | led_on(); 132 | delay_ms(300); 133 | led_off(); 134 | delay_ms(300); 135 | led_on(); 136 | delay_ms(300); 137 | led_off(); 138 | 139 | } else if (pushed == STATUS_ERROR) { 140 | sprintf(message, "Aborted by user."); 141 | status = STATUS_ERROR; 142 | led_on(); 143 | delay_ms(100); 144 | led_off(); 145 | delay_ms(100); 146 | led_on(); 147 | delay_ms(100); 148 | led_off(); 149 | delay_ms(100); 150 | led_on(); 151 | delay_ms(100); 152 | led_off(); 153 | 154 | } else { 155 | sprintf(message, "Touchbutton timed out. (%d/%d)", 156 | qt_measure_data.channel_signals[TOUCH_CHANNEL], 157 | qt_measure_data.channel_references[TOUCH_CHANNEL]); 158 | status = STATUS_ERROR; 159 | led_off(); 160 | } 161 | 162 | commander_fill_report("touchbutton", message, status); 163 | return pushed; 164 | } 165 | 166 | void touch_button_parameters(uint16_t timeout, uint16_t threshold) 167 | { 168 | char message[32]; 169 | uint16_t qt_timeout_ms = memory_read_touch_timeout(); 170 | uint16_t qt_sensor_thresh = memory_read_touch_thresh(); 171 | 172 | if (timeout > 0 && qt_timeout_ms != timeout) { 173 | if (timeout > qt_timeout_ms_min) { 174 | qt_timeout_ms = timeout; 175 | } else { 176 | qt_timeout_ms = qt_timeout_ms_min; 177 | } 178 | memory_write_touch_timeout(qt_timeout_ms); 179 | } 180 | 181 | if (threshold > 0 && qt_sensor_thresh != threshold) { 182 | qt_sensor_thresh = threshold; 183 | memory_write_touch_thresh(qt_sensor_thresh); 184 | } 185 | 186 | sprintf(message, "%d", qt_timeout_ms / 1000); 187 | commander_fill_report("touch timeout", message, STATUS_SUCCESS); 188 | 189 | sprintf(message, "%d", qt_sensor_thresh); 190 | commander_fill_report("touch threshold", message, STATUS_SUCCESS); 191 | } 192 | -------------------------------------------------------------------------------- /src/base64.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | https://github.com/superwills/NibbleAndAHalf 4 | base64.h -- Fast base64 encoding and decoding. 5 | version 1.0.0, April 17, 2013 143a 6 | 7 | Copyright (C) 2013 William Sherif 8 | 9 | This software is provided 'as-is', without any express or implied 10 | warranty. In no event will the authors be held liable for any damages 11 | arising from the use of this software. 12 | 13 | Permission is granted to anyone to use this software for any purpose, 14 | including commercial applications, and to alter it and redistribute it 15 | freely, subject to the following restrictions: 16 | 17 | 1. The origin of this software must not be misrepresented; you must not 18 | claim that you wrote the original software. If you use this software 19 | in a product, an acknowledgment in the product documentation would be 20 | appreciated but is not required. 21 | 2. Altered source versions must be plainly marked as such, and must not be 22 | misrepresented as being the original software. 23 | 3. This notice may not be removed or altered from any source distribution. 24 | 25 | William Sherif 26 | will.sherif@gmail.com 27 | 28 | YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz 29 | 30 | */ 31 | #ifndef BASE64_H 32 | #define BASE64_H 33 | 34 | #include "base64.h" 35 | #include 36 | #include 37 | #include 38 | 39 | static const char *b64 = 40 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; 41 | 42 | // maps A=>0,B=>1.. 43 | static const unsigned char unb64[] = { 44 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10 45 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20 46 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30 47 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40 48 | 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50 49 | 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60 50 | 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70 51 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80 52 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90 53 | 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100 54 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110 55 | 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120 56 | 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130 57 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140 58 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150 59 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160 60 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170 61 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180 62 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190 63 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200 64 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210 65 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220 66 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230 67 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240 68 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250 69 | 0, 0, 0, 0, 0, 0, 70 | }; // This array has 255 elements 71 | 72 | // Converts binary data of length=len to base64 characters. 73 | // Length of the resultant string is stored in flen 74 | // (you must pass pointer flen). 75 | char *base64( const void *binaryData, int len, int *flen ) 76 | { 77 | const unsigned char *bin = (const unsigned char *) binaryData ; 78 | char *res ; 79 | 80 | int rc = 0 ; // result counter 81 | int byteNo ; // I need this after the loop 82 | 83 | int modulusLen = len % 3 ; 84 | int pad = ((modulusLen & 1) << 1) + ((modulusLen & 2) >> 1) 85 | ; // 2 gives 1 and 1 gives 2, but 0 gives 0. 86 | 87 | *flen = 4 * (len + pad) / 3 ; 88 | res = malloc( *flen + 1 ) ; // and one for the null 89 | if ( !res ) { 90 | return 0; 91 | } 92 | 93 | for ( byteNo = 0 ; byteNo <= len - 3 ; byteNo += 3 ) { 94 | unsigned char BYTE0 = bin[byteNo]; 95 | unsigned char BYTE1 = bin[byteNo + 1]; 96 | unsigned char BYTE2 = bin[byteNo + 2]; 97 | res[rc++] = b64[ BYTE0 >> 2 ] ; 98 | res[rc++] = b64[ ((0x3 & BYTE0) << 4) + (BYTE1 >> 4) ] ; 99 | res[rc++] = b64[ ((0x0f & BYTE1) << 2) + (BYTE2 >> 6) ] ; 100 | res[rc++] = b64[ 0x3f & BYTE2 ] ; 101 | } 102 | 103 | if ( pad == 2 ) { 104 | res[rc++] = b64[ bin[byteNo] >> 2 ] ; 105 | res[rc++] = b64[ (0x3 & bin[byteNo]) << 4 ] ; 106 | res[rc++] = '='; 107 | res[rc++] = '='; 108 | } else if ( pad == 1 ) { 109 | res[rc++] = b64[ bin[byteNo] >> 2 ] ; 110 | res[rc++] = b64[ ((0x3 & bin[byteNo]) << 4) + (bin[byteNo + 1] >> 4) ] ; 111 | res[rc++] = b64[ (0x0f & bin[byteNo + 1]) << 2 ] ; 112 | res[rc++] = '='; 113 | } 114 | 115 | res[rc] = 0; // NULL TERMINATOR! ;) 116 | return res ; 117 | } 118 | 119 | unsigned char *unbase64( const char *ascii, int len, int *flen ) 120 | { 121 | const unsigned char *safeAsciiPtr = (const unsigned char *)ascii ; 122 | unsigned char *bin ; 123 | int cb = 0; 124 | int charNo; 125 | int pad = 0 ; 126 | 127 | if ( len < 2 ) { // 2 accesses below would be OOB. 128 | // catch empty string, return NULL as result. 129 | *flen = 0; 130 | return 0; 131 | } 132 | 133 | for ( int i = 0; i < len; i++ ) { 134 | if (safeAsciiPtr[i] == '=') { 135 | ++pad; 136 | if (pad > 2) { 137 | // invalid padding 138 | *flen = 0; 139 | return 0; 140 | } 141 | } else if (strchr(b64, safeAsciiPtr[i]) == NULL) { 142 | // invalid character 143 | *flen = 0; 144 | return 0; 145 | } else if (pad) { 146 | // contains data beyond pad symbol 147 | *flen = 0; 148 | return 0; 149 | } 150 | } 151 | 152 | *flen = 3 * len / 4 - pad ; 153 | bin = malloc( *flen ) ; 154 | if ( !bin ) { 155 | return 0; 156 | } 157 | 158 | for ( charNo = 0; charNo <= len - 4 - pad ; charNo += 4 ) { 159 | int A = unb64[safeAsciiPtr[charNo]]; 160 | int B = unb64[safeAsciiPtr[charNo + 1]]; 161 | int C = unb64[safeAsciiPtr[charNo + 2]]; 162 | int D = unb64[safeAsciiPtr[charNo + 3]]; 163 | 164 | bin[cb++] = (A << 2) | (B >> 4) ; 165 | bin[cb++] = (B << 4) | (C >> 2) ; 166 | bin[cb++] = (C << 6) | (D) ; 167 | } 168 | 169 | if ( pad == 1 ) { 170 | int A = unb64[safeAsciiPtr[charNo]]; 171 | int B = unb64[safeAsciiPtr[charNo + 1]]; 172 | int C = unb64[safeAsciiPtr[charNo + 2]]; 173 | 174 | bin[cb++] = (A << 2) | (B >> 4) ; 175 | bin[cb++] = (B << 4) | (C >> 2) ; 176 | } else if ( pad == 2 ) { 177 | int A = unb64[safeAsciiPtr[charNo]]; 178 | int B = unb64[safeAsciiPtr[charNo + 1]]; 179 | 180 | bin[cb++] = (A << 2) | (B >> 4) ; 181 | } 182 | 183 | return bin ; 184 | } 185 | 186 | #endif 187 | -------------------------------------------------------------------------------- /src/flags.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #ifndef _FLAGS_H_ 29 | #define _FLAGS_H_ 30 | 31 | 32 | #define _STRINGIFY(S) #S 33 | #define STRINGIFY(S) _STRINGIFY(S) 34 | 35 | #define GENERATE_STRING(STRING) #STRING, 36 | #define GENERATE_ENUM_ATTR(ENUM) ATTR_ ## ENUM ## _, 37 | #define GENERATE_ENUM_CMD(ENUM) CMD_ ## ENUM ## _, 38 | 39 | #define FOREACH_CMD(CMD) \ 40 | /* parent commands */ \ 41 | /* requiring touch */ \ 42 | CMD(sign) \ 43 | CMD(seed) \ 44 | CMD(test) \ 45 | CMD(password) \ 46 | CMD(touchbutton) \ 47 | /* placeholder don't move */ \ 48 | CMD(require_touch) \ 49 | /* parent commands */ \ 50 | /* not requiring touch */ \ 51 | CMD(led) \ 52 | CMD(xpub) \ 53 | CMD(name) \ 54 | CMD(reset) \ 55 | CMD(device) \ 56 | CMD(random) \ 57 | CMD(backup) \ 58 | CMD(aes256cbc) \ 59 | CMD(verifypass) \ 60 | CMD(ciphertext) \ 61 | /* child commands */ \ 62 | CMD(timeout) \ 63 | CMD(holdtime) \ 64 | CMD(threshold) \ 65 | CMD(generate) \ 66 | CMD(source) \ 67 | CMD(hash) \ 68 | CMD(type) \ 69 | CMD(data) \ 70 | CMD(checkkey) \ 71 | CMD(keypath) \ 72 | CMD(strength) \ 73 | CMD(salt) \ 74 | CMD(filename) \ 75 | CMD(decrypt) \ 76 | CMD(encrypt) \ 77 | CMD(pubkey) \ 78 | CMD(pubkeyhash) \ 79 | CMD(status) \ 80 | CMD(eccsig) \ 81 | CMD(pin) \ 82 | /* placeholder don't move */ \ 83 | CMD(none) /* keep last */ 84 | 85 | #define FOREACH_ATTR(ATTR) \ 86 | /* command attributes */ \ 87 | ATTR(true) \ 88 | ATTR(list) \ 89 | ATTR(lock) \ 90 | ATTR(erase) \ 91 | ATTR(toggle) \ 92 | ATTR(pseudo) \ 93 | ATTR(create) \ 94 | ATTR(export) \ 95 | ATTR(serial) \ 96 | ATTR(version) \ 97 | ATTR(decrypt) \ 98 | ATTR(encrypt) \ 99 | ATTR(password) \ 100 | ATTR(xpub) \ 101 | ATTR(__ERASE__) \ 102 | ATTR(__FORCE__) \ 103 | ATTR(none) /* keep last */ 104 | 105 | enum CMD_ENUM { FOREACH_CMD(GENERATE_ENUM_CMD) }; 106 | enum ATTR_ENUM { FOREACH_ATTR(GENERATE_ENUM_ATTR) }; 107 | 108 | #define CMD_NUM CMD_none_ 109 | #define ATTR_NUM ATTR_none_ 110 | 111 | 112 | enum STATUS_FLAGS { 113 | STATUS_SUCCESS, STATUS_ERROR, STATUS_ERROR_MEM, 114 | STATUS_VERIFY_ECHO, STATUS_VERIFY_SAME, STATUS_VERIFY_DIFFERENT, STATUS_VERIFY_NEXT, 115 | STATUS_TOUCHED, STATUS_NOT_TOUCHED, 116 | STATUS_KEY_PRESENT, STATUS_KEY_ABSENT, 117 | STATUS_RESET, 118 | STATUS_ACCESS_INITIALIZE, STATUS_ACCESS_ITERATE, 119 | STATUS_MEM_ERASED, STATUS_MEM_NOT_ERASED, 120 | STATUS_SD_REPLACE, STATUS_SD_NO_REPLACE 121 | }; 122 | 123 | 124 | #define PASSWORD_LEN_MIN 4 125 | #define DATA_LEN_MAX 1024/*base64 increases size by ~4/3; AES encryption by max 32 char*/ 126 | 127 | #define FLAG_ERR_PASSWORD_LEN "The password length must be at least " STRINGIFY(PASSWORD_LEN_MIN) " characters." 128 | #define FLAG_ERR_NO_PASSWORD "Please set a password." 129 | #define FLAG_ERR_NO_INPUT "No input received." 130 | #define FLAG_ERR_DATA_LEN "Data must be less than " STRINGIFY(DATA_LEN_MAX)" characters." 131 | #define FLAG_ERR_REPORT_BUFFER "{\"output\":{\"error\":\"Output report buffer overflow.\"}}" 132 | #define FLAG_ERR_JSON_PARSE "JSON parse error." 133 | #define FLAG_ERR_JSON_BRACKET "Is the command enclosed by curly brackets?" 134 | #define FLAG_ERR_INVALID_CMD "Invalid command." 135 | #define FLAG_ERR_MULTIPLE_CMD "Only one command allowed at a time." 136 | #define FLAG_ERR_RESET "Too many failed access attempts. Device reset." 137 | #define FLAG_ERR_RESET_WARNING "Too many access errors will cause the device to reset." 138 | #define FLAG_ERR_DEVICE_LOCKED "Device locked. Erase device to access this command." 139 | #define FLAG_ERR_BIP32_MISSING "BIP32 mnemonic not present." 140 | #define FLAG_ERR_DECRYPT "Could not decrypt." 141 | #define FLAG_ERR_MNEMO_CHECK "Invalid mnemonic." 142 | #define FLAG_ERR_PKH_LEN "Incorrect pubkeyhash length. A 20-byte hexadecimal value (40 characters) is expected." 143 | #define FLAG_ERR_SIGN_LEN "Incorrect hash length. A 32-byte hexadecimal value (64 characters) is expected." 144 | #define FLAG_ERR_DESERIALIZE "Could not deserialize outputs or wrong change keypath." 145 | #define FLAG_ERR_KEY_GEN "Could not generate key." 146 | #define FLAG_ERR_SIGN "Could not sign." 147 | #define FLAG_ERR_SALT_LEN "Salt must be less than " STRINGIFY(SALT_LEN_MAX) " characters." 148 | #define FLAG_ERR_SEED_SD "Seed creation requires an SD card for automatic encrypted backup of the seed." 149 | #define FLAG_ERR_SEED_SD_NUM "Too many backup files. Please remove one from the SD card." 150 | #define FLAG_ERR_SEED_MEM "Could not allocate memory for seed." 151 | #define FLAG_ERR_ENCRYPT_MEM "Could not encrypt." 152 | #define FLAG_ERR_ATAES "Chip communication error." 153 | #define FLAG_ERR_FLASH "Could not read flash." 154 | #define FLAG_ERR_NO_MCU "Ignored for non-embedded testing." 155 | #define FLAG_ERR_SD_CARD "Please insert SD card." 156 | #define FLAG_ERR_SD_MOUNT "Could not mount the SD card." 157 | #define FLAG_ERR_SD_OPEN "Could not open a file to write - it may already exist." 158 | #define FLAG_ERR_SD_OPEN_DIR "Could not open the directory." 159 | #define FLAG_ERR_SD_FILE_CORRUPT "Corrupted file." 160 | #define FLAG_ERR_SD_WRITE "Could not write the file." 161 | #define FLAG_ERR_SD_WRITE_LEN "Text to write is too large." 162 | #define FLAG_ERR_SD_READ "Could not read the file." 163 | #define FLAG_ERR_SD_ERASE "May not have erased all files (or no file present)." 164 | #define FLAG_ERR_NUM_FILES "Too many files to read. The list is truncated." 165 | #define FLAG_ERR_PASSWORD_ID "Invalid password ID." 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /src/base58.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2014 Luke Dashjr 3 | * Copyright (c) 2013-2014 Pavol Rusnak 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, including without limitation 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | * and/or sell copies of the Software, and to permit persons to whom the 10 | * Software is furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included 13 | * in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 19 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 | * OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include "base58.h" 28 | #include "sha2.h" 29 | 30 | static const int8_t b58digits_map[] = { 31 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 34 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, 35 | -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, 36 | 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, 37 | -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 38 | 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, 39 | }; 40 | 41 | static int b58tobin(void *bin, size_t *binszp, const char *b58) 42 | { 43 | size_t binsz = *binszp; 44 | const unsigned char *b58u = (const void *)b58; 45 | unsigned char *binu = bin; 46 | size_t outisz = (binsz + 3) / 4; 47 | uint32_t outi[outisz]; 48 | uint64_t t; 49 | uint32_t c; 50 | size_t i, j; 51 | uint8_t bytesleft = binsz % 4; 52 | uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; 53 | unsigned zerocount = 0; 54 | size_t b58sz; 55 | 56 | b58sz = strlen(b58); 57 | 58 | memset(outi, 0, outisz * sizeof(*outi)); 59 | 60 | // Leading zeros, just count 61 | for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i) { 62 | ++zerocount; 63 | } 64 | 65 | for ( ; i < b58sz; ++i) { 66 | if (b58u[i] & 0x80) { 67 | // High-bit set on invalid digit 68 | return false; 69 | } 70 | if (b58digits_map[b58u[i]] == -1) { 71 | // Invalid base58 digit 72 | return false; 73 | } 74 | c = (unsigned)b58digits_map[b58u[i]]; 75 | for (j = outisz; j--; ) { 76 | t = ((uint64_t)outi[j]) * 58 + c; 77 | c = (t & 0x3f00000000) >> 32; 78 | outi[j] = t & 0xffffffff; 79 | } 80 | if (c) { 81 | // Output number too big (carry to the next int32) 82 | memset(outi, 0, outisz * sizeof(*outi)); 83 | return false; 84 | } 85 | if (outi[0] & zeromask) { 86 | // Output number too big (last int32 filled too far) 87 | memset(outi, 0, outisz * sizeof(*outi)); 88 | return false; 89 | } 90 | } 91 | 92 | j = 0; 93 | switch (bytesleft) { 94 | case 3: 95 | *(binu++) = (outi[0] & 0xff0000) >> 16; 96 | case 2: 97 | *(binu++) = (outi[0] & 0xff00) >> 8; 98 | case 1: 99 | *(binu++) = (outi[0] & 0xff); 100 | ++j; 101 | default: 102 | break; 103 | } 104 | 105 | for (; j < outisz; ++j) { 106 | *(binu++) = (outi[j] >> 0x18) & 0xff; 107 | *(binu++) = (outi[j] >> 0x10) & 0xff; 108 | *(binu++) = (outi[j] >> 8) & 0xff; 109 | *(binu++) = (outi[j] >> 0) & 0xff; 110 | } 111 | 112 | // Count canonical base58 byte count 113 | binu = bin; 114 | for (i = 0; i < binsz; ++i) { 115 | if (binu[i]) { 116 | break; 117 | } 118 | --*binszp; 119 | } 120 | *binszp += zerocount; 121 | 122 | memset(outi, 0, outisz * sizeof(*outi)); 123 | return true; 124 | } 125 | 126 | static int b58check(const void *bin, size_t binsz, const char *base58str) 127 | { 128 | unsigned char buf[32]; 129 | const uint8_t *binc = bin; 130 | unsigned i; 131 | if (binsz < 4) { 132 | return -4; 133 | } 134 | sha256_Raw(bin, binsz - 4, buf); 135 | sha256_Raw(buf, 32, buf); 136 | if (memcmp(&binc[binsz - 4], buf, 4)) { 137 | return -1; 138 | } 139 | 140 | // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) 141 | for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) { 142 | } // Just finding the end of zeros, nothing to do in loop 143 | if (binc[i] == '\0' || base58str[i] == '1') { 144 | return -3; 145 | } 146 | 147 | return binc[0]; 148 | } 149 | 150 | static const char b58digits_ordered[] = 151 | "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 152 | 153 | static int b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) 154 | { 155 | const uint8_t *bin = data; 156 | int carry; 157 | ssize_t i, j, high, zcount = 0; 158 | size_t size; 159 | 160 | while (zcount < (ssize_t)binsz && !bin[zcount]) { 161 | ++zcount; 162 | } 163 | 164 | size = (binsz - zcount) * 138 / 100 + 1; 165 | uint8_t buf[size]; 166 | memset(buf, 0, size); 167 | 168 | for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) { 169 | for (carry = bin[i], j = size - 1; (j > high) || carry; --j) { 170 | carry += 256 * buf[j]; 171 | buf[j] = carry % 58; 172 | carry /= 58; 173 | } 174 | } 175 | 176 | for (j = 0; j < (ssize_t)size && !buf[j]; ++j); 177 | 178 | if (*b58sz <= zcount + size - j) { 179 | *b58sz = zcount + size - j + 1; 180 | memset(buf, 0, size); 181 | return false; 182 | } 183 | 184 | if (zcount) { 185 | memset(b58, '1', zcount); 186 | } 187 | for (i = zcount; j < (ssize_t)size; ++i, ++j) { 188 | b58[i] = b58digits_ordered[buf[j]]; 189 | } 190 | b58[i] = '\0'; 191 | *b58sz = i + 1; 192 | 193 | memset(buf, 0, size); 194 | return true; 195 | } 196 | 197 | int base58_encode_check(const uint8_t *data, int datalen, char *str, int strsize) 198 | { 199 | int ret; 200 | if (datalen > 128) { 201 | return 0; 202 | } 203 | uint8_t buf[datalen + 32]; 204 | uint8_t *hash = buf + datalen; 205 | memcpy(buf, data, datalen); 206 | sha256_Raw(data, datalen, hash); 207 | sha256_Raw(hash, 32, hash); 208 | size_t res = strsize; 209 | if (b58enc(str, &res, buf, datalen + 4) != true) { 210 | ret = 0; 211 | } else { 212 | ret = res; 213 | } 214 | memset(buf, 0, sizeof(buf)); 215 | return ret; 216 | } 217 | 218 | int base58_decode_check(const char *str, uint8_t *data, int datalen) 219 | { 220 | int ret; 221 | 222 | if (datalen > 128) { 223 | return 0; 224 | } 225 | uint8_t d[datalen + 4]; 226 | size_t res = datalen + 4; 227 | if (b58tobin(d, &res, str) != true) { 228 | ret = 0; 229 | } else if (res != (size_t)datalen + 4) { 230 | ret = 0; 231 | } else if (b58check(d, res, str) < 0) { 232 | ret = 0; 233 | } else { 234 | memcpy(data, d, datalen); 235 | ret = datalen; 236 | } 237 | memset(d, 0, sizeof(d)); 238 | return ret; 239 | } 240 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "utils.h" 34 | #include "flags.h" 35 | #include "commander.h" 36 | #include "yajl/src/api/yajl_tree.h" 37 | 38 | extern const char *CMD_STR[]; 39 | static char PIN_2FA[5] = {0}; 40 | static char decrypted_report[COMMANDER_REPORT_SIZE]; 41 | static uint8_t buffer_hex_to_uint8[TO_UINT8_HEX_BUF_LEN]; 42 | static char buffer_uint8_to_hex[TO_UINT8_HEX_BUF_LEN]; 43 | 44 | 45 | void utils_clear_buffers(void) 46 | { 47 | memset(buffer_hex_to_uint8, 0, TO_UINT8_HEX_BUF_LEN); 48 | memset(buffer_uint8_to_hex, 0, TO_UINT8_HEX_BUF_LEN); 49 | } 50 | 51 | 52 | uint8_t *utils_hex_to_uint8(const char *str) 53 | { 54 | if (strlens(str) > TO_UINT8_HEX_BUF_LEN) { 55 | return NULL; 56 | } 57 | memset(buffer_hex_to_uint8, 0, TO_UINT8_HEX_BUF_LEN); 58 | uint8_t c; 59 | size_t i; 60 | for (i = 0; i < strlens(str) / 2; i++) { 61 | c = 0; 62 | if (str[i * 2] >= '0' && str[i * 2] <= '9') { 63 | c += (str[i * 2] - '0') << 4; 64 | } 65 | if (str[i * 2] >= 'a' && str[i * 2] <= 'f') { 66 | c += (10 + str[i * 2] - 'a') << 4; 67 | } 68 | if (str[i * 2] >= 'A' && str[i * 2] <= 'F') { 69 | c += (10 + str[i * 2] - 'A') << 4; 70 | } 71 | if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') { 72 | c += (str[i * 2 + 1] - '0'); 73 | } 74 | if (str[i * 2 + 1] >= 'a' && str[i * 2 + 1] <= 'f') { 75 | c += (10 + str[i * 2 + 1] - 'a'); 76 | } 77 | if (str[i * 2 + 1] >= 'A' && str[i * 2 + 1] <= 'F') { 78 | c += (10 + str[i * 2 + 1] - 'A'); 79 | } 80 | buffer_hex_to_uint8[i] = c; 81 | } 82 | return buffer_hex_to_uint8; 83 | } 84 | 85 | 86 | char *utils_uint8_to_hex(const uint8_t *bin, size_t l) 87 | { 88 | if (l > (TO_UINT8_HEX_BUF_LEN / 2 - 1)) { 89 | return NULL; 90 | } 91 | static char digits[] = "0123456789abcdef"; 92 | memset(buffer_uint8_to_hex, 0, TO_UINT8_HEX_BUF_LEN); 93 | size_t i; 94 | for (i = 0; i < l; i++) { 95 | buffer_uint8_to_hex[i * 2] = digits[(bin[i] >> 4) & 0xF]; 96 | buffer_uint8_to_hex[i * 2 + 1] = digits[bin[i] & 0xF]; 97 | } 98 | buffer_uint8_to_hex[l * 2] = 0; 99 | return buffer_uint8_to_hex; 100 | } 101 | 102 | 103 | void utils_reverse_hex(char *h, int len) 104 | { 105 | char copy[len]; 106 | strncpy(copy, h, len); 107 | int i; 108 | for (i = 0; i < len; i += 2) { 109 | h[i] = copy[len - i - 2]; 110 | h[i + 1] = copy[len - i - 1]; 111 | } 112 | } 113 | 114 | 115 | void utils_uint64_to_varint(char *vi, int *l, uint64_t i) 116 | { 117 | int len; 118 | char v[VARINT_LEN]; 119 | 120 | if (i < 0xfd) { 121 | sprintf(v, "%02" PRIx64 , i); 122 | len = 2; 123 | } else if (i <= 0xffff) { 124 | sprintf(v, "%04" PRIx64 , i); 125 | sprintf(vi, "fd"); 126 | len = 4; 127 | } else if (i <= 0xffffffff) { 128 | sprintf(v, "%08" PRIx64 , i); 129 | sprintf(vi, "fe"); 130 | len = 8; 131 | } else { 132 | sprintf(v, "%016" PRIx64 , i); 133 | sprintf(vi, "ff"); 134 | len = 16; 135 | } 136 | 137 | // reverse order 138 | if (len > 2) { 139 | utils_reverse_hex(v, len); 140 | strncat(vi, v, len); 141 | } else { 142 | strncpy(vi, v, len); 143 | } 144 | 145 | *l = len; 146 | } 147 | 148 | 149 | int utils_varint_to_uint64(const char *vi, uint64_t *i) 150 | { 151 | char v[VARINT_LEN] = {0}; 152 | int len; 153 | 154 | if (!vi) { 155 | len = 0; 156 | } else if (!strncmp(vi, "ff", 2)) { 157 | len = 16; 158 | } else if (!strncmp(vi, "fe", 2)) { 159 | len = 8; 160 | } else if (!strncmp(vi, "fd", 2)) { 161 | len = 4; 162 | } else { 163 | len = 2; 164 | } 165 | 166 | if (len == 0) { 167 | // continue 168 | } else if (len > 2) { 169 | strncpy(v, vi + 2, len); 170 | utils_reverse_hex(v, len); 171 | } else { 172 | strncpy(v, vi, len); 173 | } 174 | sscanf(v, "%" PRIx64 , i); 175 | 176 | return len; 177 | } 178 | 179 | 180 | char *utils_read_decrypted_report(void) 181 | { 182 | return decrypted_report; 183 | } 184 | 185 | 186 | void utils_decrypt_report(const char *report) 187 | { 188 | int decrypt_len, dec_tfa_len; 189 | char *dec, *dec_tfa; 190 | const char *pin, *tfa; 191 | 192 | memset(decrypted_report, 0, sizeof(decrypted_report)); 193 | 194 | yajl_val json_node = yajl_tree_parse(report, NULL, 0); 195 | 196 | if (!json_node) { 197 | strcpy(decrypted_report, "/* error: Failed to parse report. */"); 198 | return; 199 | } 200 | 201 | size_t i, r = json_node->u.object.len; 202 | for (i = 0; i < r; i++) { 203 | const char *ciphertext_path[] = { CMD_STR[CMD_ciphertext_], (const char *) 0 }; 204 | const char *echo_path[] = { "echo", (const char *) 0 }; 205 | const char *ciphertext = YAJL_GET_STRING(yajl_tree_get(json_node, ciphertext_path, 206 | yajl_t_string)); 207 | const char *echo = YAJL_GET_STRING(yajl_tree_get(json_node, echo_path, yajl_t_string)); 208 | if (ciphertext) { 209 | dec = aes_cbc_b64_decrypt((const unsigned char *)ciphertext, strlens(ciphertext), 210 | &decrypt_len, PASSWORD_STAND); 211 | if (!dec) { 212 | strcpy(decrypted_report, "/* error: Failed to decrypt. */"); 213 | return; 214 | } 215 | 216 | char tfa_report[decrypt_len + 1]; 217 | memcpy(tfa_report, dec, decrypt_len); 218 | tfa_report[decrypt_len] = '\0'; 219 | yajl_val tfa_node = yajl_tree_parse(tfa_report, NULL, 0); 220 | 221 | 222 | const char *tfa_path[] = { "2FA", (const char *) 0 }; 223 | tfa = YAJL_GET_STRING(yajl_tree_get(tfa_node, tfa_path, yajl_t_string)); 224 | if (tfa) { 225 | dec_tfa = aes_cbc_b64_decrypt((const unsigned char *)tfa, strlens(tfa), &dec_tfa_len, 226 | PASSWORD_2FA); 227 | if (!dec_tfa) { 228 | strcpy(decrypted_report, "/* error: Failed to decrypt 2FA. */"); 229 | return; 230 | } 231 | sprintf(decrypted_report, "/* 2FA */ %.*s", dec_tfa_len, dec_tfa); 232 | free(dec_tfa); 233 | } else { 234 | sprintf(decrypted_report, "/* ciphertext */ %.*s", decrypt_len, dec); 235 | } 236 | free(dec); 237 | return; 238 | } else if (echo) { 239 | dec = aes_cbc_b64_decrypt((const unsigned char *)echo, strlens(echo), &decrypt_len, 240 | PASSWORD_VERIFY); 241 | if (!dec) { 242 | strcpy(decrypted_report, "/* error: Failed to decrypt echo. */"); 243 | return; 244 | } 245 | 246 | char pin_report[decrypt_len + 1]; 247 | memcpy(pin_report, dec, decrypt_len); 248 | pin_report[decrypt_len] = '\0'; 249 | yajl_val pin_node = yajl_tree_parse(pin_report, NULL, 0); 250 | 251 | const char *pin_path[] = { CMD_STR[CMD_pin_], (const char *) 0 }; 252 | pin = YAJL_GET_STRING(yajl_tree_get(pin_node, pin_path, yajl_t_string)); 253 | if (pin) { 254 | memcpy(PIN_2FA, pin, 4); 255 | } else { 256 | memset(PIN_2FA, 0, sizeof(PIN_2FA)); 257 | } 258 | sprintf(decrypted_report, "/* echo */ %.*s", decrypt_len, dec); 259 | free(dec); 260 | return; 261 | } 262 | } 263 | strcpy(decrypted_report, report); 264 | return; 265 | } 266 | 267 | 268 | void utils_send_cmd(const char *command, PASSWORD_ID enc_id) 269 | { 270 | if (enc_id == PASSWORD_NONE) { 271 | utils_decrypt_report(commander(command)); 272 | } else { 273 | int encrypt_len; 274 | char *enc = aes_cbc_b64_encrypt((const unsigned char *)command, strlens(command), 275 | &encrypt_len, 276 | enc_id); 277 | char cmd[COMMANDER_REPORT_SIZE] = {0}; 278 | memcpy(cmd, enc, encrypt_len < COMMANDER_REPORT_SIZE ? encrypt_len : 279 | COMMANDER_REPORT_SIZE); 280 | free(enc); 281 | utils_decrypt_report(commander(cmd)); 282 | } 283 | } 284 | 285 | 286 | #ifdef TESTING 287 | 288 | void utils_send_print_cmd(const char *command, PASSWORD_ID enc_id) 289 | { 290 | printf("\nutils send: %s\n", command); 291 | utils_send_cmd(command, enc_id); 292 | printf("utils recv: %s\n\n", decrypted_report); 293 | } 294 | 295 | 296 | #endif 297 | -------------------------------------------------------------------------------- /src/ataes132.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #include 29 | 30 | #include "commander.h" 31 | #include "ataes132.h" 32 | #include "delay.h" 33 | #include "utils.h" 34 | #include "flags.h" 35 | #include "mcu.h" 36 | 37 | 38 | #define aes_build_word_address(p_u8, addr) \ 39 | do {\ 40 | p_u8[0] = (uint8_t)(addr >> 8);\ 41 | p_u8[1] = (uint8_t)(addr & 0xFF);\ 42 | } while (0) 43 | 44 | 45 | void aes_init(void) 46 | { 47 | twi_options_t opts = { 48 | .master_clk = sysclk_get_cpu_hz(), 49 | .speed = AES_TWI_SPEED, 50 | .smbus = 0 51 | }; 52 | sysclk_enable_peripheral_clock(AES_TWI_ID); 53 | twi_master_init(AES_TWI, &opts); 54 | } 55 | 56 | 57 | void aes_calculate_crc(uint8_t length, const uint8_t *data, uint8_t *crc) 58 | { 59 | uint8_t counter; 60 | uint8_t crcLow = 0, crcHigh = 0, crcCarry; 61 | uint8_t polyLow = 0x05, polyHigh = 0x80; 62 | uint8_t shiftRegister; 63 | uint8_t dataBit, crcBit; 64 | 65 | for (counter = 0; counter < length; counter++) { 66 | for (shiftRegister = 0x80; shiftRegister > 0x00; shiftRegister >>= 1) { 67 | dataBit = (data[counter] & shiftRegister) ? 1 : 0; 68 | crcBit = crcHigh >> 7; 69 | crcCarry = crcLow >> 7; 70 | crcLow <<= 1; 71 | crcHigh <<= 1; 72 | crcHigh |= crcCarry; 73 | 74 | if ((dataBit ^ crcBit) != 0) { 75 | crcLow ^= polyLow; 76 | crcHigh ^= polyHigh; 77 | } 78 | } 79 | } 80 | crc[0] = crcHigh; 81 | crc[1] = crcLow; 82 | } 83 | 84 | 85 | uint8_t aes_eeprom_write(uint32_t u32_start_address, uint16_t u16_length, 86 | uint8_t const *p_wr_buffer) 87 | { 88 | twi_package_t twi_package; 89 | twi_package.chip = AES_DEVICE_ADDR; 90 | aes_build_word_address(twi_package.addr, u32_start_address); 91 | twi_package.addr_length = AES_MEM_ADDR_LEN; 92 | twi_package.buffer = (uint8_t *)p_wr_buffer; 93 | twi_package.length = u16_length; 94 | return twi_master_write(AES_TWI, &twi_package); 95 | } 96 | 97 | 98 | uint32_t aes_eeprom_read(uint32_t u32_start_address, uint16_t u16_length, 99 | uint8_t *p_rd_buffer) 100 | { 101 | twi_package_t twi_package; 102 | twi_package.chip = AES_DEVICE_ADDR; 103 | aes_build_word_address(twi_package.addr, u32_start_address); 104 | twi_package.addr_length = AES_MEM_ADDR_LEN; 105 | twi_package.buffer = p_rd_buffer; 106 | twi_package.length = u16_length; 107 | return twi_master_read(AES_TWI, &twi_package); 108 | } 109 | 110 | 111 | /* 112 | Sending command: OP MODE PARAMETER1 PARAMETER2 DATA ... DATA 113 | 0xXX 0xXX 0xXX 0xXX 0xXX 0xXX 0xXX ... 0xXX 114 | Return block: [Count(1) || Return Code (1) | Data(...) || CRC (2)] 115 | */ 116 | void aes_process(uint8_t const *command, uint16_t cmd_len, 117 | uint8_t *response_block, uint16_t response_len) 118 | { 119 | char errmsg[128]; 120 | uint32_t ret = 0; 121 | uint8_t aes_status = 0; 122 | uint8_t delay = 2; // msec 123 | uint8_t timeout = 10; // counts 124 | uint8_t cnt, i, crc[2]; 125 | 126 | uint8_t command_block[cmd_len + 3]; 127 | command_block[0] = cmd_len + 3; 128 | for (i = 0; i < cmd_len; i++) { 129 | command_block[i + 1] = command[i]; 130 | } 131 | 132 | // CRC on [Count | Packet] bytes 133 | aes_calculate_crc(cmd_len + 1, command_block, crc); 134 | 135 | command_block[cmd_len + 1] = crc[0]; 136 | command_block[cmd_len + 2] = crc[1]; 137 | 138 | memset(response_block, 0, response_len); 139 | 140 | // Check if awake 141 | cnt = 0; 142 | while (1) { 143 | ret = aes_eeprom_read(AES_MEM_ADDR_STATUS, 1, &aes_status); 144 | if (!aes_status && !ret) { 145 | break; 146 | } 147 | if ((aes_status & 0x40) && !ret) { 148 | break; 149 | } 150 | if (cnt++ > timeout) { 151 | sprintf(errmsg, "Status buffer 0: %u %lu", aes_status, ret); 152 | commander_fill_report("ataes", errmsg, STATUS_ERROR); 153 | return; 154 | } 155 | delay_ms(delay); 156 | } 157 | 158 | // Reset memory pointer 159 | cnt = 0; 160 | while (1) { 161 | ret = aes_eeprom_write(AES_MEM_ADDR_RESET, 1, 0); 162 | if (!ret) { 163 | break; 164 | } else if (cnt++ > timeout) { 165 | sprintf(errmsg, "Reset buffer 1: %lu", ret); 166 | commander_fill_report("ataes", errmsg, STATUS_ERROR); 167 | return; 168 | } 169 | } 170 | 171 | // Check if ready 172 | cnt = 0; 173 | while (1) { 174 | ret = aes_eeprom_read(AES_MEM_ADDR_STATUS, 1, &aes_status); 175 | if (!aes_status && !ret) { 176 | break; 177 | } 178 | if ((aes_status & 0x40) && !ret) { 179 | break; 180 | } else if (cnt++ > timeout) { 181 | sprintf(errmsg, "Status buffer 1: %u %lu", aes_status, ret); 182 | commander_fill_report("ataes", errmsg, STATUS_ERROR); 183 | return; 184 | } 185 | delay_ms(delay); 186 | } 187 | 188 | // Write command block 189 | cnt = 0; 190 | while (1) { 191 | ret = aes_eeprom_write(AES_MEM_ADDR_IO, cmd_len + 3, command_block); 192 | if (!ret) { 193 | break; 194 | } else if (cnt++ > timeout) { 195 | sprintf(errmsg, "Command buffer: %lu", ret); 196 | commander_fill_report("ataes", errmsg, STATUS_ERROR); 197 | return; 198 | } 199 | } 200 | 201 | // Check if data is available to read (0x40) 202 | cnt = 0; 203 | while (1) { 204 | ret = aes_eeprom_read(AES_MEM_ADDR_STATUS, 1, &aes_status); 205 | if ((aes_status & 0x40) && !ret) { 206 | break; 207 | } 208 | if (cnt++ > timeout) { 209 | sprintf(errmsg, "Status buffer 2: %u %lu", aes_status, ret); 210 | commander_fill_report("ataes", errmsg, STATUS_ERROR); 211 | return; 212 | } 213 | delay_ms(delay); 214 | } 215 | 216 | // Reset memory pointer 217 | cnt = 0; 218 | while (1) { 219 | ret = aes_eeprom_write(AES_MEM_ADDR_RESET, 1, 0); 220 | if (!ret) { 221 | break; 222 | } else if (cnt++ > timeout) { 223 | sprintf(errmsg, "Reset buffer 2: %lu", ret); 224 | commander_fill_report("ataes", errmsg, STATUS_ERROR); 225 | return; 226 | } 227 | } 228 | 229 | // Read response block - does not change STATUS register 230 | cnt = 0; 231 | while (1) { 232 | ret = aes_eeprom_read(AES_MEM_ADDR_IO, response_len, response_block); 233 | if (!ret) { 234 | break; 235 | } else if (cnt++ > timeout) { 236 | sprintf(errmsg, "Response buffer 1: %lu", ret); 237 | commander_fill_report("ataes", errmsg, STATUS_ERROR); 238 | return; 239 | } 240 | } 241 | } 242 | 243 | 244 | // Pass NULL to read only or write only 245 | void aes_eeprom(uint16_t LEN, uint32_t ADDR, uint8_t *userdata_read, 246 | const uint8_t *userdata_write) 247 | { 248 | int ret; 249 | char message[64]; 250 | 251 | uint8_t aes_status = 0; 252 | uint8_t delay = 2; // msec 253 | uint8_t timeout = 10; // counts 254 | uint8_t cnt = 0; 255 | 256 | if (userdata_write != NULL) { 257 | ret = aes_eeprom_write(ADDR, LEN, userdata_write); 258 | if (ret) { 259 | sprintf(message, "EEPROM write error %i.", ret); 260 | commander_fill_report("eeprom", message, STATUS_ERROR); 261 | return; 262 | } 263 | while (1) { 264 | ret = aes_eeprom_read(AES_MEM_ADDR_STATUS, 1, &aes_status); 265 | if (!(aes_status & 0x81) && !ret) { // 0x81 = no error and device ready 266 | break; 267 | } else if (cnt++ > timeout) { 268 | sprintf(message, "EEPROM write error [status]: %u %i", aes_status, ret); 269 | commander_fill_report("eeprom", message, STATUS_ERROR); 270 | return; 271 | } 272 | delay_ms(delay); 273 | } 274 | } 275 | 276 | if (userdata_read != NULL) { 277 | ret = aes_eeprom_read(ADDR, LEN, userdata_read); 278 | if (ret) { 279 | sprintf(message, "EEPROM read error %i.", ret); 280 | commander_fill_report("eeprom", message, STATUS_ERROR); 281 | return; 282 | } 283 | while (1) { 284 | ret = aes_eeprom_read(AES_MEM_ADDR_STATUS, 1, &aes_status); 285 | if (!aes_status && !ret) { 286 | break; 287 | } else if (cnt++ > timeout) { 288 | sprintf(message, "EEPROM read error [status]: %u %i", aes_status, ret); 289 | commander_fill_report("eeprom", message, STATUS_ERROR); 290 | return; 291 | } 292 | delay_ms(delay); 293 | } 294 | } 295 | } 296 | 297 | -------------------------------------------------------------------------------- /src/sd.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | #include "sd.h" 31 | #include "commander.h" 32 | #include "flags.h" 33 | #include "mcu.h" 34 | 35 | uint32_t sd_update = 0; 36 | uint32_t sd_fs_found = 0; 37 | uint32_t sd_listing_pos = 0; 38 | uint32_t sd_num_files = 0; 39 | 40 | static char ROOTDIR[] = "0:/DigitalBitboxFiles"; 41 | 42 | FATFS fs; 43 | 44 | 45 | uint8_t sd_write(const char *f, uint16_t f_len, const char *t, uint16_t t_len, 46 | uint8_t replace) 47 | { 48 | char file[256]; 49 | memset(file, 0, sizeof(file)); 50 | memcpy(file, ROOTDIR, strlen(ROOTDIR)); 51 | strncat(file, "/", 1); 52 | strncat(file, f, (f_len < sizeof(file) - strlen(file)) ? f_len : sizeof(file) - strlen( 53 | file)); 54 | 55 | char text[512] = {0}; 56 | if (t_len > sizeof(text) - 1) { 57 | commander_fill_report("sd_write", FLAG_ERR_SD_WRITE_LEN, STATUS_ERROR); 58 | goto err; 59 | } 60 | 61 | sd_mmc_init(); 62 | sd_listing_pos = 0; 63 | 64 | if (CTRL_FAIL == sd_mmc_test_unit_ready(0)) { 65 | commander_fill_report("sd_write", FLAG_ERR_SD_CARD, STATUS_ERROR); 66 | goto err; 67 | } 68 | 69 | FRESULT res; 70 | FIL file_object; 71 | 72 | memset(&fs, 0, sizeof(FATFS)); 73 | res = f_mount(LUN_ID_SD_MMC_0_MEM, &fs); 74 | if (FR_INVALID_DRIVE == res) { 75 | commander_fill_report("sd_write", FLAG_ERR_SD_MOUNT, STATUS_ERROR); 76 | goto err; 77 | } 78 | 79 | f_mkdir(ROOTDIR); 80 | 81 | res = f_open(&file_object, (char const *)file, 82 | (replace == STATUS_SD_REPLACE ? FA_CREATE_ALWAYS : FA_CREATE_NEW) | FA_WRITE); 83 | if (res != FR_OK) { 84 | commander_fill_report("sd_write", FLAG_ERR_SD_OPEN, STATUS_ERROR); 85 | f_mount(LUN_ID_SD_MMC_0_MEM, NULL); 86 | goto err; 87 | } 88 | 89 | memcpy(text, t, (t_len < sizeof(text) - 1) ? t_len : sizeof(text) - 1); 90 | if (0 == f_puts(text, &file_object)) { 91 | commander_fill_report("sd_write", FLAG_ERR_SD_WRITE, STATUS_ERROR); 92 | f_close(&file_object); 93 | f_mount(LUN_ID_SD_MMC_0_MEM, NULL); 94 | memset(text, 0, sizeof(text)); 95 | goto err; 96 | } 97 | 98 | commander_fill_report("sd_write", "success", STATUS_SUCCESS); 99 | 100 | f_close(&file_object); 101 | f_mount(LUN_ID_SD_MMC_0_MEM, NULL); 102 | memset(text, 0, sizeof(text)); 103 | memset(file, 0, sizeof(file)); 104 | return STATUS_SUCCESS; 105 | 106 | err: 107 | memset(text, 0, sizeof(text)); 108 | memset(file, 0, sizeof(file)); 109 | return STATUS_ERROR; 110 | } 111 | 112 | 113 | char *sd_load(const char *f, uint16_t f_len) 114 | { 115 | FIL file_object; 116 | char file[256]; 117 | memset(file, 0, sizeof(file)); 118 | memcpy(file, ROOTDIR, strlen(ROOTDIR)); 119 | strncat(file, "/", 1); 120 | strncat(file, f, (f_len < sizeof(file) - strlen(file)) ? f_len : sizeof(file) - strlen( 121 | file)); 122 | 123 | static char text[512]; 124 | memset(text, 0, sizeof(text)); 125 | 126 | sd_mmc_init(); 127 | sd_listing_pos = 0; 128 | 129 | if (CTRL_FAIL == sd_mmc_test_unit_ready(0)) { 130 | commander_fill_report("sd_load", FLAG_ERR_SD_CARD, STATUS_ERROR); 131 | goto err; 132 | } 133 | 134 | FRESULT res; 135 | memset(&fs, 0, sizeof(FATFS)); 136 | res = f_mount(LUN_ID_SD_MMC_0_MEM, &fs); 137 | if (FR_INVALID_DRIVE == res) { 138 | commander_fill_report("sd_load", FLAG_ERR_SD_MOUNT, STATUS_ERROR); 139 | goto err; 140 | } 141 | 142 | res = f_open(&file_object, (char const *)file, FA_OPEN_EXISTING | FA_READ); 143 | if (res != FR_OK) { 144 | commander_fill_report("sd_load", FLAG_ERR_SD_OPEN, STATUS_ERROR); 145 | f_mount(LUN_ID_SD_MMC_0_MEM, NULL); 146 | goto err; 147 | } 148 | 149 | UINT text_read; 150 | res = f_read(&file_object, text, file_object.fsize, &text_read); 151 | if (res != FR_OK) { 152 | commander_fill_report("sd_load", FLAG_ERR_SD_READ, STATUS_ERROR); 153 | f_close(&file_object); 154 | f_mount(LUN_ID_SD_MMC_0_MEM, NULL); 155 | goto err; 156 | } 157 | 158 | commander_fill_report("sd_load", "success", STATUS_SUCCESS); 159 | 160 | f_close(&file_object); 161 | f_mount(LUN_ID_SD_MMC_0_MEM, NULL); 162 | memset(file, 0, sizeof(file)); 163 | return text; 164 | 165 | err: 166 | memset(file, 0, sizeof(file)); 167 | return NULL; 168 | } 169 | 170 | 171 | uint8_t sd_list(void) 172 | { 173 | FILINFO fno; 174 | DIR dir; 175 | #if _USE_LFN 176 | char c_lfn[_MAX_LFN + 1]; 177 | fno.lfname = c_lfn; 178 | fno.lfsize = sizeof(c_lfn); 179 | #endif 180 | 181 | char files[1028] = {0}; 182 | size_t f_len = 0; 183 | uint32_t pos = 1; 184 | 185 | 186 | sd_mmc_init(); 187 | sd_listing_pos = 0; 188 | 189 | if (CTRL_FAIL == sd_mmc_test_unit_ready(0)) { 190 | commander_fill_report("sd_list", FLAG_ERR_SD_CARD, STATUS_ERROR); 191 | goto err; 192 | } 193 | 194 | FRESULT res; 195 | memset(&fs, 0, sizeof(FATFS)); 196 | res = f_mount(LUN_ID_SD_MMC_0_MEM, &fs); 197 | if (FR_INVALID_DRIVE == res) { 198 | commander_fill_report("sd_list", FLAG_ERR_SD_MOUNT, STATUS_ERROR); 199 | goto err; 200 | } 201 | 202 | // Open the directory 203 | res = f_opendir(&dir, ROOTDIR); 204 | if (res == FR_OK) { 205 | for (;;) { 206 | char *pc_fn; 207 | res = f_readdir(&dir, &fno); 208 | if (res != FR_OK || fno.fname[0] == 0) { 209 | break; 210 | } 211 | 212 | #if _USE_LFN 213 | pc_fn = *fno.lfname ? fno.lfname : fno.fname; 214 | #else 215 | pc_fn = fno.fname; 216 | #endif 217 | if (*pc_fn == '.' && *(pc_fn + 1) == '\0') { 218 | continue; 219 | } 220 | if (*pc_fn == '.' && *(pc_fn + 1) == '.' && *(pc_fn + 2) == '\0') { 221 | continue; 222 | } 223 | 224 | f_len += strlen(pc_fn) + 2; 225 | if (f_len >= sizeof(files)) { 226 | f_mount(LUN_ID_SD_MMC_0_MEM, NULL); 227 | commander_fill_report("sd_list", FLAG_ERR_NUM_FILES, STATUS_ERROR); 228 | goto err; 229 | } 230 | 231 | if (pos >= sd_listing_pos) { 232 | strcat(files, pc_fn); 233 | strcat(files, ", "); 234 | } 235 | 236 | pos += 1; 237 | } 238 | } else { 239 | commander_fill_report("sd_list debug", "could not open dir", STATUS_ERROR); 240 | } 241 | 242 | commander_fill_report("sd_list", files, STATUS_SUCCESS); 243 | 244 | f_mount(LUN_ID_SD_MMC_0_MEM, NULL); 245 | memset(files, 0, sizeof(files)); 246 | return STATUS_SUCCESS; 247 | 248 | err: 249 | memset(files, 0, sizeof(files)); 250 | return STATUS_ERROR; 251 | 252 | } 253 | 254 | 255 | static uint8_t delete_files(char *path) 256 | { 257 | int failed = 0; 258 | FRESULT res; 259 | FILINFO fno; 260 | DIR dir; 261 | #if _USE_LFN 262 | static char lfn[_MAX_LFN + 1]; 263 | fno.lfname = lfn; 264 | fno.lfsize = sizeof lfn; 265 | #endif 266 | 267 | res = f_opendir(&dir, path); 268 | if (res == FR_OK) { 269 | for (;;) { 270 | 271 | char *pc_fn; 272 | res = f_readdir(&dir, &fno); 273 | if (res != FR_OK) { 274 | failed++; 275 | break; 276 | } 277 | 278 | if (fno.fname[0] == 0) { // no more files or directories 279 | break; 280 | } 281 | 282 | #if _USE_LFN 283 | pc_fn = *fno.lfname ? fno.lfname : fno.fname; 284 | #else 285 | pc_fn = fno.fname; 286 | #endif 287 | if (*pc_fn == '.' && *(pc_fn + 1) == '\0') { 288 | continue; 289 | } 290 | if (*pc_fn == '.' && *(pc_fn + 1) == '.' && *(pc_fn + 2) == '\0') { 291 | continue; 292 | } 293 | 294 | char file[1024]; 295 | snprintf(file, sizeof(file), "%s/%s", path, pc_fn); 296 | 297 | if (fno.fattrib & AM_DIR) { // is a directory 298 | failed += delete_files(file); 299 | } else { // is a file 300 | FIL file_object; 301 | res = f_open(&file_object, (char const *)file, FA_OPEN_EXISTING | FA_WRITE); 302 | if (res != FR_OK) { 303 | failed++; 304 | } else { 305 | DWORD f_ps, fsize = file_object.fsize; 306 | for (f_ps = 0; f_ps < fsize; f_ps++) { 307 | f_putc(0xAC, &file_object); // overwrite data 308 | } 309 | if (f_close(&file_object) != FR_OK) { 310 | failed++; 311 | } 312 | } 313 | } 314 | if (f_unlink(file + 2) != FR_OK) { 315 | failed++; 316 | } 317 | } 318 | } 319 | return failed; 320 | } 321 | 322 | 323 | uint8_t sd_erase(void) 324 | { 325 | int failed = 0; 326 | char *path = ROOTDIR; 327 | 328 | sd_mmc_init(); 329 | sd_listing_pos = 0; 330 | 331 | if (CTRL_FAIL == sd_mmc_test_unit_ready(0)) { 332 | commander_fill_report("sd_erase", FLAG_ERR_SD_CARD, STATUS_ERROR); 333 | return STATUS_ERROR; 334 | } 335 | 336 | FRESULT res; 337 | memset(&fs, 0, sizeof(FATFS)); 338 | res = f_mount(LUN_ID_SD_MMC_0_MEM, &fs); 339 | if (FR_INVALID_DRIVE == res) { 340 | commander_fill_report("sd_erase", FLAG_ERR_SD_MOUNT, STATUS_ERROR); 341 | return STATUS_ERROR; 342 | } 343 | 344 | failed = delete_files(path); 345 | 346 | f_mount(LUN_ID_SD_MMC_0_MEM, NULL); // Unmount 347 | 348 | if (failed) { 349 | commander_fill_report("sd_erase", FLAG_ERR_SD_ERASE, STATUS_ERROR); 350 | return STATUS_ERROR; 351 | } else { 352 | commander_fill_report("sd_erase", "success", STATUS_SUCCESS); 353 | return STATUS_SUCCESS; 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/ripemd160.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ripemd160.h" 4 | 5 | #define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 6 | 7 | #define F(x, y, z) ((x) ^ (y) ^ (z)) 8 | #define G(x, y, z) (((x) & (y)) | (~(x) & (z))) 9 | #define H(x, y, z) (((x) | ~(y)) ^ (z)) 10 | #define IQ(x, y, z) (((x) & (z)) | ((y) & ~(z))) 11 | #define J(x, y, z) ((x) ^ ((y) | ~(z))) 12 | 13 | #define FF(a, b, c, d, e, x, s) {\ 14 | (a) += F((b), (c), (d)) + (x);\ 15 | (a) = ROL((a), (s)) + (e);\ 16 | (c) = ROL((c), 10);\ 17 | } 18 | #define GG(a, b, c, d, e, x, s) {\ 19 | (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ 20 | (a) = ROL((a), (s)) + (e);\ 21 | (c) = ROL((c), 10);\ 22 | } 23 | #define HH(a, b, c, d, e, x, s) {\ 24 | (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ 25 | (a) = ROL((a), (s)) + (e);\ 26 | (c) = ROL((c), 10);\ 27 | } 28 | #define II(a, b, c, d, e, x, s) {\ 29 | (a) += IQ((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ 30 | (a) = ROL((a), (s)) + (e);\ 31 | (c) = ROL((c), 10);\ 32 | } 33 | #define JJ(a, b, c, d, e, x, s) {\ 34 | (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ 35 | (a) = ROL((a), (s)) + (e);\ 36 | (c) = ROL((c), 10);\ 37 | } 38 | #define FFF(a, b, c, d, e, x, s) {\ 39 | (a) += F((b), (c), (d)) + (x);\ 40 | (a) = ROL((a), (s)) + (e);\ 41 | (c) = ROL((c), 10);\ 42 | } 43 | #define GGG(a, b, c, d, e, x, s) {\ 44 | (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ 45 | (a) = ROL((a), (s)) + (e);\ 46 | (c) = ROL((c), 10);\ 47 | } 48 | #define HHH(a, b, c, d, e, x, s) {\ 49 | (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ 50 | (a) = ROL((a), (s)) + (e);\ 51 | (c) = ROL((c), 10);\ 52 | } 53 | #define III(a, b, c, d, e, x, s) {\ 54 | (a) += IQ((b), (c), (d)) + (x) + 0x5c4dd124UL;\ 55 | (a) = ROL((a), (s)) + (e);\ 56 | (c) = ROL((c), 10);\ 57 | } 58 | #define JJJ(a, b, c, d, e, x, s) {\ 59 | (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ 60 | (a) = ROL((a), (s)) + (e);\ 61 | (c) = ROL((c), 10);\ 62 | } 63 | 64 | static void compress(uint32_t *MDbuf, uint32_t *X) 65 | { 66 | uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], dd = MDbuf[3], ee = MDbuf[4]; 67 | uint32_t aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], ddd = MDbuf[3], eee = MDbuf[4]; 68 | 69 | /* round 1 */ 70 | FF(aa, bb, cc, dd, ee, X[ 0], 11); 71 | FF(ee, aa, bb, cc, dd, X[ 1], 14); 72 | FF(dd, ee, aa, bb, cc, X[ 2], 15); 73 | FF(cc, dd, ee, aa, bb, X[ 3], 12); 74 | FF(bb, cc, dd, ee, aa, X[ 4], 5); 75 | FF(aa, bb, cc, dd, ee, X[ 5], 8); 76 | FF(ee, aa, bb, cc, dd, X[ 6], 7); 77 | FF(dd, ee, aa, bb, cc, X[ 7], 9); 78 | FF(cc, dd, ee, aa, bb, X[ 8], 11); 79 | FF(bb, cc, dd, ee, aa, X[ 9], 13); 80 | FF(aa, bb, cc, dd, ee, X[10], 14); 81 | FF(ee, aa, bb, cc, dd, X[11], 15); 82 | FF(dd, ee, aa, bb, cc, X[12], 6); 83 | FF(cc, dd, ee, aa, bb, X[13], 7); 84 | FF(bb, cc, dd, ee, aa, X[14], 9); 85 | FF(aa, bb, cc, dd, ee, X[15], 8); 86 | 87 | /* round 2 */ 88 | GG(ee, aa, bb, cc, dd, X[ 7], 7); 89 | GG(dd, ee, aa, bb, cc, X[ 4], 6); 90 | GG(cc, dd, ee, aa, bb, X[13], 8); 91 | GG(bb, cc, dd, ee, aa, X[ 1], 13); 92 | GG(aa, bb, cc, dd, ee, X[10], 11); 93 | GG(ee, aa, bb, cc, dd, X[ 6], 9); 94 | GG(dd, ee, aa, bb, cc, X[15], 7); 95 | GG(cc, dd, ee, aa, bb, X[ 3], 15); 96 | GG(bb, cc, dd, ee, aa, X[12], 7); 97 | GG(aa, bb, cc, dd, ee, X[ 0], 12); 98 | GG(ee, aa, bb, cc, dd, X[ 9], 15); 99 | GG(dd, ee, aa, bb, cc, X[ 5], 9); 100 | GG(cc, dd, ee, aa, bb, X[ 2], 11); 101 | GG(bb, cc, dd, ee, aa, X[14], 7); 102 | GG(aa, bb, cc, dd, ee, X[11], 13); 103 | GG(ee, aa, bb, cc, dd, X[ 8], 12); 104 | 105 | /* round 3 */ 106 | HH(dd, ee, aa, bb, cc, X[ 3], 11); 107 | HH(cc, dd, ee, aa, bb, X[10], 13); 108 | HH(bb, cc, dd, ee, aa, X[14], 6); 109 | HH(aa, bb, cc, dd, ee, X[ 4], 7); 110 | HH(ee, aa, bb, cc, dd, X[ 9], 14); 111 | HH(dd, ee, aa, bb, cc, X[15], 9); 112 | HH(cc, dd, ee, aa, bb, X[ 8], 13); 113 | HH(bb, cc, dd, ee, aa, X[ 1], 15); 114 | HH(aa, bb, cc, dd, ee, X[ 2], 14); 115 | HH(ee, aa, bb, cc, dd, X[ 7], 8); 116 | HH(dd, ee, aa, bb, cc, X[ 0], 13); 117 | HH(cc, dd, ee, aa, bb, X[ 6], 6); 118 | HH(bb, cc, dd, ee, aa, X[13], 5); 119 | HH(aa, bb, cc, dd, ee, X[11], 12); 120 | HH(ee, aa, bb, cc, dd, X[ 5], 7); 121 | HH(dd, ee, aa, bb, cc, X[12], 5); 122 | 123 | /* round 4 */ 124 | II(cc, dd, ee, aa, bb, X[ 1], 11); 125 | II(bb, cc, dd, ee, aa, X[ 9], 12); 126 | II(aa, bb, cc, dd, ee, X[11], 14); 127 | II(ee, aa, bb, cc, dd, X[10], 15); 128 | II(dd, ee, aa, bb, cc, X[ 0], 14); 129 | II(cc, dd, ee, aa, bb, X[ 8], 15); 130 | II(bb, cc, dd, ee, aa, X[12], 9); 131 | II(aa, bb, cc, dd, ee, X[ 4], 8); 132 | II(ee, aa, bb, cc, dd, X[13], 9); 133 | II(dd, ee, aa, bb, cc, X[ 3], 14); 134 | II(cc, dd, ee, aa, bb, X[ 7], 5); 135 | II(bb, cc, dd, ee, aa, X[15], 6); 136 | II(aa, bb, cc, dd, ee, X[14], 8); 137 | II(ee, aa, bb, cc, dd, X[ 5], 6); 138 | II(dd, ee, aa, bb, cc, X[ 6], 5); 139 | II(cc, dd, ee, aa, bb, X[ 2], 12); 140 | 141 | /* round 5 */ 142 | JJ(bb, cc, dd, ee, aa, X[ 4], 9); 143 | JJ(aa, bb, cc, dd, ee, X[ 0], 15); 144 | JJ(ee, aa, bb, cc, dd, X[ 5], 5); 145 | JJ(dd, ee, aa, bb, cc, X[ 9], 11); 146 | JJ(cc, dd, ee, aa, bb, X[ 7], 6); 147 | JJ(bb, cc, dd, ee, aa, X[12], 8); 148 | JJ(aa, bb, cc, dd, ee, X[ 2], 13); 149 | JJ(ee, aa, bb, cc, dd, X[10], 12); 150 | JJ(dd, ee, aa, bb, cc, X[14], 5); 151 | JJ(cc, dd, ee, aa, bb, X[ 1], 12); 152 | JJ(bb, cc, dd, ee, aa, X[ 3], 13); 153 | JJ(aa, bb, cc, dd, ee, X[ 8], 14); 154 | JJ(ee, aa, bb, cc, dd, X[11], 11); 155 | JJ(dd, ee, aa, bb, cc, X[ 6], 8); 156 | JJ(cc, dd, ee, aa, bb, X[15], 5); 157 | JJ(bb, cc, dd, ee, aa, X[13], 6); 158 | 159 | /* parallel round 1 */ 160 | JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); 161 | JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); 162 | JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); 163 | JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); 164 | JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); 165 | JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); 166 | JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); 167 | JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); 168 | JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); 169 | JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); 170 | JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); 171 | JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); 172 | JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); 173 | JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); 174 | JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); 175 | JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); 176 | 177 | /* parallel round 2 */ 178 | III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); 179 | III(ddd, eee, aaa, bbb, ccc, X[11], 13); 180 | III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); 181 | III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); 182 | III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); 183 | III(eee, aaa, bbb, ccc, ddd, X[13], 8); 184 | III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); 185 | III(ccc, ddd, eee, aaa, bbb, X[10], 11); 186 | III(bbb, ccc, ddd, eee, aaa, X[14], 7); 187 | III(aaa, bbb, ccc, ddd, eee, X[15], 7); 188 | III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); 189 | III(ddd, eee, aaa, bbb, ccc, X[12], 7); 190 | III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); 191 | III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); 192 | III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); 193 | III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); 194 | 195 | /* parallel round 3 */ 196 | HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); 197 | HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); 198 | HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); 199 | HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); 200 | HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); 201 | HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); 202 | HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); 203 | HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); 204 | HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); 205 | HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); 206 | HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); 207 | HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); 208 | HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); 209 | HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); 210 | HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); 211 | HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); 212 | 213 | /* parallel round 4 */ 214 | GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); 215 | GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); 216 | GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); 217 | GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); 218 | GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); 219 | GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); 220 | GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); 221 | GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); 222 | GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); 223 | GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); 224 | GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); 225 | GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); 226 | GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); 227 | GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); 228 | GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); 229 | GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); 230 | 231 | /* parallel round 5 */ 232 | FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); 233 | FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); 234 | FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); 235 | FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); 236 | FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); 237 | FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); 238 | FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); 239 | FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); 240 | FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); 241 | FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); 242 | FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); 243 | FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); 244 | FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); 245 | FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); 246 | FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); 247 | FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); 248 | 249 | /* combine results */ 250 | ddd += cc + MDbuf[1]; 251 | MDbuf[1] = MDbuf[2] + dd + eee; 252 | MDbuf[2] = MDbuf[3] + ee + aaa; 253 | MDbuf[3] = MDbuf[4] + aa + bbb; 254 | MDbuf[4] = MDbuf[0] + bb + ccc; 255 | MDbuf[0] = ddd; 256 | } 257 | 258 | void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t *hash) 259 | { 260 | uint32_t i; 261 | int j; 262 | uint32_t digest[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0UL}; 263 | 264 | for (i = 0; i < (msg_len >> 6); ++i) { 265 | uint32_t chunk[16]; 266 | 267 | for (j = 0; j < 16; ++j) { 268 | chunk[j] = (uint32_t)(*(msg++)); 269 | chunk[j] |= (uint32_t)(*(msg++)) << 8; 270 | chunk[j] |= (uint32_t)(*(msg++)) << 16; 271 | chunk[j] |= (uint32_t)(*(msg++)) << 24; 272 | } 273 | 274 | compress (digest, chunk); 275 | } 276 | 277 | // Last chunk 278 | { 279 | uint32_t chunk[16] = {0}; 280 | 281 | for (i = 0; i < (msg_len & 63); ++i) { 282 | chunk[i >> 2] ^= (uint32_t) * msg++ << ((i & 3) << 3); 283 | } 284 | 285 | chunk[(msg_len >> 2) & 15] ^= (uint32_t)1 << (8 * (msg_len & 3) + 7); 286 | 287 | if ((msg_len & 63) > 55) { 288 | compress (digest, chunk); 289 | memset (chunk, 0, 64); 290 | } 291 | 292 | chunk[14] = msg_len << 3; 293 | chunk[15] = (msg_len >> 29); 294 | compress (digest, chunk); 295 | } 296 | 297 | for (i = 0; i < 5; ++i) { 298 | *(hash++) = digest[i]; 299 | *(hash++) = digest[i] >> 8; 300 | *(hash++) = digest[i] >> 16; 301 | *(hash++) = digest[i] >> 24; 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /src/wallet.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | /* Some functions adapted from the Trezor crypto library. */ 28 | 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "commander.h" 36 | #include "ripemd160.h" 37 | #include "wallet.h" 38 | #include "memory.h" 39 | #include "random.h" 40 | #include "base64.h" 41 | #include "base58.h" 42 | #include "pbkdf2.h" 43 | #include "utils.h" 44 | #include "bip32.h" 45 | #include "flags.h" 46 | #include "hmac.h" 47 | #include "sha2.h" 48 | #include "uECC.h" 49 | #include "led.h" 50 | 51 | #include "bip39_english.h" 52 | 53 | extern const uint8_t MEM_PAGE_ERASE[MEM_PAGE_LEN]; 54 | extern const uint16_t MEM_PAGE_ERASE_2X[MEM_PAGE_LEN]; 55 | 56 | static char mnemonic[(BIP39_MAX_WORD_LEN + 1) * MAX_SEED_WORDS + 1]; 57 | static uint16_t seed_index[MAX_SEED_WORDS]; 58 | static uint8_t seed[64]; 59 | static uint8_t rand_data_32[32]; 60 | 61 | 62 | // Avoid leaving secrets in RAM 63 | static void clear_static_variables(void) 64 | { 65 | memset(seed, 0, sizeof(seed)); 66 | memset(mnemonic, 0, sizeof(mnemonic)); 67 | memset(seed_index, 0, sizeof(seed_index)); 68 | memset(rand_data_32, 0, sizeof(rand_data_32)); 69 | } 70 | 71 | 72 | int wallet_split_seed(char **seed_words, const char *message) 73 | { 74 | int i = 0; 75 | static char msg[(BIP39_MAX_WORD_LEN + 1) * MAX_SEED_WORDS + 1]; 76 | 77 | memset(msg, 0, sizeof(msg)); 78 | snprintf(msg, sizeof(msg), "%s", message); 79 | seed_words[i] = strtok(msg, " ,"); 80 | for (i = 0; seed_words[i] != NULL; i++) { 81 | if (i + 1 >= MAX_SEED_WORDS) { 82 | break; 83 | } 84 | seed_words[i + 1] = strtok(NULL, " ,"); 85 | } 86 | return i; 87 | } 88 | 89 | 90 | const char **wallet_mnemonic_wordlist(void) 91 | { 92 | return wordlist; 93 | } 94 | 95 | 96 | uint16_t *wallet_index_from_mnemonic(const char *mnemo) 97 | { 98 | int i, j, k, seed_words_n; 99 | char *seed_word[MAX_SEED_WORDS] = {NULL}; 100 | memset(seed_index, 0, sizeof(seed_index)); 101 | seed_words_n = wallet_split_seed(seed_word, mnemo); 102 | 103 | k = 0; 104 | for (i = 0; i < seed_words_n; i++) { 105 | if (i >= MAX_SEED_WORDS) { 106 | break; 107 | } 108 | for (j = 0; wordlist[j]; j++) { 109 | if (strcmp(seed_word[i], wordlist[j]) == 0) { // word found 110 | seed_index[k++] = j + 1; // offset of 1 111 | break; 112 | } 113 | } 114 | } 115 | return seed_index; 116 | } 117 | 118 | 119 | char *wallet_mnemonic_from_index(const uint16_t *idx) 120 | { 121 | if (!memcmp(idx, MEM_PAGE_ERASE_2X, 64)) { 122 | return NULL; 123 | } 124 | int i; 125 | memset(mnemonic, 0, sizeof(mnemonic)); 126 | for (i = 0; idx[i]; i++) { 127 | if (i >= MAX_SEED_WORDS || idx[i] > BIP39_NUM_WORDS) { 128 | return NULL; 129 | } 130 | strncat(mnemonic, wordlist[idx[i] - 1], BIP39_MAX_WORD_LEN); 131 | strncat(mnemonic, " ", 1); 132 | } 133 | 134 | if (i == 0 || strlens(mnemonic) < 1) { 135 | return NULL; 136 | } 137 | 138 | mnemonic[strlens(mnemonic) - 1] = '\0'; 139 | return mnemonic; 140 | } 141 | 142 | 143 | int wallet_master_from_mnemonic(char *mnemo, int m_len, const char *salt, int s_len) 144 | { 145 | int ret = STATUS_SUCCESS; 146 | HDNode node; 147 | 148 | clear_static_variables(); 149 | 150 | if (mnemo == NULL) { 151 | if (random_bytes(rand_data_32, 32, 1) == STATUS_ERROR) { 152 | ret = STATUS_ERROR_MEM; 153 | goto exit; 154 | } 155 | mnemo = wallet_mnemonic_from_data(rand_data_32, 32); 156 | memcpy(mnemonic, mnemo, strlens(mnemo)); 157 | } else { 158 | if ((size_t)m_len > sizeof(mnemonic)) { 159 | ret = STATUS_ERROR; 160 | goto exit; 161 | } 162 | snprintf(mnemonic, sizeof(mnemonic), "%.*s", m_len, mnemo); 163 | } 164 | 165 | if (wallet_mnemonic_check(mnemonic) == STATUS_ERROR) { 166 | ret = STATUS_ERROR; 167 | goto exit; 168 | } 169 | 170 | if (salt == NULL || s_len == 0) { 171 | wallet_mnemonic_to_seed(mnemonic, NULL, seed, 0); 172 | } else { 173 | wallet_mnemonic_to_seed(mnemonic, salt, seed, 0); 174 | } 175 | 176 | if (hdnode_from_seed(seed, sizeof(seed), &node) == STATUS_ERROR) { 177 | ret = STATUS_ERROR; 178 | goto exit; 179 | } 180 | 181 | if (!memcmp(memory_master(node.private_key), MEM_PAGE_ERASE, 32) || 182 | !memcmp(memory_chaincode(node.chain_code), MEM_PAGE_ERASE, 32) || 183 | !memcmp(memory_mnemonic(wallet_index_from_mnemonic(mnemonic)), MEM_PAGE_ERASE_2X, 64)) { 184 | ret = STATUS_ERROR_MEM; 185 | goto exit; 186 | } else { 187 | ret = STATUS_SUCCESS; 188 | goto exit; 189 | } 190 | 191 | exit: 192 | memset(&node, 0, sizeof(HDNode)); 193 | clear_static_variables(); 194 | return ret; 195 | } 196 | 197 | 198 | int wallet_generate_key(HDNode *node, const char *keypath, int keypath_len, 199 | const uint8_t *privkeymaster, const uint8_t *chaincode) 200 | { 201 | unsigned long idx = 0; 202 | char *pch, *kp = malloc(keypath_len + 1); 203 | 204 | if (!kp) { 205 | return STATUS_ERROR_MEM; 206 | } 207 | 208 | memcpy(kp, keypath, keypath_len); 209 | kp[keypath_len] = '\0'; 210 | 211 | node->depth = 0; 212 | node->child_num = 0; 213 | node->fingerprint = 0; 214 | memcpy(node->chain_code, chaincode, 32); 215 | memcpy(node->private_key, privkeymaster, 32); 216 | hdnode_fill_public_key(node); 217 | 218 | pch = strtok(kp, " /,m\\"); 219 | while (pch != NULL) { 220 | sscanf(pch, "%lu", &idx); 221 | if (pch[strlens(pch) - 1] == '\'' || 222 | pch[strlens(pch) - 1] == 'p' || 223 | pch[strlens(pch) - 1] == 'h' || 224 | pch[strlens(pch) - 1] == 'H') { 225 | if (hdnode_private_ckd_prime(node, idx) != STATUS_SUCCESS) { 226 | goto err; 227 | } 228 | } else { 229 | if (hdnode_private_ckd(node, idx) != STATUS_SUCCESS) { 230 | goto err; 231 | } 232 | } 233 | pch = strtok(NULL, " /,m\\"); 234 | } 235 | free(kp); 236 | return STATUS_SUCCESS; 237 | 238 | err: 239 | free(kp); 240 | return STATUS_ERROR; 241 | } 242 | 243 | 244 | void wallet_report_xpub(const char *keypath, int keypath_len, char *xpub) 245 | { 246 | uint8_t *priv_key_master = memory_master(NULL); 247 | uint8_t *chain_code = memory_chaincode(NULL); 248 | HDNode node; 249 | 250 | if (memcmp(priv_key_master, MEM_PAGE_ERASE, 32) && 251 | memcmp(chain_code, MEM_PAGE_ERASE, 32)) { 252 | if (wallet_generate_key(&node, keypath, keypath_len, priv_key_master, 253 | chain_code) == STATUS_SUCCESS) { 254 | hdnode_serialize_public(&node, xpub, 112); 255 | } 256 | } 257 | memset(&node, 0, sizeof(HDNode)); 258 | clear_static_variables(); 259 | } 260 | 261 | 262 | int wallet_check_pubkey(const char *pubkeyhash, const char *keypath, int keypath_len) 263 | { 264 | uint8_t *priv_key_master = memory_master(NULL); 265 | uint8_t *chain_code = memory_chaincode(NULL); 266 | uint8_t pub_key[33]; 267 | HDNode node; 268 | 269 | if (strlens(pubkeyhash) != (20 * 2)) { 270 | commander_clear_report(); 271 | commander_fill_report("checkkey", FLAG_ERR_PKH_LEN, STATUS_ERROR); 272 | goto err; 273 | } 274 | 275 | if (!memcmp(priv_key_master, MEM_PAGE_ERASE, 32) || 276 | !memcmp(chain_code, MEM_PAGE_ERASE, 32)) { 277 | commander_clear_report(); 278 | commander_fill_report("checkkey", FLAG_ERR_BIP32_MISSING, STATUS_ERROR); 279 | goto err; 280 | } 281 | 282 | if (wallet_generate_key(&node, keypath, keypath_len, priv_key_master, 283 | chain_code) != STATUS_SUCCESS) { 284 | commander_clear_report(); 285 | commander_fill_report("checkkey", FLAG_ERR_KEY_GEN, STATUS_ERROR); 286 | goto err; 287 | } 288 | 289 | uECC_get_public_key33(node.private_key, pub_key); 290 | 291 | uint8_t pub_key_hash[21]; 292 | char address[36]; 293 | char pHex[67]; 294 | wallet_get_address_raw(pub_key, 0, pub_key_hash); 295 | wallet_get_address(pub_key, 0, address, sizeof(address)); 296 | 297 | memcpy(pHex, utils_uint8_to_hex(pub_key, 66), 66); 298 | memset(&node, 0, sizeof(HDNode)); 299 | clear_static_variables(); 300 | if (memcmp(pubkeyhash, utils_uint8_to_hex(pub_key_hash + 1, 20), 40)) { 301 | return STATUS_KEY_ABSENT; 302 | } else { 303 | return STATUS_KEY_PRESENT; 304 | } 305 | 306 | err: 307 | memset(&node, 0, sizeof(HDNode)); 308 | clear_static_variables(); 309 | return STATUS_ERROR; 310 | } 311 | 312 | 313 | int wallet_sign(const char *message, int msg_len, const char *keypath, int keypath_len) 314 | { 315 | uint8_t data[32]; 316 | uint8_t sig[64]; 317 | uint8_t *priv_key_master = memory_master(NULL); 318 | uint8_t *chain_code = memory_chaincode(NULL); 319 | uint8_t pub_key[33]; 320 | HDNode node; 321 | 322 | if (msg_len != (32 * 2)) { 323 | commander_clear_report(); 324 | commander_fill_report("sign", FLAG_ERR_SIGN_LEN, STATUS_ERROR); 325 | goto err; 326 | } 327 | 328 | if (!memcmp(priv_key_master, MEM_PAGE_ERASE, 32) || 329 | !memcmp(chain_code, MEM_PAGE_ERASE, 32)) { 330 | commander_clear_report(); 331 | commander_fill_report("sign", FLAG_ERR_BIP32_MISSING, STATUS_ERROR); 332 | goto err; 333 | } 334 | 335 | if (wallet_generate_key(&node, keypath, keypath_len, priv_key_master, 336 | chain_code) != STATUS_SUCCESS) { 337 | commander_clear_report(); 338 | commander_fill_report("sign", FLAG_ERR_KEY_GEN, STATUS_ERROR); 339 | goto err; 340 | } 341 | 342 | memcpy(data, utils_hex_to_uint8(message), 32); 343 | int ret = uECC_sign_digest(node.private_key, data, sig); 344 | if (ret) { 345 | commander_clear_report(); 346 | commander_fill_report("sign", FLAG_ERR_SIGN, STATUS_ERROR); 347 | goto err; 348 | } 349 | 350 | uECC_get_public_key33(node.private_key, pub_key); 351 | memset(&node, 0, sizeof(HDNode)); 352 | clear_static_variables(); 353 | return commander_fill_signature(sig, pub_key); 354 | 355 | err: 356 | memset(&node, 0, sizeof(HDNode)); 357 | clear_static_variables(); 358 | return STATUS_ERROR; 359 | } 360 | 361 | 362 | char *wallet_mnemonic_from_data(const uint8_t *data, int len) 363 | { 364 | if (len % 4 || len < 16 || len > 32) { 365 | return 0; 366 | } 367 | 368 | uint8_t bits[32 + 1]; 369 | 370 | sha256_Raw(data, len, bits); 371 | bits[len] = bits[0]; 372 | memcpy(bits, data, len); 373 | 374 | int mlen = len * 3 / 4; 375 | static char mnemo[24 * 10]; 376 | 377 | int i, j; 378 | char *p = mnemo; 379 | for (i = 0; i < mlen; i++) { 380 | int idx = 0; 381 | for (j = 0; j < 11; j++) { 382 | idx <<= 1; 383 | idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0; 384 | } 385 | strcpy(p, wordlist[idx]); 386 | p += strlens(wordlist[idx]); 387 | *p = (i < mlen - 1) ? ' ' : 0; 388 | p++; 389 | } 390 | 391 | return mnemo; 392 | } 393 | 394 | 395 | int wallet_mnemonic_check(const char *mnemo) 396 | { 397 | uint32_t i, j, k, ki, bi, n; 398 | int chksum = 0; 399 | char *sham[MAX_SEED_WORDS] = {NULL}; 400 | char current_word[10]; 401 | uint8_t bits[32 + 1]; 402 | 403 | if (!mnemo) { 404 | //commander_fill_report("seed", FLAG_ERR_MNEMO_EMPTY, ERROR); 405 | return STATUS_ERROR; 406 | } 407 | 408 | // check number of words 409 | n = wallet_split_seed(sham, mnemo); 410 | memset(sham, 0, sizeof(sham)); 411 | 412 | if (n != 12 && n != 18 && n != 24) { 413 | //commander_fill_report("seed", FLAG_ERR_MNEMO_NUM_WORDS, ERROR); 414 | return STATUS_ERROR; 415 | } 416 | 417 | memset(bits, 0, sizeof(bits)); 418 | i = 0; 419 | bi = 0; 420 | while (mnemo[i]) { 421 | j = 0; 422 | while (mnemo[i] != ' ' && mnemo[i] != 0) { 423 | if (j >= sizeof(current_word)) { 424 | //commander_fill_report("seed", FLAG_ERR_MNEMO_WORD, ERROR); 425 | return STATUS_ERROR; 426 | } 427 | current_word[j] = mnemo[i]; 428 | i++; 429 | j++; 430 | } 431 | current_word[j] = 0; 432 | if (mnemo[i] != 0) { 433 | i++; 434 | } 435 | k = 0; 436 | for (;;) { 437 | if (!wordlist[k]) { // word not found 438 | //commander_fill_report("seed", FLAG_ERR_MNEMO_WORD, ERROR); 439 | return STATUS_ERROR; 440 | } 441 | if (strcmp(current_word, wordlist[k]) == 0) { // word found on index k 442 | for (ki = 0; ki < 11; ki++) { 443 | if (k & (1 << (10 - ki))) { 444 | bits[bi / 8] |= 1 << (7 - (bi % 8)); 445 | } 446 | bi++; 447 | } 448 | break; 449 | } 450 | k++; 451 | } 452 | } 453 | if (bi != n * 11) { 454 | //commander_fill_report("seed", FLAG_ERR_MNEMO_CHECK, ERROR); 455 | return STATUS_ERROR; 456 | } 457 | bits[32] = bits[n * 4 / 3]; 458 | sha256_Raw(bits, n * 4 / 3, bits); 459 | if (n == 12) { 460 | chksum = (bits[0] & 0xF0) == (bits[32] & 0xF0); // compare first 4 bits 461 | } else if (n == 18) { 462 | chksum = (bits[0] & 0xFC) == (bits[32] & 0xFC); // compare first 6 bits 463 | } else if (n == 24) { 464 | chksum = bits[0] == bits[32]; // compare 8 bits 465 | } 466 | 467 | if (!chksum) { 468 | //commander_fill_report("seed", FLAG_ERR_MNEMO_CHECKSUM, ERROR); 469 | return STATUS_ERROR; 470 | } 471 | 472 | return STATUS_SUCCESS; 473 | } 474 | 475 | 476 | void wallet_mnemonic_to_seed(const char *mnemo, const char *passphrase, 477 | uint8_t s[512 / 8], 478 | void (*progress_callback)(uint32_t current, uint32_t total)) 479 | { 480 | static uint8_t salt[8 + SALT_LEN_MAX + 4]; 481 | int saltlen = 0; 482 | memset(salt, 0, sizeof(salt)); 483 | memcpy(salt, "mnemonic", 8); 484 | if (passphrase) { 485 | saltlen = strlens(passphrase); 486 | //memcpy(salt + 8, passphrase, saltlen); 487 | snprintf((char *)salt + 8, SALT_LEN_MAX, "%s", passphrase); 488 | } 489 | saltlen += 8; 490 | pbkdf2_hmac_sha512((const uint8_t *)mnemo, strlens(mnemo), salt, saltlen, 491 | BIP39_PBKDF2_ROUNDS, s, 512 / 8, progress_callback); 492 | } 493 | 494 | 495 | // -- bitcoin formats -- // 496 | // from: github.com/trezor/trezor-crypto 497 | 498 | void wallet_get_pubkeyhash(const uint8_t *pub_key, uint8_t *pubkeyhash) 499 | { 500 | uint8_t h[32]; 501 | if (pub_key[0] == 0x04) { // uncompressed format 502 | sha256_Raw(pub_key, 65, h); 503 | } else if (pub_key[0] == 0x00) { // point at infinity 504 | sha256_Raw(pub_key, 1, h); 505 | } else { 506 | sha256_Raw(pub_key, 33, h); // expecting compressed format 507 | } 508 | ripemd160(h, 32, pubkeyhash); 509 | } 510 | 511 | void wallet_get_address_raw(const uint8_t *pub_key, uint8_t version, uint8_t *addr_raw) 512 | { 513 | addr_raw[0] = version; 514 | wallet_get_pubkeyhash(pub_key, addr_raw + 1); 515 | } 516 | 517 | void wallet_get_address(const uint8_t *pub_key, uint8_t version, char *addr, int addrsize) 518 | { 519 | uint8_t raw[21]; 520 | wallet_get_address_raw(pub_key, version, raw); 521 | base58_encode_check(raw, 21, addr, addrsize); 522 | } 523 | 524 | void wallet_get_wif(const uint8_t *priv_key, uint8_t version, char *wif, int wifsize) 525 | { 526 | uint8_t data[34]; 527 | data[0] = version; 528 | memcpy(data + 1, priv_key, 32); 529 | data[33] = 0x01; 530 | base58_encode_check(data, 34, wif, wifsize); 531 | } 532 | 533 | -------------------------------------------------------------------------------- /src/memory.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Douglas J. Bakkum 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 21 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | 31 | #include "commander.h" 32 | #include "random.h" 33 | #include "memory.h" 34 | #include "utils.h" 35 | #include "flags.h" 36 | #include "sha2.h" 37 | #ifndef TESTING 38 | #include "ataes132.h" 39 | #include 40 | #include 41 | #include 42 | #endif 43 | 44 | 45 | static uint8_t MEM_unlocked_ = DEFAULT_unlocked_; 46 | static uint8_t MEM_erased_ = DEFAULT_erased_; 47 | static uint8_t MEM_setup_ = DEFAULT_setup_; 48 | static uint16_t MEM_access_err_ = DEFAULT_access_err_; 49 | static uint16_t MEM_touch_thresh_ = DEFAULT_touch_thresh_; 50 | static uint16_t MEM_touch_timeout_ = DEFAULT_touch_timeout_; 51 | 52 | __extension__ static uint8_t MEM_aeskey_2FA_[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFF}; 53 | __extension__ static uint8_t MEM_aeskey_stand_[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFF}; 54 | __extension__ static uint8_t MEM_aeskey_crypt_[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFF}; 55 | __extension__ static uint8_t MEM_aeskey_verify_[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFF}; 56 | __extension__ static uint8_t MEM_aeskey_memory_[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFF}; 57 | __extension__ static uint8_t MEM_name_[] = {[0 ... MEM_PAGE_LEN - 1] = '0'}; 58 | __extension__ static uint8_t MEM_master_[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFF}; 59 | __extension__ static uint8_t MEM_master_chain_[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFF}; 60 | __extension__ static uint16_t MEM_mnemonic_[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFFFF}; 61 | 62 | __extension__ const uint8_t MEM_PAGE_ERASE[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFF}; 63 | __extension__ const uint16_t MEM_PAGE_ERASE_2X[] = {[0 ... MEM_PAGE_LEN - 1] = 0xFFFF}; 64 | 65 | 66 | // One-time setup on factory install 67 | void memory_setup(void) 68 | { 69 | if (memory_read_setup()) { 70 | memory_erase(); 71 | #ifndef TESTING 72 | // Lock Config Memory: OP MODE PARAMETER1 PARAMETER2 73 | const uint8_t ataes_cmd[] = {0x0D, 0x02, 0x00, 0x00, 0x00, 0x00}; 74 | // Return packet [Count(1) || Return Code (1) || CRC (2)] 75 | uint8_t ataes_ret[4] = {0}; 76 | aes_process(ataes_cmd, sizeof(ataes_cmd), ataes_ret, 4); 77 | #endif 78 | memory_write_setup(0x00); 79 | } else { 80 | memory_mempass(); 81 | } 82 | } 83 | 84 | 85 | void memory_erase_seed(void) 86 | { 87 | memory_mnemonic(MEM_PAGE_ERASE_2X); 88 | memory_chaincode(MEM_PAGE_ERASE); 89 | memory_master(MEM_PAGE_ERASE); 90 | } 91 | 92 | 93 | void memory_erase(void) 94 | { 95 | memory_mempass(); 96 | memory_write_aeskey((const char *)MEM_PAGE_ERASE, MEM_PAGE_LEN, PASSWORD_STAND); 97 | memory_write_aeskey((const char *)MEM_PAGE_ERASE, MEM_PAGE_LEN, PASSWORD_CRYPT); 98 | memory_erase_seed(); 99 | memory_name("Digital Bitbox"); 100 | memory_write_erased(DEFAULT_erased_); 101 | memory_write_unlocked(DEFAULT_unlocked_); 102 | memory_write_touch_timeout(DEFAULT_touch_timeout_); 103 | memory_write_touch_thresh(DEFAULT_touch_thresh_); 104 | memory_access_err_count(DEFAULT_access_err_); 105 | commander_create_verifypass(); 106 | } 107 | 108 | 109 | void memory_clear_variables(void) 110 | { 111 | #ifndef TESTING 112 | // Zero important variables in RAM on embedded MCU. 113 | // Do not clear for testing routines (i.e. not embedded). 114 | memcpy(MEM_name_, MEM_PAGE_ERASE, MEM_PAGE_LEN); 115 | memcpy(MEM_aeskey_stand_, MEM_PAGE_ERASE, MEM_PAGE_LEN); 116 | memcpy(MEM_aeskey_crypt_, MEM_PAGE_ERASE, MEM_PAGE_LEN); 117 | memcpy(MEM_aeskey_verify_, MEM_PAGE_ERASE, MEM_PAGE_LEN); 118 | memcpy(MEM_master_, MEM_PAGE_ERASE, MEM_PAGE_LEN); 119 | memcpy(MEM_master_chain_, MEM_PAGE_ERASE, MEM_PAGE_LEN); 120 | memcpy(MEM_mnemonic_, MEM_PAGE_ERASE_2X, MEM_PAGE_LEN * 2); 121 | #endif 122 | } 123 | 124 | 125 | static int memory_eeprom(const uint8_t *write_b, uint8_t *read_b, const int32_t addr, 126 | const uint16_t len) 127 | { 128 | #ifndef TESTING 129 | // read current memory 130 | aes_eeprom(len, addr, read_b, NULL); 131 | #endif 132 | if (write_b) { 133 | #ifndef TESTING 134 | // skip writing if memory does not change 135 | if (read_b) { 136 | if (!memcmp(read_b, write_b, len)) { 137 | return STATUS_SUCCESS; 138 | } 139 | } 140 | aes_eeprom(len, addr, read_b, write_b); 141 | if (read_b) { 142 | if (!memcmp(write_b, read_b, len)) { 143 | return STATUS_SUCCESS; 144 | } else { 145 | // error 146 | if (len > 2) { 147 | memcpy(read_b, MEM_PAGE_ERASE, len); 148 | } 149 | return STATUS_ERROR; 150 | } 151 | } 152 | #else 153 | memcpy(read_b, write_b, len); 154 | (void) addr; 155 | return STATUS_SUCCESS; 156 | #endif 157 | } 158 | return STATUS_SUCCESS; 159 | } 160 | 161 | 162 | // Encrypted storage 163 | static int memory_eeprom_crypt(const uint8_t *write_b, uint8_t *read_b, 164 | const int32_t addr) 165 | { 166 | int enc_len, dec_len; 167 | char *enc, *dec, enc_r[MEM_PAGE_LEN * 4 + 1] = {0}; 168 | if (read_b) { 169 | enc = aes_cbc_b64_encrypt((unsigned char *)utils_uint8_to_hex(read_b, MEM_PAGE_LEN), 170 | MEM_PAGE_LEN * 2, &enc_len, PASSWORD_MEMORY); 171 | if (!enc) { 172 | goto err; 173 | } 174 | memcpy(enc_r, enc, enc_len); 175 | free(enc); 176 | } 177 | 178 | if (write_b) { 179 | char enc_w[MEM_PAGE_LEN * 4 + 1] = {0}; 180 | enc = aes_cbc_b64_encrypt((unsigned char *)utils_uint8_to_hex(write_b, MEM_PAGE_LEN), 181 | MEM_PAGE_LEN * 2, &enc_len, PASSWORD_MEMORY); 182 | if (!enc) { 183 | goto err; 184 | } 185 | memcpy(enc_w, enc, enc_len); 186 | free(enc); 187 | if (memory_eeprom((uint8_t *)enc_w, (uint8_t *)enc_r, addr, 188 | MEM_PAGE_LEN) == STATUS_ERROR) { 189 | goto err; 190 | } 191 | if (memory_eeprom((uint8_t *)enc_w + MEM_PAGE_LEN, (uint8_t *)enc_r + MEM_PAGE_LEN, 192 | addr + MEM_PAGE_LEN, MEM_PAGE_LEN) == STATUS_ERROR) { 193 | goto err; 194 | } 195 | if (memory_eeprom((uint8_t *)enc_w + MEM_PAGE_LEN * 2, 196 | (uint8_t *)enc_r + MEM_PAGE_LEN * 2, addr + MEM_PAGE_LEN * 2, 197 | MEM_PAGE_LEN) == STATUS_ERROR) { 198 | goto err; 199 | } 200 | if (memory_eeprom((uint8_t *)enc_w + MEM_PAGE_LEN * 3, 201 | (uint8_t *)enc_r + MEM_PAGE_LEN * 3, addr + MEM_PAGE_LEN * 3, 202 | MEM_PAGE_LEN) == STATUS_ERROR) { 203 | goto err; 204 | } 205 | } else { 206 | if (memory_eeprom(NULL, (uint8_t *)enc_r, addr, MEM_PAGE_LEN) == STATUS_ERROR) { 207 | goto err; 208 | } 209 | if (memory_eeprom(NULL, (uint8_t *)enc_r + MEM_PAGE_LEN, addr + MEM_PAGE_LEN, 210 | MEM_PAGE_LEN) == STATUS_ERROR) { 211 | goto err; 212 | } 213 | if (memory_eeprom(NULL, (uint8_t *)enc_r + MEM_PAGE_LEN * 2, addr + MEM_PAGE_LEN * 2, 214 | MEM_PAGE_LEN) == STATUS_ERROR) { 215 | goto err; 216 | } 217 | if (memory_eeprom(NULL, (uint8_t *)enc_r + MEM_PAGE_LEN * 3, addr + MEM_PAGE_LEN * 3, 218 | MEM_PAGE_LEN) == STATUS_ERROR) { 219 | goto err; 220 | } 221 | } 222 | 223 | dec = aes_cbc_b64_decrypt((unsigned char *)enc_r, MEM_PAGE_LEN * 4, &dec_len, 224 | PASSWORD_MEMORY); 225 | if (!dec) { 226 | goto err; 227 | } 228 | memcpy(read_b, utils_hex_to_uint8(dec), MEM_PAGE_LEN); 229 | memset(dec, 0, dec_len); 230 | free(dec); 231 | 232 | utils_clear_buffers(); 233 | return STATUS_SUCCESS; 234 | err: 235 | utils_clear_buffers(); 236 | return STATUS_ERROR; 237 | } 238 | 239 | 240 | void memory_mempass(void) 241 | { 242 | uint8_t mempass[88] = {0}; 243 | #ifndef TESTING 244 | // Encrypt data saved to memory using an AES key obfuscated by the 245 | // compilation time and date, which is used to 'randomly' read bytes 246 | // (i.e. the AES key) from the MCU code in flash memory. 247 | uint8_t *mp = mempass; 248 | int r[8] = {0}; 249 | char c[3] = {0}; 250 | sscanf(__TIME__, "%d:%d:%d", &r[0], &r[1], &r[2]); 251 | sscanf(__DATE__, "%c%c%c %d ", &c[0], &c[1], &c[2], &r[3]); 252 | r[7] = __LINE__ % 1028; 253 | r[4] = c[0]; 254 | r[5] = c[1]; 255 | r[6] = c[2]; 256 | memcpy(mp + 0, (uint32_t *)IFLASH0_ADDR + r[0] * r[0], 8); 257 | memcpy(mp + 8, (uint32_t *)IFLASH0_ADDR + r[0] * r[1], 8); 258 | memcpy(mp + 16, (uint32_t *)IFLASH0_ADDR + r[0] * r[2], 8); 259 | memcpy(mp + 24, (uint32_t *)IFLASH0_ADDR + r[1] * r[1], 8); 260 | memcpy(mp + 32, (uint32_t *)IFLASH0_ADDR + r[1] * r[2], 8); 261 | memcpy(mp + 40, (uint32_t *)IFLASH0_ADDR + r[2] * r[2], 8); 262 | memcpy(mp + 48, (uint32_t *)IFLASH0_ADDR + r[0] * r[3], 8); 263 | memcpy(mp + 56, (uint32_t *)IFLASH0_ADDR + r[0] * r[4], 8); 264 | memcpy(mp + 64, (uint32_t *)IFLASH0_ADDR + r[0] * r[5], 8); 265 | memcpy(mp + 72, (uint32_t *)IFLASH0_ADDR + r[0] * r[6], 8); 266 | memcpy(mp + 80, (uint32_t *)IFLASH0_ADDR + r[2] + r[7], 8); 267 | #endif 268 | memory_write_aeskey(utils_uint8_to_hex(mempass, sizeof(mempass)), sizeof(mempass) * 2, 269 | PASSWORD_MEMORY); 270 | memset(mempass, 0, sizeof(mempass)); 271 | utils_clear_buffers(); 272 | } 273 | 274 | 275 | uint8_t *memory_name(const char *name) 276 | { 277 | uint8_t name_b[MEM_PAGE_LEN] = {0}; 278 | if (strlen(name)) { 279 | memcpy(name_b, name, (strlen(name) > MEM_PAGE_LEN) ? MEM_PAGE_LEN : strlen(name)); 280 | memory_eeprom(name_b, MEM_name_, MEM_NAME_ADDR, MEM_PAGE_LEN); 281 | } else { 282 | memory_eeprom(NULL, MEM_name_, MEM_NAME_ADDR, MEM_PAGE_LEN); 283 | } 284 | return MEM_name_; 285 | } 286 | 287 | 288 | uint8_t *memory_master(const uint8_t *master) 289 | { 290 | memory_eeprom_crypt(master, MEM_master_, MEM_MASTER_BIP32_ADDR); 291 | return MEM_master_; 292 | } 293 | 294 | 295 | uint8_t *memory_chaincode(const uint8_t *chain) 296 | { 297 | memory_eeprom_crypt(chain, MEM_master_chain_, MEM_MASTER_BIP32_CHAIN_ADDR); 298 | return MEM_master_chain_; 299 | } 300 | 301 | 302 | uint16_t *memory_mnemonic(const uint16_t *idx) 303 | { 304 | if (idx) { 305 | memory_eeprom_crypt((const uint8_t *)idx, (uint8_t *)MEM_mnemonic_, 306 | MEM_MNEMONIC_BIP32_ADDR_0); 307 | memory_eeprom_crypt((const uint8_t *)idx + MEM_PAGE_LEN, 308 | (uint8_t *)MEM_mnemonic_ + MEM_PAGE_LEN, 309 | MEM_MNEMONIC_BIP32_ADDR_1); 310 | } else { 311 | memory_eeprom_crypt(NULL, (uint8_t *)MEM_mnemonic_, 312 | MEM_MNEMONIC_BIP32_ADDR_0); 313 | memory_eeprom_crypt(NULL, (uint8_t *)MEM_mnemonic_ + MEM_PAGE_LEN, 314 | MEM_MNEMONIC_BIP32_ADDR_1); 315 | } 316 | return MEM_mnemonic_; 317 | } 318 | 319 | 320 | int memory_aeskey_is_erased(PASSWORD_ID id) 321 | { 322 | uint8_t mem_aeskey_erased[MEM_PAGE_LEN]; 323 | sha256_Raw((const uint8_t *)MEM_PAGE_ERASE, MEM_PAGE_LEN, mem_aeskey_erased); 324 | sha256_Raw(mem_aeskey_erased, MEM_PAGE_LEN, mem_aeskey_erased); 325 | 326 | if (memcmp(memory_read_aeskey(id), mem_aeskey_erased, 32)) { 327 | return STATUS_MEM_NOT_ERASED; 328 | } else { 329 | return STATUS_MEM_ERASED; 330 | } 331 | } 332 | 333 | 334 | int memory_write_aeskey(const char *password, int len, PASSWORD_ID id) 335 | { 336 | int ret = 0; 337 | uint8_t password_b[MEM_PAGE_LEN]; 338 | memset(password_b, 0, MEM_PAGE_LEN); 339 | 340 | 341 | if (!password) { 342 | commander_fill_report("password", FLAG_ERR_PASSWORD_LEN, STATUS_ERROR); 343 | return STATUS_ERROR; 344 | } 345 | 346 | if (len < PASSWORD_LEN_MIN) { 347 | commander_fill_report("password", FLAG_ERR_PASSWORD_LEN, STATUS_ERROR); 348 | return STATUS_ERROR; 349 | } 350 | 351 | if (strlen(password) < PASSWORD_LEN_MIN) { 352 | commander_fill_report("password", FLAG_ERR_PASSWORD_LEN, STATUS_ERROR); 353 | return STATUS_ERROR; 354 | } 355 | 356 | sha256_Raw((const uint8_t *)password, len, password_b); 357 | sha256_Raw(password_b, MEM_PAGE_LEN, password_b); 358 | 359 | switch ((int)id) { 360 | case PASSWORD_MEMORY: 361 | memcpy(MEM_aeskey_memory_, password_b, MEM_PAGE_LEN); 362 | ret = STATUS_SUCCESS; 363 | break; 364 | case PASSWORD_2FA: 365 | memcpy(MEM_aeskey_2FA_, password_b, MEM_PAGE_LEN); 366 | ret = STATUS_SUCCESS; 367 | break; 368 | case PASSWORD_STAND: 369 | ret = memory_eeprom_crypt(password_b, MEM_aeskey_stand_, MEM_AESKEY_STAND_ADDR); 370 | break; 371 | case PASSWORD_CRYPT: 372 | ret = memory_eeprom_crypt(password_b, MEM_aeskey_crypt_, MEM_AESKEY_CRYPT_ADDR); 373 | break; 374 | case PASSWORD_VERIFY: 375 | ret = memory_eeprom_crypt(password_b, MEM_aeskey_verify_, MEM_AESKEY_VERIFY_ADDR); 376 | break; 377 | default: 378 | memset(password_b, 0, MEM_PAGE_LEN); 379 | commander_fill_report("password", FLAG_ERR_PASSWORD_ID, STATUS_ERROR); 380 | return STATUS_ERROR; 381 | } 382 | 383 | memset(password_b, 0, MEM_PAGE_LEN); 384 | if (ret == STATUS_SUCCESS) { 385 | return STATUS_SUCCESS; 386 | } else { 387 | commander_fill_report("password", FLAG_ERR_ATAES, STATUS_ERROR); 388 | return STATUS_ERROR; 389 | } 390 | } 391 | 392 | uint8_t *memory_read_aeskey(PASSWORD_ID id) 393 | { 394 | switch ((int)id) { 395 | case PASSWORD_MEMORY: 396 | return MEM_aeskey_memory_; 397 | case PASSWORD_2FA: 398 | return MEM_aeskey_2FA_; 399 | case PASSWORD_STAND: 400 | memory_eeprom_crypt(NULL, MEM_aeskey_stand_, MEM_AESKEY_STAND_ADDR); 401 | return MEM_aeskey_stand_; 402 | case PASSWORD_CRYPT: 403 | memory_eeprom_crypt(NULL, MEM_aeskey_crypt_, MEM_AESKEY_CRYPT_ADDR); 404 | return MEM_aeskey_crypt_; 405 | case PASSWORD_VERIFY: 406 | memory_eeprom_crypt(NULL, MEM_aeskey_verify_, MEM_AESKEY_VERIFY_ADDR); 407 | return MEM_aeskey_verify_; 408 | default: 409 | return 0; 410 | } 411 | } 412 | 413 | 414 | void memory_write_setup(const uint8_t setup) 415 | { 416 | memory_eeprom(&setup, &MEM_setup_, MEM_SETUP_ADDR, 1); 417 | } 418 | uint8_t memory_read_setup(void) 419 | { 420 | memory_eeprom(NULL, &MEM_setup_, MEM_SETUP_ADDR, 1); 421 | return MEM_setup_; 422 | } 423 | 424 | 425 | void memory_write_unlocked(const uint8_t u) 426 | { 427 | memory_eeprom(&u, &MEM_unlocked_, MEM_UNLOCKED_ADDR, 1); 428 | } 429 | uint8_t memory_read_unlocked(void) 430 | { 431 | memory_eeprom(NULL, &MEM_unlocked_, MEM_UNLOCKED_ADDR, 1); 432 | return MEM_unlocked_; 433 | } 434 | 435 | 436 | void memory_write_erased(const uint8_t erased) 437 | { 438 | memory_eeprom(&erased, &MEM_erased_, MEM_ERASED_ADDR, 1); 439 | } 440 | uint8_t memory_read_erased(void) 441 | { 442 | memory_eeprom(NULL, &MEM_erased_, MEM_ERASED_ADDR, 1); 443 | return MEM_erased_; 444 | } 445 | 446 | 447 | void memory_write_touch_timeout(const uint16_t t) 448 | { 449 | memory_eeprom((const uint8_t *)&t, (uint8_t *)&MEM_touch_timeout_, MEM_TOUCH_TIMEOUT_ADDR, 450 | 2); 451 | } 452 | uint16_t memory_read_touch_timeout(void) 453 | { 454 | memory_eeprom(NULL, (uint8_t *)&MEM_touch_timeout_, MEM_TOUCH_TIMEOUT_ADDR, 2); 455 | return MEM_touch_timeout_; 456 | } 457 | 458 | 459 | void memory_write_touch_thresh(const uint16_t t) 460 | { 461 | memory_eeprom((const uint8_t *)&t, (uint8_t *)&MEM_touch_thresh_, MEM_TOUCH_THRESH_ADDR, 462 | 2); 463 | } 464 | uint16_t memory_read_touch_thresh(void) 465 | { 466 | memory_eeprom(NULL, (uint8_t *)&MEM_touch_thresh_, MEM_TOUCH_THRESH_ADDR, 2); 467 | return MEM_touch_thresh_; 468 | } 469 | 470 | 471 | // Initialize or increment non-volatile err counter 472 | uint16_t memory_access_err_count(const uint8_t access) 473 | { 474 | uint16_t err_count = 0xF0F0; 475 | if (access == STATUS_ACCESS_ITERATE) { 476 | memory_eeprom(NULL, (uint8_t *)&MEM_access_err_, MEM_ACCESS_ERR_ADDR, 2); 477 | err_count = MEM_access_err_ + 1; 478 | } else if (access == STATUS_ACCESS_INITIALIZE) { 479 | err_count = 0; 480 | } else { 481 | err_count = COMMANDER_MAX_ATTEMPTS; // corrupted input 482 | } 483 | 484 | // Force reset after too many failed attempts 485 | if (err_count >= COMMANDER_MAX_ATTEMPTS) { 486 | commander_force_reset(); 487 | } else { 488 | memory_eeprom((uint8_t *)&err_count, (uint8_t *)&MEM_access_err_, MEM_ACCESS_ERR_ADDR, 2); 489 | } 490 | return err_count; 491 | } 492 | uint16_t memory_read_access_err_count(void) 493 | { 494 | memory_eeprom(NULL, (uint8_t *)&MEM_access_err_, MEM_ACCESS_ERR_ADDR, 2); 495 | return MEM_access_err_; 496 | } 497 | 498 | --------------------------------------------------------------------------------