├── .gitignore ├── CMakeLists.txt ├── Cargo.toml ├── LICENSE ├── README.md ├── crypto ├── aes.c ├── aes.h ├── cmac.c ├── cmac.h ├── lw_crypto.c └── lw_crypto.h ├── lw_packets.c ├── lw_packets.h ├── lw_state.h ├── module_logging.h └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(util-lorawan-packets) 2 | 3 | include(${CPATH}/src/github.com/lobaro/c-build/build.cmake) 4 | cbuild_module() -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "util-lorawan-packets" 3 | version = "0.1.0" 4 | authors = ["Tobias Kaupat "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | # name = "" 11 | path="src/lib.rs" 12 | 13 | [dependencies] 14 | 15 | [build-dependencies] 16 | c-build = {path = "../c-build"} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Theodor Tobias Rohde (tr@lobaro.com) 2 | Lobaro - Industrial IoT Solutions 3 | www.lobaro.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # util-lorawan-packets 2 | 3 | A simple library just to pack (marshal) and parse (unmarshal) LoRaWAN packets in C. 4 | It's intended to be used as basis for upper-layer LoRaWAN node oder network-server stacks. Beside this it could be useful for LoRaWAN testing and verification purposes. 5 | 6 | When using this library knowledge about the LoRaWAN specification is needed. You can request the LoRaWAN specification here: https://www.lora-alliance.org/for-developers 7 | 8 | # Features 9 | 10 | - Stack independent LoRaWAN packet parser & encoder 11 | - Easy integration into custom upper-layer LoRaWAN stack implementations 12 | - Only 5 functions: Init, New, Delete, Marshal, Unmarshal 13 | - [x] Support LoRaWAN 1.0 protocol (EU868 only) 14 | - [ ] Support LoRaWAN 1.1 protocol 15 | 16 | The Following message types (MType) are implemented: 17 | - JoinRequest 18 | - JoinAccept 19 | - UnconfirmedDataUp 20 | - UnconfirmedDataDown 21 | - ConfirmedDataUp 22 | - ConfirmedDataDown 23 | - TBD: RejoinRequest (LoRaWAN 1.1) 24 | 25 | # Background 26 | 27 | We use this library internally inside our proprietary closed-source (sorry!) freeRTOS based LoRaWAN-Stack. 28 | At Lobaro we heavily try to achieve a flexible & modular code-base to get projects done fast. With embedded C-code this is often not that easy as with modern languages like goLang. This might be the reason why most LoRaWAN implementations mix the "simple" task of packet encode/decode with protocol business logic. 29 | 30 | This library tries to decouple the packet generation from LoRaWAN stack logic. It includes - cleanly separated - only the absolute minimum of needed LoRaWAN state like keys or framecounters. We think that this LoRaWAN packet encode/decode library is valuable for anybody writing its own LoRaWAN stack. Writing an own LoRaWAN stack is not that hard and can be crucial for getting the most out of the protocol for a particular application. 31 | 32 | ## Future development 33 | 34 | + Additions / Fixes will be constantly merged into this repository. 35 | + Soon the support of the LoRaWAN 1.1 specification should be integrated. 36 | + Add GoLang cgo wrapper 37 | 38 | ## Demo/Example 39 | 40 | TBD 41 | 42 | ## Related 43 | 44 | - This lib is partly based on the work of [JiapengLi](https://github.com/JiapengLi/lorawan-parser) and his command line tool for LoRaWAN packet parsing & encoding 45 | - Similar approach for GoLang https://github.com/brocaar/lorawan. 46 | - Follow [Lobaro on Twitter](https://twitter.com/LobaroHH) to get latest news about our iot projects. 47 | 48 | ## Contribute 49 | 50 | We appreciate any feedback, do not hesitate to create issues or pull requests. 51 | 52 | ## License 53 | 54 | util-lorawan-packets is licensed under [The MIT License](http://opensource.org/licenses/mit-license.php). Check LICENSE for more information. 55 | 56 | AES, CMAC have its own licenses. Please follow links below to get the details. 57 | 58 | ## Acknowledgement 59 | 60 | + LoRa Alliance https://www.lora-alliance.org/ 61 | + Brian Gladman. AES library http://www.gladman.me.uk/ 62 | + Lander Casado, Philippas Tsigas. CMAC library http://www.cse.chalmers.se/research/group/dcs/masters/contikisec/ 63 | + JiapengLi, LoRaWAN protocol parser and packer in C https://github.com/JiapengLi/lorawan-parser 64 | -------------------------------------------------------------------------------- /crypto/aes.c: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. 3 | 4 | LICENSE TERMS 5 | 6 | The redistribution and use of this software (with or without changes) 7 | is allowed without the payment of fees or royalties provided that: 8 | 9 | 1. source code distributions include the above copyright notice, this 10 | list of conditions and the following disclaimer; 11 | 12 | 2. binary distributions include the above copyright notice, this list 13 | of conditions and the following disclaimer in their documentation; 14 | 15 | 3. the name of the copyright holder is not used to endorse products 16 | built using this software without specific written permission. 17 | 18 | DISCLAIMER 19 | 20 | This software is provided 'as is' with no explicit or implied warranties 21 | in respect of its properties, including, but not limited to, correctness 22 | and/or fitness for purpose. 23 | --------------------------------------------------------------------------- 24 | Issue 09/09/2006 25 | 26 | This is an AES implementation that uses only 8-bit byte operations on the 27 | cipher state (there are options to use 32-bit types if available). 28 | 29 | The combination of mix columns and byte substitution used here is based on 30 | that developed by Karl Malbrain. His contribution is acknowledged. 31 | 32 | *****************************************************************************/ 33 | 34 | #include "aes.h" 35 | 36 | #if 1 37 | # define HAVE_MEMCPY 38 | # include 39 | # if defined( _MSC_VER ) 40 | # include 41 | # pragma intrinsic( memcpy ) 42 | # endif 43 | #endif 44 | 45 | 46 | #include 47 | 48 | /* define if you have fast 32-bit types on your system */ 49 | #if 1 50 | # define HAVE_UINT_32T 51 | #endif 52 | 53 | /* define if you don't want any tables */ 54 | #if 1 55 | # define USE_TABLES 56 | #endif 57 | 58 | /* On Intel Core 2 duo VERSION_1 is faster */ 59 | 60 | /* alternative versions (test for performance on your system) */ 61 | #if 1 62 | # define VERSION_1 63 | #endif 64 | 65 | #include "aes.h" 66 | 67 | #if defined( HAVE_UINT_32T ) 68 | typedef unsigned uint_32t; // Edited by Semtech - David Roe 1 Dec 13 69 | #endif 70 | 71 | /* functions for finite field multiplication in the AES Galois field */ 72 | 73 | #define WPOLY 0x011b 74 | #define BPOLY 0x1b 75 | #define DPOLY 0x008d 76 | 77 | #define f1(x) (x) 78 | #define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY)) 79 | #define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY)) 80 | #define f8(x) ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) \ 81 | ^ (((x >> 5) & 4) * WPOLY)) 82 | #define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0)) 83 | 84 | #define f3(x) (f2(x) ^ x) 85 | #define f9(x) (f8(x) ^ x) 86 | #define fb(x) (f8(x) ^ f2(x) ^ x) 87 | #define fd(x) (f8(x) ^ f4(x) ^ x) 88 | #define fe(x) (f8(x) ^ f4(x) ^ f2(x)) 89 | 90 | #if defined( USE_TABLES ) 91 | 92 | #define sb_data(w) { /* S Box data values */ \ 93 | w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ 94 | w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ 95 | w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ 96 | w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ 97 | w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ 98 | w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ 99 | w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ 100 | w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ 101 | w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ 102 | w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ 103 | w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ 104 | w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ 105 | w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ 106 | w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ 107 | w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ 108 | w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ 109 | w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ 110 | w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ 111 | w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ 112 | w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ 113 | w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ 114 | w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ 115 | w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ 116 | w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ 117 | w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ 118 | w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ 119 | w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ 120 | w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ 121 | w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ 122 | w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ 123 | w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ 124 | w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } 125 | 126 | #define isb_data(w) { /* inverse S Box data values */ \ 127 | w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ 128 | w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ 129 | w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ 130 | w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ 131 | w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ 132 | w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ 133 | w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ 134 | w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ 135 | w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ 136 | w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ 137 | w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ 138 | w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ 139 | w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ 140 | w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ 141 | w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ 142 | w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ 143 | w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ 144 | w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ 145 | w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ 146 | w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ 147 | w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ 148 | w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ 149 | w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ 150 | w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ 151 | w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ 152 | w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ 153 | w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ 154 | w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ 155 | w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ 156 | w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ 157 | w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ 158 | w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } 159 | 160 | #define mm_data(w) { /* basic data for forming finite field tables */ \ 161 | w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ 162 | w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ 163 | w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ 164 | w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ 165 | w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ 166 | w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ 167 | w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ 168 | w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ 169 | w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ 170 | w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ 171 | w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ 172 | w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ 173 | w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ 174 | w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ 175 | w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ 176 | w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ 177 | w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ 178 | w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ 179 | w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ 180 | w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ 181 | w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ 182 | w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ 183 | w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ 184 | w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ 185 | w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ 186 | w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ 187 | w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ 188 | w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ 189 | w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ 190 | w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ 191 | w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ 192 | w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } 193 | 194 | static const uint_8t sbox[256] = sb_data(f1); 195 | static const uint_8t isbox[256] = isb_data(f1); 196 | 197 | static const uint_8t gfm2_sbox[256] = sb_data(f2); 198 | static const uint_8t gfm3_sbox[256] = sb_data(f3); 199 | 200 | static const uint_8t gfmul_9[256] = mm_data(f9); 201 | static const uint_8t gfmul_b[256] = mm_data(fb); 202 | static const uint_8t gfmul_d[256] = mm_data(fd); 203 | static const uint_8t gfmul_e[256] = mm_data(fe); 204 | 205 | #define s_box(x) sbox[(x)] 206 | #define is_box(x) isbox[(x)] 207 | #define gfm2_sb(x) gfm2_sbox[(x)] 208 | #define gfm3_sb(x) gfm3_sbox[(x)] 209 | #define gfm_9(x) gfmul_9[(x)] 210 | #define gfm_b(x) gfmul_b[(x)] 211 | #define gfm_d(x) gfmul_d[(x)] 212 | #define gfm_e(x) gfmul_e[(x)] 213 | 214 | #else 215 | 216 | /* this is the high bit of x right shifted by 1 */ 217 | /* position. Since the starting polynomial has */ 218 | /* 9 bits (0x11b), this right shift keeps the */ 219 | /* values of all top bits within a byte */ 220 | 221 | static uint_8t hibit(const uint_8t x) 222 | { uint_8t r = (uint_8t)((x >> 1) | (x >> 2)); 223 | 224 | r |= (r >> 2); 225 | r |= (r >> 4); 226 | return (r + 1) >> 1; 227 | } 228 | 229 | /* return the inverse of the finite field element x */ 230 | 231 | static uint_8t gf_inv(const uint_8t x) 232 | { uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; 233 | 234 | if(x < 2) 235 | return x; 236 | 237 | for( ; ; ) 238 | { 239 | if(n1) 240 | while(n2 >= n1) /* divide polynomial p2 by p1 */ 241 | { 242 | n2 /= n1; /* shift smaller polynomial left */ 243 | p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ 244 | v2 ^= (v1 * n2); /* shift accumulated value and */ 245 | n2 = hibit(p2); /* add into result */ 246 | } 247 | else 248 | return v1; 249 | 250 | if(n2) /* repeat with values swapped */ 251 | while(n1 >= n2) 252 | { 253 | n1 /= n2; 254 | p1 ^= p2 * n1; 255 | v1 ^= v2 * n1; 256 | n1 = hibit(p1); 257 | } 258 | else 259 | return v2; 260 | } 261 | } 262 | 263 | /* The forward and inverse affine transformations used in the S-box */ 264 | uint_8t fwd_affine(const uint_8t x) 265 | { 266 | #if defined( HAVE_UINT_32T ) 267 | uint_32t w = x; 268 | w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); 269 | return 0x63 ^ ((w ^ (w >> 8)) & 0xff); 270 | #else 271 | return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) 272 | ^ (x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4); 273 | #endif 274 | } 275 | 276 | uint_8t inv_affine(const uint_8t x) 277 | { 278 | #if defined( HAVE_UINT_32T ) 279 | uint_32t w = x; 280 | w = (w << 1) ^ (w << 3) ^ (w << 6); 281 | return 0x05 ^ ((w ^ (w >> 8)) & 0xff); 282 | #else 283 | return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) 284 | ^ (x >> 7) ^ (x >> 5) ^ (x >> 2); 285 | #endif 286 | } 287 | 288 | #define s_box(x) fwd_affine(gf_inv(x)) 289 | #define is_box(x) gf_inv(inv_affine(x)) 290 | #define gfm2_sb(x) f2(s_box(x)) 291 | #define gfm3_sb(x) f3(s_box(x)) 292 | #define gfm_9(x) f9(x) 293 | #define gfm_b(x) fb(x) 294 | #define gfm_d(x) fd(x) 295 | #define gfm_e(x) fe(x) 296 | 297 | #endif 298 | 299 | #if defined( HAVE_MEMCPY ) 300 | # define block_copy_nn(d, s, l) memcpy(d, s, l) 301 | # define block_copy(d, s) memcpy(d, s, N_BLOCK) 302 | #else 303 | # define block_copy_nn(d, s, l) copy_block_nn(d, s, l) 304 | # define block_copy(d, s) copy_block(d, s) 305 | 306 | static void copy_block( void *d, const void *s ) 307 | { 308 | #if defined( HAVE_UINT_32T ) 309 | ((uint_32t*)d)[ 0] = ((uint_32t*)s)[ 0]; 310 | ((uint_32t*)d)[ 1] = ((uint_32t*)s)[ 1]; 311 | ((uint_32t*)d)[ 2] = ((uint_32t*)s)[ 2]; 312 | ((uint_32t*)d)[ 3] = ((uint_32t*)s)[ 3]; 313 | #else 314 | ((uint_8t*)d)[ 0] = ((uint_8t*)s)[ 0]; 315 | ((uint_8t*)d)[ 1] = ((uint_8t*)s)[ 1]; 316 | ((uint_8t*)d)[ 2] = ((uint_8t*)s)[ 2]; 317 | ((uint_8t*)d)[ 3] = ((uint_8t*)s)[ 3]; 318 | ((uint_8t*)d)[ 4] = ((uint_8t*)s)[ 4]; 319 | ((uint_8t*)d)[ 5] = ((uint_8t*)s)[ 5]; 320 | ((uint_8t*)d)[ 6] = ((uint_8t*)s)[ 6]; 321 | ((uint_8t*)d)[ 7] = ((uint_8t*)s)[ 7]; 322 | ((uint_8t*)d)[ 8] = ((uint_8t*)s)[ 8]; 323 | ((uint_8t*)d)[ 9] = ((uint_8t*)s)[ 9]; 324 | ((uint_8t*)d)[10] = ((uint_8t*)s)[10]; 325 | ((uint_8t*)d)[11] = ((uint_8t*)s)[11]; 326 | ((uint_8t*)d)[12] = ((uint_8t*)s)[12]; 327 | ((uint_8t*)d)[13] = ((uint_8t*)s)[13]; 328 | ((uint_8t*)d)[14] = ((uint_8t*)s)[14]; 329 | ((uint_8t*)d)[15] = ((uint_8t*)s)[15]; 330 | #endif 331 | } 332 | 333 | static void copy_block_nn( uint_8t * d, const uint_8t *s, uint_8t nn ) 334 | { 335 | while( nn-- ) 336 | //*((uint_8t*)d)++ = *((uint_8t*)s)++; 337 | *d++ = *s++; 338 | } 339 | 340 | #endif /* HAVE_MEMCPY */ 341 | 342 | static void xor_block( void *d, const void *s ) 343 | { 344 | #if defined( HAVE_UINT_32T ) 345 | ((uint_32t*)d)[ 0] ^= ((uint_32t*)s)[ 0]; 346 | ((uint_32t*)d)[ 1] ^= ((uint_32t*)s)[ 1]; 347 | ((uint_32t*)d)[ 2] ^= ((uint_32t*)s)[ 2]; 348 | ((uint_32t*)d)[ 3] ^= ((uint_32t*)s)[ 3]; 349 | #else 350 | ((uint_8t*)d)[ 0] ^= ((uint_8t*)s)[ 0]; 351 | ((uint_8t*)d)[ 1] ^= ((uint_8t*)s)[ 1]; 352 | ((uint_8t*)d)[ 2] ^= ((uint_8t*)s)[ 2]; 353 | ((uint_8t*)d)[ 3] ^= ((uint_8t*)s)[ 3]; 354 | ((uint_8t*)d)[ 4] ^= ((uint_8t*)s)[ 4]; 355 | ((uint_8t*)d)[ 5] ^= ((uint_8t*)s)[ 5]; 356 | ((uint_8t*)d)[ 6] ^= ((uint_8t*)s)[ 6]; 357 | ((uint_8t*)d)[ 7] ^= ((uint_8t*)s)[ 7]; 358 | ((uint_8t*)d)[ 8] ^= ((uint_8t*)s)[ 8]; 359 | ((uint_8t*)d)[ 9] ^= ((uint_8t*)s)[ 9]; 360 | ((uint_8t*)d)[10] ^= ((uint_8t*)s)[10]; 361 | ((uint_8t*)d)[11] ^= ((uint_8t*)s)[11]; 362 | ((uint_8t*)d)[12] ^= ((uint_8t*)s)[12]; 363 | ((uint_8t*)d)[13] ^= ((uint_8t*)s)[13]; 364 | ((uint_8t*)d)[14] ^= ((uint_8t*)s)[14]; 365 | ((uint_8t*)d)[15] ^= ((uint_8t*)s)[15]; 366 | #endif 367 | } 368 | 369 | static void copy_and_key( void *d, const void *s, const void *k ) 370 | { 371 | #if defined( HAVE_UINT_32T ) 372 | ((uint_32t*)d)[ 0] = ((uint_32t*)s)[ 0] ^ ((uint_32t*)k)[ 0]; 373 | ((uint_32t*)d)[ 1] = ((uint_32t*)s)[ 1] ^ ((uint_32t*)k)[ 1]; 374 | ((uint_32t*)d)[ 2] = ((uint_32t*)s)[ 2] ^ ((uint_32t*)k)[ 2]; 375 | ((uint_32t*)d)[ 3] = ((uint_32t*)s)[ 3] ^ ((uint_32t*)k)[ 3]; 376 | #elif 1 377 | ((uint_8t*)d)[ 0] = ((uint_8t*)s)[ 0] ^ ((uint_8t*)k)[ 0]; 378 | ((uint_8t*)d)[ 1] = ((uint_8t*)s)[ 1] ^ ((uint_8t*)k)[ 1]; 379 | ((uint_8t*)d)[ 2] = ((uint_8t*)s)[ 2] ^ ((uint_8t*)k)[ 2]; 380 | ((uint_8t*)d)[ 3] = ((uint_8t*)s)[ 3] ^ ((uint_8t*)k)[ 3]; 381 | ((uint_8t*)d)[ 4] = ((uint_8t*)s)[ 4] ^ ((uint_8t*)k)[ 4]; 382 | ((uint_8t*)d)[ 5] = ((uint_8t*)s)[ 5] ^ ((uint_8t*)k)[ 5]; 383 | ((uint_8t*)d)[ 6] = ((uint_8t*)s)[ 6] ^ ((uint_8t*)k)[ 6]; 384 | ((uint_8t*)d)[ 7] = ((uint_8t*)s)[ 7] ^ ((uint_8t*)k)[ 7]; 385 | ((uint_8t*)d)[ 8] = ((uint_8t*)s)[ 8] ^ ((uint_8t*)k)[ 8]; 386 | ((uint_8t*)d)[ 9] = ((uint_8t*)s)[ 9] ^ ((uint_8t*)k)[ 9]; 387 | ((uint_8t*)d)[10] = ((uint_8t*)s)[10] ^ ((uint_8t*)k)[10]; 388 | ((uint_8t*)d)[11] = ((uint_8t*)s)[11] ^ ((uint_8t*)k)[11]; 389 | ((uint_8t*)d)[12] = ((uint_8t*)s)[12] ^ ((uint_8t*)k)[12]; 390 | ((uint_8t*)d)[13] = ((uint_8t*)s)[13] ^ ((uint_8t*)k)[13]; 391 | ((uint_8t*)d)[14] = ((uint_8t*)s)[14] ^ ((uint_8t*)k)[14]; 392 | ((uint_8t*)d)[15] = ((uint_8t*)s)[15] ^ ((uint_8t*)k)[15]; 393 | #else 394 | block_copy(d, s); 395 | xor_block(d, k); 396 | #endif 397 | } 398 | 399 | static void add_round_key( uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK] ) 400 | { 401 | xor_block(d, k); 402 | } 403 | 404 | static void shift_sub_rows( uint_8t st[N_BLOCK] ) 405 | { uint_8t tt; 406 | 407 | st[ 0] = s_box(st[ 0]); st[ 4] = s_box(st[ 4]); 408 | st[ 8] = s_box(st[ 8]); st[12] = s_box(st[12]); 409 | 410 | tt = st[1]; st[ 1] = s_box(st[ 5]); st[ 5] = s_box(st[ 9]); 411 | st[ 9] = s_box(st[13]); st[13] = s_box( tt ); 412 | 413 | tt = st[2]; st[ 2] = s_box(st[10]); st[10] = s_box( tt ); 414 | tt = st[6]; st[ 6] = s_box(st[14]); st[14] = s_box( tt ); 415 | 416 | tt = st[15]; st[15] = s_box(st[11]); st[11] = s_box(st[ 7]); 417 | st[ 7] = s_box(st[ 3]); st[ 3] = s_box( tt ); 418 | } 419 | 420 | static void inv_shift_sub_rows( uint_8t st[N_BLOCK] ) 421 | { uint_8t tt; 422 | 423 | st[ 0] = is_box(st[ 0]); st[ 4] = is_box(st[ 4]); 424 | st[ 8] = is_box(st[ 8]); st[12] = is_box(st[12]); 425 | 426 | tt = st[13]; st[13] = is_box(st[9]); st[ 9] = is_box(st[5]); 427 | st[ 5] = is_box(st[1]); st[ 1] = is_box( tt ); 428 | 429 | tt = st[2]; st[ 2] = is_box(st[10]); st[10] = is_box( tt ); 430 | tt = st[6]; st[ 6] = is_box(st[14]); st[14] = is_box( tt ); 431 | 432 | tt = st[3]; st[ 3] = is_box(st[ 7]); st[ 7] = is_box(st[11]); 433 | st[11] = is_box(st[15]); st[15] = is_box( tt ); 434 | } 435 | 436 | #if defined( VERSION_1 ) 437 | static void mix_sub_columns( uint_8t dt[N_BLOCK] ) 438 | { uint_8t st[N_BLOCK]; 439 | block_copy(st, dt); 440 | #else 441 | static void mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] ) 442 | { 443 | #endif 444 | dt[ 0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]); 445 | dt[ 1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]); 446 | dt[ 2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]); 447 | dt[ 3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]); 448 | 449 | dt[ 4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]); 450 | dt[ 5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]); 451 | dt[ 6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]); 452 | dt[ 7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]); 453 | 454 | dt[ 8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]); 455 | dt[ 9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]); 456 | dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]); 457 | dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]); 458 | 459 | dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]); 460 | dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]); 461 | dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]); 462 | dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]); 463 | } 464 | 465 | #if defined( VERSION_1 ) 466 | static void inv_mix_sub_columns( uint_8t dt[N_BLOCK] ) 467 | { uint_8t st[N_BLOCK]; 468 | block_copy(st, dt); 469 | #else 470 | static void inv_mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] ) 471 | { 472 | #endif 473 | dt[ 0] = is_box(gfm_e(st[ 0]) ^ gfm_b(st[ 1]) ^ gfm_d(st[ 2]) ^ gfm_9(st[ 3])); 474 | dt[ 5] = is_box(gfm_9(st[ 0]) ^ gfm_e(st[ 1]) ^ gfm_b(st[ 2]) ^ gfm_d(st[ 3])); 475 | dt[10] = is_box(gfm_d(st[ 0]) ^ gfm_9(st[ 1]) ^ gfm_e(st[ 2]) ^ gfm_b(st[ 3])); 476 | dt[15] = is_box(gfm_b(st[ 0]) ^ gfm_d(st[ 1]) ^ gfm_9(st[ 2]) ^ gfm_e(st[ 3])); 477 | 478 | dt[ 4] = is_box(gfm_e(st[ 4]) ^ gfm_b(st[ 5]) ^ gfm_d(st[ 6]) ^ gfm_9(st[ 7])); 479 | dt[ 9] = is_box(gfm_9(st[ 4]) ^ gfm_e(st[ 5]) ^ gfm_b(st[ 6]) ^ gfm_d(st[ 7])); 480 | dt[14] = is_box(gfm_d(st[ 4]) ^ gfm_9(st[ 5]) ^ gfm_e(st[ 6]) ^ gfm_b(st[ 7])); 481 | dt[ 3] = is_box(gfm_b(st[ 4]) ^ gfm_d(st[ 5]) ^ gfm_9(st[ 6]) ^ gfm_e(st[ 7])); 482 | 483 | dt[ 8] = is_box(gfm_e(st[ 8]) ^ gfm_b(st[ 9]) ^ gfm_d(st[10]) ^ gfm_9(st[11])); 484 | dt[13] = is_box(gfm_9(st[ 8]) ^ gfm_e(st[ 9]) ^ gfm_b(st[10]) ^ gfm_d(st[11])); 485 | dt[ 2] = is_box(gfm_d(st[ 8]) ^ gfm_9(st[ 9]) ^ gfm_e(st[10]) ^ gfm_b(st[11])); 486 | dt[ 7] = is_box(gfm_b(st[ 8]) ^ gfm_d(st[ 9]) ^ gfm_9(st[10]) ^ gfm_e(st[11])); 487 | 488 | dt[12] = is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15])); 489 | dt[ 1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15])); 490 | dt[ 6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15])); 491 | dt[11] = is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15])); 492 | } 493 | 494 | #if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) 495 | 496 | /* Set the cipher key for the pre-keyed version */ 497 | 498 | return_type aes_set_key( const unsigned char key[], length_type keylen, aes_context ctx[1] ) 499 | { 500 | uint_8t cc, rc, hi; 501 | 502 | switch( keylen ) 503 | { 504 | case 16: 505 | case 24: 506 | case 32: 507 | break; 508 | default: 509 | ctx->rnd = 0; 510 | return -1; 511 | } 512 | block_copy_nn(ctx->ksch, key, keylen); 513 | hi = (keylen + 28) << 2; 514 | ctx->rnd = (hi >> 4) - 1; 515 | for( cc = keylen, rc = 1; cc < hi; cc += 4 ) 516 | { uint_8t tt, t0, t1, t2, t3; 517 | 518 | t0 = ctx->ksch[cc - 4]; 519 | t1 = ctx->ksch[cc - 3]; 520 | t2 = ctx->ksch[cc - 2]; 521 | t3 = ctx->ksch[cc - 1]; 522 | if( cc % keylen == 0 ) 523 | { 524 | tt = t0; 525 | t0 = s_box(t1) ^ rc; 526 | t1 = s_box(t2); 527 | t2 = s_box(t3); 528 | t3 = s_box(tt); 529 | rc = f2(rc); 530 | } 531 | else if( keylen > 24 && cc % keylen == 16 ) 532 | { 533 | t0 = s_box(t0); 534 | t1 = s_box(t1); 535 | t2 = s_box(t2); 536 | t3 = s_box(t3); 537 | } 538 | tt = cc - keylen; 539 | ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0; 540 | ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1; 541 | ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2; 542 | ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3; 543 | } 544 | return 0; 545 | } 546 | 547 | #endif 548 | 549 | #if defined( AES_ENC_PREKEYED ) 550 | 551 | /* Encrypt a single block of 16 bytes */ 552 | 553 | return_type aes_encrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] ) 554 | { 555 | if( ctx->rnd ) 556 | { 557 | uint_8t s1[N_BLOCK], r; 558 | copy_and_key( s1, in, ctx->ksch ); 559 | 560 | for( r = 1 ; r < ctx->rnd ; ++r ) 561 | #if defined( VERSION_1 ) 562 | { 563 | mix_sub_columns( s1 ); 564 | add_round_key( s1, ctx->ksch + r * N_BLOCK); 565 | } 566 | #else 567 | { uint_8t s2[N_BLOCK]; 568 | mix_sub_columns( s2, s1 ); 569 | copy_and_key( s1, s2, ctx->ksch + r * N_BLOCK); 570 | } 571 | #endif 572 | shift_sub_rows( s1 ); 573 | copy_and_key( out, s1, ctx->ksch + r * N_BLOCK ); 574 | } 575 | else 576 | return -1; 577 | return 0; 578 | } 579 | 580 | /* CBC encrypt a number of blocks (input and return an IV) */ 581 | 582 | return_type aes_cbc_encrypt( const unsigned char *in, unsigned char *out, 583 | int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] ) 584 | { 585 | 586 | while(n_block--) 587 | { 588 | xor_block(iv, in); 589 | if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) 590 | return EXIT_FAILURE; 591 | //memcpy(out, iv, N_BLOCK); 592 | block_copy(out, iv); 593 | in += N_BLOCK; 594 | out += N_BLOCK; 595 | } 596 | return EXIT_SUCCESS; 597 | } 598 | 599 | #endif 600 | 601 | #if defined( AES_DEC_PREKEYED ) 602 | 603 | /* Decrypt a single block of 16 bytes */ 604 | 605 | return_type aes_decrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] ) 606 | { 607 | if( ctx->rnd ) 608 | { 609 | uint_8t s1[N_BLOCK], r; 610 | copy_and_key( s1, in, ctx->ksch + ctx->rnd * N_BLOCK ); 611 | inv_shift_sub_rows( s1 ); 612 | 613 | for( r = ctx->rnd ; --r ; ) 614 | #if defined( VERSION_1 ) 615 | { 616 | add_round_key( s1, ctx->ksch + r * N_BLOCK ); 617 | inv_mix_sub_columns( s1 ); 618 | } 619 | #else 620 | { uint_8t s2[N_BLOCK]; 621 | copy_and_key( s2, s1, ctx->ksch + r * N_BLOCK ); 622 | inv_mix_sub_columns( s1, s2 ); 623 | } 624 | #endif 625 | copy_and_key( out, s1, ctx->ksch ); 626 | } 627 | else 628 | return -1; 629 | return 0; 630 | } 631 | 632 | /* CBC decrypt a number of blocks (input and return an IV) */ 633 | 634 | return_type aes_cbc_decrypt( const unsigned char *in, unsigned char *out, 635 | int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] ) 636 | { 637 | while(n_block--) 638 | { uint_8t tmp[N_BLOCK]; 639 | 640 | //memcpy(tmp, in, N_BLOCK); 641 | block_copy(tmp, in); 642 | if(aes_decrypt(in, out, ctx) != EXIT_SUCCESS) 643 | return EXIT_FAILURE; 644 | xor_block(out, iv); 645 | //memcpy(iv, tmp, N_BLOCK); 646 | block_copy(iv, tmp); 647 | in += N_BLOCK; 648 | out += N_BLOCK; 649 | } 650 | return EXIT_SUCCESS; 651 | } 652 | 653 | #endif 654 | 655 | #if defined( AES_ENC_128_OTFK ) 656 | 657 | /* The 'on the fly' encryption key update for for 128 bit keys */ 658 | 659 | static void update_encrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc ) 660 | { uint_8t cc; 661 | 662 | k[0] ^= s_box(k[13]) ^ *rc; 663 | k[1] ^= s_box(k[14]); 664 | k[2] ^= s_box(k[15]); 665 | k[3] ^= s_box(k[12]); 666 | *rc = f2( *rc ); 667 | 668 | for(cc = 4; cc < 16; cc += 4 ) 669 | { 670 | k[cc + 0] ^= k[cc - 4]; 671 | k[cc + 1] ^= k[cc - 3]; 672 | k[cc + 2] ^= k[cc - 2]; 673 | k[cc + 3] ^= k[cc - 1]; 674 | } 675 | } 676 | 677 | /* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ 678 | 679 | void aes_encrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], 680 | const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] ) 681 | { uint_8t s1[N_BLOCK], r, rc = 1; 682 | 683 | if(o_key != key) 684 | block_copy( o_key, key ); 685 | copy_and_key( s1, in, o_key ); 686 | 687 | for( r = 1 ; r < 10 ; ++r ) 688 | #if defined( VERSION_1 ) 689 | { 690 | mix_sub_columns( s1 ); 691 | update_encrypt_key_128( o_key, &rc ); 692 | add_round_key( s1, o_key ); 693 | } 694 | #else 695 | { uint_8t s2[N_BLOCK]; 696 | mix_sub_columns( s2, s1 ); 697 | update_encrypt_key_128( o_key, &rc ); 698 | copy_and_key( s1, s2, o_key ); 699 | } 700 | #endif 701 | 702 | shift_sub_rows( s1 ); 703 | update_encrypt_key_128( o_key, &rc ); 704 | copy_and_key( out, s1, o_key ); 705 | } 706 | 707 | #endif 708 | 709 | #if defined( AES_DEC_128_OTFK ) 710 | 711 | /* The 'on the fly' decryption key update for for 128 bit keys */ 712 | 713 | static void update_decrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc ) 714 | { uint_8t cc; 715 | 716 | for( cc = 12; cc > 0; cc -= 4 ) 717 | { 718 | k[cc + 0] ^= k[cc - 4]; 719 | k[cc + 1] ^= k[cc - 3]; 720 | k[cc + 2] ^= k[cc - 2]; 721 | k[cc + 3] ^= k[cc - 1]; 722 | } 723 | *rc = d2(*rc); 724 | k[0] ^= s_box(k[13]) ^ *rc; 725 | k[1] ^= s_box(k[14]); 726 | k[2] ^= s_box(k[15]); 727 | k[3] ^= s_box(k[12]); 728 | } 729 | 730 | /* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ 731 | 732 | void aes_decrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], 733 | const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] ) 734 | { 735 | uint_8t s1[N_BLOCK], r, rc = 0x6c; 736 | if(o_key != key) 737 | block_copy( o_key, key ); 738 | 739 | copy_and_key( s1, in, o_key ); 740 | inv_shift_sub_rows( s1 ); 741 | 742 | for( r = 10 ; --r ; ) 743 | #if defined( VERSION_1 ) 744 | { 745 | update_decrypt_key_128( o_key, &rc ); 746 | add_round_key( s1, o_key ); 747 | inv_mix_sub_columns( s1 ); 748 | } 749 | #else 750 | { uint_8t s2[N_BLOCK]; 751 | update_decrypt_key_128( o_key, &rc ); 752 | copy_and_key( s2, s1, o_key ); 753 | inv_mix_sub_columns( s1, s2 ); 754 | } 755 | #endif 756 | update_decrypt_key_128( o_key, &rc ); 757 | copy_and_key( out, s1, o_key ); 758 | } 759 | 760 | #endif 761 | 762 | #if defined( AES_ENC_256_OTFK ) 763 | 764 | /* The 'on the fly' encryption key update for for 256 bit keys */ 765 | 766 | static void update_encrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc ) 767 | { uint_8t cc; 768 | 769 | k[0] ^= s_box(k[29]) ^ *rc; 770 | k[1] ^= s_box(k[30]); 771 | k[2] ^= s_box(k[31]); 772 | k[3] ^= s_box(k[28]); 773 | *rc = f2( *rc ); 774 | 775 | for(cc = 4; cc < 16; cc += 4) 776 | { 777 | k[cc + 0] ^= k[cc - 4]; 778 | k[cc + 1] ^= k[cc - 3]; 779 | k[cc + 2] ^= k[cc - 2]; 780 | k[cc + 3] ^= k[cc - 1]; 781 | } 782 | 783 | k[16] ^= s_box(k[12]); 784 | k[17] ^= s_box(k[13]); 785 | k[18] ^= s_box(k[14]); 786 | k[19] ^= s_box(k[15]); 787 | 788 | for( cc = 20; cc < 32; cc += 4 ) 789 | { 790 | k[cc + 0] ^= k[cc - 4]; 791 | k[cc + 1] ^= k[cc - 3]; 792 | k[cc + 2] ^= k[cc - 2]; 793 | k[cc + 3] ^= k[cc - 1]; 794 | } 795 | } 796 | 797 | /* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */ 798 | 799 | void aes_encrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], 800 | const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] ) 801 | { 802 | uint_8t s1[N_BLOCK], r, rc = 1; 803 | if(o_key != key) 804 | { 805 | block_copy( o_key, key ); 806 | block_copy( o_key + 16, key + 16 ); 807 | } 808 | copy_and_key( s1, in, o_key ); 809 | 810 | for( r = 1 ; r < 14 ; ++r ) 811 | #if defined( VERSION_1 ) 812 | { 813 | mix_sub_columns(s1); 814 | if( r & 1 ) 815 | add_round_key( s1, o_key + 16 ); 816 | else 817 | { 818 | update_encrypt_key_256( o_key, &rc ); 819 | add_round_key( s1, o_key ); 820 | } 821 | } 822 | #else 823 | { uint_8t s2[N_BLOCK]; 824 | mix_sub_columns( s2, s1 ); 825 | if( r & 1 ) 826 | copy_and_key( s1, s2, o_key + 16 ); 827 | else 828 | { 829 | update_encrypt_key_256( o_key, &rc ); 830 | copy_and_key( s1, s2, o_key ); 831 | } 832 | } 833 | #endif 834 | 835 | shift_sub_rows( s1 ); 836 | update_encrypt_key_256( o_key, &rc ); 837 | copy_and_key( out, s1, o_key ); 838 | } 839 | 840 | #endif 841 | 842 | #if defined( AES_DEC_256_OTFK ) 843 | 844 | /* The 'on the fly' encryption key update for for 256 bit keys */ 845 | 846 | static void update_decrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc ) 847 | { uint_8t cc; 848 | 849 | for(cc = 28; cc > 16; cc -= 4) 850 | { 851 | k[cc + 0] ^= k[cc - 4]; 852 | k[cc + 1] ^= k[cc - 3]; 853 | k[cc + 2] ^= k[cc - 2]; 854 | k[cc + 3] ^= k[cc - 1]; 855 | } 856 | 857 | k[16] ^= s_box(k[12]); 858 | k[17] ^= s_box(k[13]); 859 | k[18] ^= s_box(k[14]); 860 | k[19] ^= s_box(k[15]); 861 | 862 | for(cc = 12; cc > 0; cc -= 4) 863 | { 864 | k[cc + 0] ^= k[cc - 4]; 865 | k[cc + 1] ^= k[cc - 3]; 866 | k[cc + 2] ^= k[cc - 2]; 867 | k[cc + 3] ^= k[cc - 1]; 868 | } 869 | 870 | *rc = d2(*rc); 871 | k[0] ^= s_box(k[29]) ^ *rc; 872 | k[1] ^= s_box(k[30]); 873 | k[2] ^= s_box(k[31]); 874 | k[3] ^= s_box(k[28]); 875 | } 876 | 877 | /* Decrypt a single block of 16 bytes with 'on the fly' 878 | 256 bit keying 879 | */ 880 | void aes_decrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], 881 | const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] ) 882 | { 883 | uint_8t s1[N_BLOCK], r, rc = 0x80; 884 | 885 | if(o_key != key) 886 | { 887 | block_copy( o_key, key ); 888 | block_copy( o_key + 16, key + 16 ); 889 | } 890 | 891 | copy_and_key( s1, in, o_key ); 892 | inv_shift_sub_rows( s1 ); 893 | 894 | for( r = 14 ; --r ; ) 895 | #if defined( VERSION_1 ) 896 | { 897 | if( ( r & 1 ) ) 898 | { 899 | update_decrypt_key_256( o_key, &rc ); 900 | add_round_key( s1, o_key + 16 ); 901 | } 902 | else 903 | add_round_key( s1, o_key ); 904 | inv_mix_sub_columns( s1 ); 905 | } 906 | #else 907 | { uint_8t s2[N_BLOCK]; 908 | if( ( r & 1 ) ) 909 | { 910 | update_decrypt_key_256( o_key, &rc ); 911 | copy_and_key( s2, s1, o_key + 16 ); 912 | } 913 | else 914 | copy_and_key( s2, s1, o_key ); 915 | inv_mix_sub_columns( s1, s2 ); 916 | } 917 | #endif 918 | copy_and_key( out, s1, o_key ); 919 | } 920 | 921 | #endif 922 | -------------------------------------------------------------------------------- /crypto/aes.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. 3 | 4 | LICENSE TERMS 5 | 6 | The redistribution and use of this software (with or without changes) 7 | is allowed without the payment of fees or royalties provided that: 8 | 9 | 1. source code distributions include the above copyright notice, this 10 | list of conditions and the following disclaimer; 11 | 12 | 2. binary distributions include the above copyright notice, this list 13 | of conditions and the following disclaimer in their documentation; 14 | 15 | 3. the name of the copyright holder is not used to endorse products 16 | built using this software without specific written permission. 17 | 18 | DISCLAIMER 19 | 20 | This software is provided 'as is' with no explicit or implied warranties 21 | in respect of its properties, including, but not limited to, correctness 22 | and/or fitness for purpose. 23 | --------------------------------------------------------------------------- 24 | Issue 09/09/2006 25 | 26 | This is an AES implementation that uses only 8-bit byte operations on the 27 | cipher state. 28 | 29 | *****************************************************************************/ 30 | 31 | #ifndef AES_H 32 | #define AES_H 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | #if 1 39 | # define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */ 40 | #endif 41 | #if 1 //Changed Dave Roe 29 Apr 2014 42 | # define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */ 43 | #endif 44 | #if 0 45 | # define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */ 46 | #endif 47 | #if 0 48 | # define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */ 49 | #endif 50 | #if 0 51 | # define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */ 52 | #endif 53 | #if 0 54 | # define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */ 55 | #endif 56 | 57 | #define N_ROW 4 58 | #define N_COL 4 59 | #define N_BLOCK (N_ROW * N_COL) 60 | #define N_MAX_ROUNDS 14 61 | 62 | typedef unsigned char uint_8t; 63 | 64 | typedef uint_8t return_type; 65 | 66 | /* Warning: The key length for 256 bit keys overflows a byte 67 | (see comment below) 68 | */ 69 | 70 | typedef uint_8t length_type; 71 | 72 | typedef struct 73 | { uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK]; 74 | uint_8t rnd; 75 | } aes_context; 76 | 77 | /* The following calls are for a precomputed key schedule 78 | 79 | NOTE: If the length_type used for the key length is an 80 | unsigned 8-bit character, a key length of 256 bits must 81 | be entered as a length in bytes (valid inputs are hence 82 | 128, 192, 16, 24 and 32). 83 | */ 84 | 85 | #if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) 86 | 87 | return_type aes_set_key( const unsigned char key[], 88 | length_type keylen, 89 | aes_context ctx[1] ); 90 | #endif 91 | 92 | #if defined( AES_ENC_PREKEYED ) 93 | 94 | return_type aes_encrypt( const unsigned char in[N_BLOCK], 95 | unsigned char out[N_BLOCK], 96 | const aes_context ctx[1] ); 97 | 98 | return_type aes_cbc_encrypt( const unsigned char *in, 99 | unsigned char *out, 100 | int n_block, 101 | unsigned char iv[N_BLOCK], 102 | const aes_context ctx[1] ); 103 | #endif 104 | 105 | #if defined( AES_DEC_PREKEYED ) 106 | 107 | return_type aes_decrypt( const unsigned char in[N_BLOCK], 108 | unsigned char out[N_BLOCK], 109 | const aes_context ctx[1] ); 110 | 111 | return_type aes_cbc_decrypt( const unsigned char *in, 112 | unsigned char *out, 113 | int n_block, 114 | unsigned char iv[N_BLOCK], 115 | const aes_context ctx[1] ); 116 | #endif 117 | 118 | /* The following calls are for 'on the fly' keying. In this case the 119 | encryption and decryption keys are different. 120 | 121 | The encryption subroutines take a key in an array of bytes in 122 | key[L] where L is 16, 24 or 32 bytes for key lengths of 128, 123 | 192, and 256 bits respectively. They then encrypts the input 124 | data, in[] with this key and put the reult in the output array 125 | out[]. In addition, the second key array, o_key[L], is used 126 | to output the key that is needed by the decryption subroutine 127 | to reverse the encryption operation. The two key arrays can 128 | be the same array but in this case the original key will be 129 | overwritten. 130 | 131 | In the same way, the decryption subroutines output keys that 132 | can be used to reverse their effect when used for encryption. 133 | 134 | Only 128 and 256 bit keys are supported in these 'on the fly' 135 | modes. 136 | */ 137 | 138 | #if defined( AES_ENC_128_OTFK ) 139 | void aes_encrypt_128( const unsigned char in[N_BLOCK], 140 | unsigned char out[N_BLOCK], 141 | const unsigned char key[N_BLOCK], 142 | uint_8t o_key[N_BLOCK] ); 143 | #endif 144 | 145 | #if defined( AES_DEC_128_OTFK ) 146 | void aes_decrypt_128( const unsigned char in[N_BLOCK], 147 | unsigned char out[N_BLOCK], 148 | const unsigned char key[N_BLOCK], 149 | unsigned char o_key[N_BLOCK] ); 150 | #endif 151 | 152 | #if defined( AES_ENC_256_OTFK ) 153 | void aes_encrypt_256( const unsigned char in[N_BLOCK], 154 | unsigned char out[N_BLOCK], 155 | const unsigned char key[2 * N_BLOCK], 156 | unsigned char o_key[2 * N_BLOCK] ); 157 | #endif 158 | 159 | #if defined( AES_DEC_256_OTFK ) 160 | void aes_decrypt_256( const unsigned char in[N_BLOCK], 161 | unsigned char out[N_BLOCK], 162 | const unsigned char key[2 * N_BLOCK], 163 | unsigned char o_key[2 * N_BLOCK] ); 164 | #endif 165 | 166 | #ifdef __cplusplus 167 | } 168 | #endif 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /crypto/cmac.c: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (C) 2009 Lander Casado, Philippas Tsigas 3 | 4 | All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files 8 | (the "Software"), to deal with the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | Redistributions of source code must retain the above copyright notice, 15 | this list of conditions and the following disclaimers. Redistributions in 16 | binary form must reproduce the above copyright notice, this list of 17 | conditions and the following disclaimers in the documentation and/or 18 | other materials provided with the distribution. 19 | 20 | In no event shall the authors or copyright holders be liable for any special, 21 | incidental, indirect or consequential damages of any kind, or any damages 22 | whatsoever resulting from loss of use, data or profits, whether or not 23 | advised of the possibility of damage, and on any theory of liability, 24 | arising out of or in connection with the use or performance of this software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 27 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 31 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 32 | DEALINGS WITH THE SOFTWARE 33 | 34 | *****************************************************************************/ 35 | 36 | //#include 37 | //#include 38 | #include "aes.h" 39 | #include "cmac.h" 40 | #include 41 | //#include 42 | 43 | #define LSHIFT(v, r) do { \ 44 | int i; \ 45 | for (i = 0; i < 15; i++) \ 46 | (r)[i] = (v)[i] << 1 | (v)[i + 1] >> 7; \ 47 | (r)[15] = (v)[15] << 1; \ 48 | } while (0) 49 | 50 | #define XOR(v, r) do { \ 51 | int i; \ 52 | for (i = 0; i < 16; i++) \ 53 | { \ 54 | (r)[i] = (r)[i] ^ (v)[i]; \ 55 | } \ 56 | } while (0) \ 57 | 58 | 59 | #define MIN(a,b) (((a)<(b))?(a):(b)) 60 | 61 | 62 | void AES_CMAC_Init(AES_CMAC_CTX *ctx) 63 | { 64 | memset(ctx->X, 0, sizeof ctx->X); 65 | ctx->M_n = 0; 66 | memset(ctx->rijndael.ksch, '\0', sizeof(ctx->rijndael.ksch)); 67 | } 68 | 69 | void AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const u_int8_t key[AES_CMAC_KEY_LENGTH]) 70 | { 71 | //rijndael_set_key_enc_only(&ctx->rijndael, key, 128); 72 | aes_set_key( key, AES_CMAC_KEY_LENGTH, &ctx->rijndael); 73 | } 74 | 75 | void AES_CMAC_Update(AES_CMAC_CTX *ctx, const u_int8_t *data, u_int len) 76 | { 77 | u_int mlen; 78 | unsigned char in[16]; 79 | 80 | if (ctx->M_n > 0) { 81 | mlen = MIN(16 - ctx->M_n, len); 82 | memcpy(ctx->M_last + ctx->M_n, data, mlen); 83 | ctx->M_n += mlen; 84 | if (ctx->M_n < 16 || len == mlen) 85 | return; 86 | XOR(ctx->M_last, ctx->X); 87 | //rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X); 88 | aes_encrypt( ctx->X, ctx->X, &ctx->rijndael); 89 | data += mlen; 90 | len -= mlen; 91 | } 92 | while (len > 16) { /* not last block */ 93 | 94 | XOR(data, ctx->X); 95 | //rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X); 96 | 97 | memcpy(in, &ctx->X[0], 16); //Bestela ez du ondo iten 98 | aes_encrypt( in, in, &ctx->rijndael); 99 | memcpy(&ctx->X[0], in, 16); 100 | 101 | data += 16; 102 | len -= 16; 103 | } 104 | /* potential last block, save it */ 105 | memcpy(ctx->M_last, data, len); 106 | ctx->M_n = len; 107 | } 108 | 109 | void AES_CMAC_Final(u_int8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx) 110 | { 111 | u_int8_t K[16]; 112 | unsigned char in[16]; 113 | /* generate subkey K1 */ 114 | memset(K, '\0', 16); 115 | 116 | //rijndael_encrypt(&ctx->rijndael, K, K); 117 | 118 | aes_encrypt( K, K, &ctx->rijndael); 119 | 120 | if (K[0] & 0x80) { 121 | LSHIFT(K, K); 122 | K[15] ^= 0x87; 123 | } else 124 | LSHIFT(K, K); 125 | 126 | 127 | if (ctx->M_n == 16) { 128 | /* last block was a complete block */ 129 | XOR(K, ctx->M_last); 130 | 131 | } else { 132 | /* generate subkey K2 */ 133 | if (K[0] & 0x80) { 134 | LSHIFT(K, K); 135 | K[15] ^= 0x87; 136 | } else 137 | LSHIFT(K, K); 138 | 139 | /* padding(M_last) */ 140 | ctx->M_last[ctx->M_n] = 0x80; 141 | while (++ctx->M_n < 16) 142 | ctx->M_last[ctx->M_n] = 0; 143 | 144 | XOR(K, ctx->M_last); 145 | 146 | } 147 | XOR(ctx->M_last, ctx->X); 148 | 149 | //rijndael_encrypt(&ctx->rijndael, ctx->X, digest); 150 | 151 | memcpy(in, &ctx->X[0], 16); //Bestela ez du ondo iten 152 | aes_encrypt(in, digest, &ctx->rijndael); 153 | memset(K, 0, sizeof K); 154 | 155 | } 156 | 157 | -------------------------------------------------------------------------------- /crypto/cmac.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (C) 2009 Lander Casado, Philippas Tsigas 3 | 4 | All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files 8 | (the "Software"), to deal with the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | Redistributions of source code must retain the above copyright notice, 15 | this list of conditions and the following disclaimers. Redistributions in 16 | binary form must reproduce the above copyright notice, this list of 17 | conditions and the following disclaimers in the documentation and/or 18 | other materials provided with the distribution. 19 | 20 | In no event shall the authors or copyright holders be liable for any special, 21 | incidental, indirect or consequential damages of any kind, or any damages 22 | whatsoever resulting from loss of use, data or profits, whether or not 23 | advised of the possibility of damage, and on any theory of liability, 24 | arising out of or in connection with the use or performance of this software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 27 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 31 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 32 | DEALINGS WITH THE SOFTWARE 33 | 34 | *****************************************************************************/ 35 | 36 | #ifndef _CMAC_H_ 37 | #define _CMAC_H_ 38 | 39 | #include "aes.h" 40 | 41 | #ifdef __cplusplus 42 | extern "C" { 43 | #endif 44 | 45 | #define AES_CMAC_KEY_LENGTH 16 46 | #define AES_CMAC_DIGEST_LENGTH 16 47 | 48 | 49 | typedef unsigned char u_int8_t; 50 | typedef unsigned int u_int; 51 | typedef struct _AES_CMAC_CTX { 52 | aes_context rijndael; 53 | u_int8_t X[16]; 54 | u_int8_t M_last[16]; 55 | u_int M_n; 56 | } AES_CMAC_CTX; 57 | 58 | //#include 59 | 60 | //__BEGIN_DECLS 61 | void AES_CMAC_Init(AES_CMAC_CTX * ctx); 62 | void AES_CMAC_SetKey(AES_CMAC_CTX * ctx, const u_int8_t key[AES_CMAC_KEY_LENGTH]); 63 | void AES_CMAC_Update(AES_CMAC_CTX * ctx, const u_int8_t * data, u_int len); 64 | // __attribute__((__bounded__(__string__,2,3))); 65 | void AES_CMAC_Final(u_int8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX * ctx); 66 | // __attribute__((__bounded__(__minbytes__,1,AES_CMAC_DIGEST_LENGTH))); 67 | //__END_DECLS 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif /* _CMAC_H_ */ 74 | 75 | -------------------------------------------------------------------------------- /crypto/lw_crypto.c: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) <2016> 3 | https://github.com/JiapengLi/lorawan-parser 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | *****************************************************************************/ 24 | 25 | #include 26 | #include // memset 27 | #include 28 | 29 | #include "lw_crypto.h" 30 | #include "cmac.h" 31 | 32 | #define LW_KEY_LEN (16) 33 | #define LW_MIC_LEN (4) 34 | 35 | static void lw_write_dw(uint8_t *output, uint32_t input) 36 | { 37 | uint8_t* ptr = output; 38 | 39 | *(ptr++) = (uint8_t)(input), input >>= 8u; 40 | *(ptr++) = (uint8_t)(input), input >>= 8u; 41 | *(ptr++) = (uint8_t)(input), input >>= 8u; 42 | *(ptr) = (uint8_t)(input); 43 | } 44 | 45 | //static uint32_t lw_read_dw(uint8_t *buf) 46 | //{ 47 | // uint32_t ret; 48 | // 49 | // ret = ( (uint32_t)buf[0] << 0 ); 50 | // ret |= ( (uint32_t)buf[1] << 8 ); 51 | // ret |= ( (uint32_t)buf[2] << 16 ); 52 | // ret |= ( (uint32_t)buf[3] << 24 ); 53 | // 54 | // return ret; 55 | //} 56 | 57 | void lw_msg_mic(lw_mic_t* mic, lw_key_t *key) 58 | { 59 | uint8_t b0[LW_KEY_LEN]; 60 | memset(b0, 0 , LW_KEY_LEN); 61 | b0[0] = 0x49; 62 | // todo add LoRaWAN 1.1 support for b0[1..4] 63 | // LoRaWAN 1.1 spec, 4.4: 64 | // If the device is connected to a LoRaWAN1.1 Network Server and the ACK bit of the downlink frame is set, 65 | // meaning this frame is acknowledging an uplink �confirmed� frame, 66 | // then ConfFCnt is the frame counter value modulo 2^16 of the �confirmed� uplink frame that is being acknowledged. 67 | // In all other cases ConfFCnt = 0x0000. 68 | b0[5] = key->link; 69 | 70 | lw_write_dw(b0+6, key->devaddr.data); 71 | lw_write_dw(b0+10, key->fcnt32); 72 | b0[15] = (uint8_t)key->len; 73 | 74 | AES_CMAC_CTX cmacctx; 75 | AES_CMAC_Init(&cmacctx); 76 | AES_CMAC_SetKey(&cmacctx, key->aeskey); 77 | 78 | AES_CMAC_Update(&cmacctx, b0, LW_KEY_LEN); 79 | AES_CMAC_Update(&cmacctx, key->in, key->len); 80 | 81 | uint8_t temp[LW_KEY_LEN]; 82 | AES_CMAC_Final(temp, &cmacctx); 83 | 84 | memcpy(mic->buf, temp, LW_MIC_LEN); 85 | } 86 | 87 | void lw_msg_mic11(lw_mic_t *mic, lw_key_mic11_t *key) { 88 | uint8_t b0[LW_KEY_LEN]; 89 | memset(b0, 0 , LW_KEY_LEN); 90 | b0[0] = 0x49; 91 | // todo add LoRaWAN 1.1 support for b0[1..4] 92 | // LoRaWAN 1.1 spec, 4.4: 93 | // If the device is connected to a LoRaWAN1.1 Network Server and the ACK bit of the downlink frame is set, 94 | // meaning this frame is acknowledging an uplink �confirmed� frame, 95 | // then ConfFCnt is the frame counter value modulo 2^16 of the �confirmed� uplink frame that is being acknowledged. 96 | // In all other cases ConfFCnt = 0x0000. 97 | b0[1] = key->confFCnt & 0xffu; 98 | b0[2] = key->confFCnt >> 0x8u; 99 | b0[3] = key->txDr; 100 | b0[4] = key->txCh; 101 | b0[5] = 0x00; // Dir = 0x00 102 | lw_write_dw(b0+6, key->devaddr->data); // 6 - 9 103 | lw_write_dw(b0+10, key->fcnt32); // 10-13 104 | b0[14] = 0x00; 105 | b0[15] = (uint8_t)key->len; 106 | 107 | /* log("B1: "); 108 | for (int i=0; isnwksintkey); 117 | AES_CMAC_Update(&cmacctx, b0, LW_KEY_LEN); 118 | AES_CMAC_Update(&cmacctx, key->in, key->len); 119 | uint8_t temp[LW_KEY_LEN]; 120 | AES_CMAC_Final(temp, &cmacctx); 121 | memcpy(mic->buf, temp, 2); 122 | 123 | // cmacF = aes128_cmac(FNwkSIntKey, B0 | msg) 124 | b0[1] = b0[2] = b0[3] = b0[4] = 0x00; 125 | /* log("B0: "); 126 | for (int i=0; ifnwksintkey); 132 | AES_CMAC_Update(&cmacctx, b0, LW_KEY_LEN); 133 | AES_CMAC_Update(&cmacctx, key->in, key->len); 134 | AES_CMAC_Final(temp, &cmacctx); 135 | memcpy(mic->buf + 2, temp, 2); 136 | } 137 | 138 | void lw_join_mic(lw_mic_t* mic, lw_key_t *key) 139 | { 140 | AES_CMAC_CTX cmacctx; 141 | AES_CMAC_Init(&cmacctx); 142 | AES_CMAC_SetKey(&cmacctx, key->aeskey); 143 | 144 | AES_CMAC_Update(&cmacctx, key->in, key->len); 145 | 146 | uint8_t temp[LW_KEY_LEN]; 147 | AES_CMAC_Final(temp, &cmacctx); 148 | 149 | memcpy(mic->buf, temp, LW_MIC_LEN); 150 | } 151 | 152 | // Use to generate JoinAccept Payload 153 | int lw_join_encrypt(uint8_t *out, lw_key_t *key) 154 | { 155 | if((key->len == 0) || (key->len%LW_KEY_LEN != 0)){ 156 | return -1; 157 | } 158 | 159 | aes_context aesContext; 160 | 161 | aes_set_key(key->aeskey, LW_KEY_LEN, &aesContext); 162 | 163 | // Check if optional CFList is included 164 | int i; 165 | for(i=0; ilen; i+=LW_KEY_LEN){ 166 | aes_decrypt( key->in + i, out + i, &aesContext ); 167 | } 168 | 169 | return key->len; 170 | } 171 | 172 | // Use to decrypt JoinAccept Payload 173 | int lw_join_decrypt(uint8_t *out, lw_key_t *key) 174 | { 175 | if((key->len == 0) || (key->len%LW_KEY_LEN != 0)){ 176 | return -1; 177 | } 178 | 179 | aes_context aesContext; 180 | 181 | aes_set_key(key->aeskey, LW_KEY_LEN, &aesContext); 182 | 183 | // Check if optional CFList is included 184 | int i; 185 | for(i=0; ilen; i+=LW_KEY_LEN){ 186 | aes_encrypt( key->in + i, out + i, &aesContext ); 187 | } 188 | 189 | return key->len; 190 | } 191 | 192 | static void lw_block_xor(uint8_t const l[], uint8_t const r[], uint8_t out[], uint16_t bytes) 193 | { 194 | uint8_t const* lptr = l; 195 | uint8_t const* rptr = r; 196 | uint8_t* optr = out; 197 | uint8_t const* const end = out + bytes; 198 | 199 | for (;optr < end; lptr++, rptr++, optr++) 200 | *optr = *lptr ^ *rptr; 201 | } 202 | 203 | int lw_encrypt(uint8_t *out, lw_key_t *key) 204 | { 205 | if (key->len == 0) 206 | return -1; 207 | 208 | uint8_t A[LW_KEY_LEN]; 209 | 210 | uint16_t const over_hang_bytes = key->len%LW_KEY_LEN; 211 | int blocks = key->len/LW_KEY_LEN; 212 | if (over_hang_bytes) { 213 | ++blocks; 214 | } 215 | 216 | memset(A, 0, LW_KEY_LEN); 217 | 218 | A[0] = 0x01; //encryption flags 219 | A[5] = key->link; 220 | 221 | lw_write_dw(A+6, key->devaddr.data); 222 | lw_write_dw(A+10, key->fcnt32); 223 | 224 | uint8_t const* blockInput = key->in; 225 | uint8_t* blockOutput = out; 226 | uint16_t i; 227 | for(i = 1; i <= blocks; i++, blockInput += LW_KEY_LEN, blockOutput += LW_KEY_LEN){ 228 | A[15] = (uint8_t)(i); 229 | 230 | aes_context aesContext; 231 | aes_set_key(key->aeskey, LW_KEY_LEN, &aesContext); 232 | 233 | uint8_t S[LW_KEY_LEN]; 234 | aes_encrypt(A, S, &aesContext); 235 | 236 | uint16_t bytes_to_encrypt; 237 | if ((i < blocks) || (over_hang_bytes == 0)) 238 | bytes_to_encrypt = LW_KEY_LEN; 239 | else 240 | bytes_to_encrypt = over_hang_bytes; 241 | 242 | lw_block_xor(S, blockInput, blockOutput, bytes_to_encrypt); 243 | } 244 | return key->len; 245 | } 246 | 247 | 248 | void lw_get_skeys(uint8_t *nwkskey, uint8_t *appskey, lw_skey_seed_t *seed) 249 | { 250 | aes_context aesContext; 251 | uint8_t b[LW_KEY_LEN]; 252 | 253 | memset(&aesContext, 0, sizeof(aesContext)); 254 | memset(b, 0, LW_KEY_LEN); 255 | b[1] = (uint8_t)(seed->anonce.data>>0u); 256 | b[2] = (uint8_t)(seed->anonce.data>>8u); 257 | b[3] = (uint8_t)(seed->anonce.data>>16u); 258 | b[4] = (uint8_t)(seed->netid.data>>0u); 259 | b[5] = (uint8_t)(seed->netid.data>>8u); 260 | b[6] = (uint8_t)(seed->netid.data>>16u); 261 | b[7] = (uint8_t)(seed->dnonce.data>>0u); 262 | b[8] = (uint8_t)(seed->dnonce.data>>8u); 263 | 264 | b[0] = 0x01; 265 | aes_set_key(seed->aeskey, LW_KEY_LEN, &aesContext); 266 | aes_encrypt( b, nwkskey, &aesContext ); 267 | 268 | b[0] = 0x02; 269 | aes_set_key(seed->aeskey, LW_KEY_LEN, &aesContext); 270 | aes_encrypt( b, appskey, &aesContext ); 271 | } 272 | 273 | void lw_get_skeys_11(uint8_t *FNwkSntKey, uint8_t* SNwkSIntKey, uint8_t* NwkSEncKey, uint8_t *AppSKey, lw_skey_seed_11_t *seed) 274 | { 275 | aes_context aesContext; 276 | uint8_t b[LW_KEY_LEN]; 277 | 278 | memset(&aesContext, 0, sizeof(aesContext)); 279 | memset(b, 0, LW_KEY_LEN); 280 | b[1] = (uint8_t)(seed->jnonce.data>>0u); 281 | b[2] = (uint8_t)(seed->jnonce.data>>8u); 282 | b[3] = (uint8_t)(seed->jnonce.data>>16u); 283 | b[4] = seed->joineui[7]; 284 | b[5] = seed->joineui[6]; 285 | b[6] = seed->joineui[5]; 286 | b[7] = seed->joineui[4]; 287 | b[8] = seed->joineui[3]; 288 | b[9] = seed->joineui[2]; 289 | b[10] = seed->joineui[1]; 290 | b[11] = seed->joineui[0]; 291 | b[12] = (uint8_t)(seed->dnonce.data>>0u); 292 | b[13] = (uint8_t)(seed->dnonce.data>>8u); 293 | 294 | b[0] = 0x01; 295 | aes_set_key(seed->nwkkey, LW_KEY_LEN, &aesContext); 296 | aes_encrypt(b, FNwkSntKey, &aesContext); 297 | 298 | b[0] = 0x02; 299 | aes_set_key(seed->appkey, LW_KEY_LEN, &aesContext); 300 | aes_encrypt(b, AppSKey, &aesContext); 301 | 302 | b[0] = 0x03; 303 | aes_set_key(seed->nwkkey, LW_KEY_LEN, &aesContext); 304 | aes_encrypt(b, SNwkSIntKey, &aesContext); 305 | 306 | b[0] = 0x04; 307 | aes_set_key(seed->nwkkey, LW_KEY_LEN, &aesContext); 308 | aes_encrypt(b, NwkSEncKey, &aesContext); 309 | } 310 | 311 | /** 312 | * En- or decrypt FOpts. Only used for LoRaWAN >= 1.1 313 | * @param data 314 | * @param dataLen 315 | * @param key 316 | * @param isUplink 317 | * @param devaddr 318 | * @param cnt 319 | */ 320 | void encrypt_fopts(uint8_t *data, uint8_t dataLen, uint8_t *key, bool aFCntDown, bool isUplink, lw_devaddr_t *devaddr, 321 | uint32_t cnt) { 322 | lobaroASSERT(dataLen <= 15); 323 | uint8_t A[16]; 324 | A[0] = 0x01; 325 | A[1] = A[2] = A[3] = 0x00; 326 | A[4] = (aFCntDown ? 0x02 : 0x01); 327 | A[5] = (isUplink ? 0 : 1); 328 | lw_write_dw(A + 6, devaddr->data); 329 | lw_write_dw(A + 10, cnt); 330 | A[14] = 0x00; 331 | A[15] = 0x01; 332 | 333 | aes_context aesContext; 334 | aes_set_key(key, LW_KEY_LEN, &aesContext); 335 | uint8_t S[16]; 336 | aes_encrypt(A, S, &aesContext); 337 | 338 | for (uint8_t i=0; i 3 | https://github.com/JiapengLi/lorawan-parser 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | *****************************************************************************/ 24 | #include 25 | 26 | #ifndef DRV_LOBAWAN_LW_CRYPTO_H_ 27 | #define DRV_LOBAWAN_LW_CRYPTO_H_ 28 | 29 | typedef union{ 30 | uint32_t data; 31 | uint8_t buf[4]; 32 | struct{ 33 | #ifdef ENABLE_BIG_ENDIAN 34 | uint32_t nwkaddr : 25; 35 | uint32_t nwkid : 7; 36 | #else 37 | uint32_t nwkid : 7; 38 | uint32_t nwkaddr : 25; 39 | #endif 40 | }bits; 41 | }__attribute__((packed)) lw_devaddr_t; 42 | 43 | typedef union{ 44 | uint32_t data; 45 | uint8_t buf[4]; 46 | }__attribute__((packed)) lw_mic_t; 47 | 48 | typedef enum{ 49 | LW_UPLINK = 0, 50 | LW_DOWNLINK = 1, 51 | }lw_link_t; 52 | 53 | typedef union{ 54 | uint32_t data; 55 | }__attribute__((packed)) lw_anonce_t; 56 | 57 | typedef union{ 58 | uint16_t data; 59 | }__attribute__((packed)) lw_dnonce_t; 60 | 61 | typedef lw_anonce_t lw_netid_t; 62 | 63 | typedef struct{ 64 | uint8_t *aeskey; 65 | lw_anonce_t anonce; 66 | lw_netid_t netid; 67 | lw_dnonce_t dnonce; 68 | }lw_skey_seed_t; 69 | 70 | typedef struct{ 71 | uint8_t *nwkkey; 72 | uint8_t *appkey; 73 | lw_anonce_t jnonce; 74 | uint8_t *joineui; 75 | lw_dnonce_t dnonce; 76 | }lw_skey_seed_11_t; 77 | 78 | typedef struct{ 79 | uint8_t *aeskey; 80 | const uint8_t *in; 81 | uint16_t len; 82 | lw_devaddr_t devaddr; 83 | lw_link_t link; 84 | uint32_t fcnt32; 85 | }lw_key_t; 86 | 87 | typedef struct{ 88 | uint8_t *snwksintkey; 89 | uint8_t *fnwksintkey; 90 | uint8_t *in; 91 | uint16_t len; 92 | lw_devaddr_t *devaddr; 93 | uint32_t fcnt32; 94 | uint16_t confFCnt; 95 | uint8_t txDr; 96 | uint8_t txCh; 97 | }lw_key_mic11_t; 98 | 99 | void lw_msg_mic(lw_mic_t* mic, lw_key_t *key); 100 | void lw_msg_mic11(lw_mic_t *mic, lw_key_mic11_t *key); 101 | void lw_join_mic(lw_mic_t* mic, lw_key_t *key); 102 | int lw_encrypt(uint8_t *out, lw_key_t *key); 103 | int lw_join_decrypt(uint8_t *out, lw_key_t *key); 104 | int lw_join_encrypt(uint8_t *out, lw_key_t *key); 105 | void lw_get_skeys(uint8_t *nwkskey, uint8_t *appskey, lw_skey_seed_t *seed); 106 | void lw_get_skeys_11(uint8_t *FNwkSntKey, uint8_t* SNwkSIntKey, uint8_t* NwkSEncKey, uint8_t *AppSKey, lw_skey_seed_11_t *seed); 107 | 108 | void encrypt_fopts(uint8_t *data, uint8_t dataLen, uint8_t *key, bool aFCntDown, bool isUplink, lw_devaddr_t *devaddr, uint32_t cnt); 109 | 110 | #endif /* DRV_LOBAWAN_LW_CRYPTO_H_ */ 111 | -------------------------------------------------------------------------------- /lw_packets.c: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 Theodor Tobias Rohde (tr@lobaro.com) 3 | Lobaro - Industrial IoT Solutions 4 | www.lobaro.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | *****************************************************************************/ 25 | #include 26 | #include 27 | #include // for memcpy 28 | #include // for NULL 29 | 30 | #ifndef lobaroASSERT 31 | 32 | #include 33 | #include 34 | 35 | #if configUSE_FREERTOS == 1 36 | 37 | #include "FreeRTOSConfig.h" 38 | 39 | #define lobaroASSERT(x) configASSERT(x) 40 | #else 41 | #define lobaroASSERT(x) assert(x) 42 | #endif 43 | #endif 44 | 45 | #include "crypto/lw_crypto.h" 46 | #include "lw_packets.h" 47 | 48 | #include "module_logging.h" 49 | 50 | #if configLOG_LOBAWAN == 1 51 | #define LOG(...) lib.api.LogInfo(__VA_ARGS__) 52 | #else 53 | #define LOG(...) {} 54 | #endif 55 | 56 | typedef struct { 57 | lwPackets_api_t api; 58 | lwPackets_state_t state; 59 | bool initDone; 60 | } lwPacketsLib_t; 61 | 62 | static lwPacketsLib_t lib = {.initDone = false}; // holds external dependencies 63 | 64 | static uint16_t parseUInt16LittleEndian(const uint8_t *bytes) { 65 | return (((uint16_t) bytes[0]) << 0u) | (((uint16_t) bytes[1]) << 8u); 66 | } 67 | 68 | static uint32_t parseUInt32LittleEndian(const uint8_t *bytes) { 69 | return (((uint32_t) bytes[0]) << 0u) | (((uint32_t) bytes[1]) << 8u) | (((uint32_t) bytes[2]) << 16u) | (((uint32_t) bytes[3]) << 24u); 70 | } 71 | 72 | // EUI are 8 bytes multi-octet fields and are transmitted as little endian. 73 | static void convertInPlaceEUI64bufLittleEndian(uint8_t *eui8buf) { 74 | uint8_t tmp[8]; 75 | if (eui8buf) { 76 | memcpy(tmp, eui8buf, 8); 77 | for (int i = 0; i < 8; i++) { 78 | eui8buf[i] = tmp[7 - i]; 79 | } 80 | } 81 | } 82 | 83 | static void logNothingDummy(const char *format, ...) { 84 | return; 85 | // example log function may be implemented by app/user (#include , #include ) : 86 | // char buffer[100]; 87 | // va_list args; 88 | // va_start(args, format); 89 | // int len = vsnprintf(buffer, sizeof(buffer), format, args); 90 | // if (len > 100 - 1) { 91 | // strcpy(&buffer[100 - 5], "...\n"); 92 | // } 93 | // va_end(args); 94 | // puts(buffer); // or custom uart puts 95 | } 96 | 97 | void LoRaWAN_PacketsUtil_Init(lwPackets_api_t api, lwPackets_state_t state) { 98 | lib.api = api; 99 | lib.state = state; 100 | 101 | if (lib.api.LogError == NULL) { 102 | lib.api.LogError = logNothingDummy; 103 | } 104 | 105 | if (lib.api.LogInfo == NULL) { 106 | lib.api.LogInfo = logNothingDummy; 107 | } 108 | 109 | if (lib.api.free == NULL || lib.api.malloc == NULL) { 110 | LOG_INFO("LW Packets: using c malloc and free default\n"); 111 | lib.api.free = free; // from 112 | lib.api.malloc = malloc; // from 113 | } 114 | 115 | lib.initDone = true; 116 | } 117 | 118 | 119 | static const char *mhdrString(MHDR_Mtype_t t) { 120 | switch (t) { 121 | case MTYPE_JOIN_REQUEST: 122 | return "JOIN_REQUEST"; 123 | case MTYPE_JOIN_ACCEPT: 124 | return "JOIN_ACCEPT"; 125 | case MTYPE_UNCONFIRMED_DATA_UP: 126 | return "UNCONFIRMED_DATA_UP"; 127 | case MTYPE_UNCONFIRMED_DATA_DOWN: 128 | return "UNCONFIRMED_DATA_DOWN"; 129 | case MTYPE_CONFIRMED_DATA_UP: 130 | return "CONFIRMED_DATA_UP"; 131 | case MTYPE_CONFIRMED_DATA_DOWN: 132 | return "CONFIRMED_DATA_DOWN"; 133 | case MTYPE_REJOIN_REQUEST: 134 | return "REJOIN_REQUEST"; 135 | case MTYPE_PROPRIETARY: 136 | return "PROPRIETARY"; 137 | default: 138 | return "UNKNOWN"; 139 | } 140 | } 141 | 142 | // note that MIC can only be printed correctly after marshal was called on the packet 143 | void lorawan_logLoraPacket(lorawan_packet_t *p, bool uplink) { 144 | LOG("\nLoRa| LoRaWAN Packet (%s)\n", uplink ? "Uplink" : "Downlink"); 145 | LOG("LoRa| --------------\n"); 146 | LOG("LoRa| MIC: %08X\n", p->MIC); // LCTT prints the MIC in inverted byte order ... 147 | LOG("LoRa| MHDR: %s v%d\n", mhdrString(p->MHDR.type), p->MHDR.version); 148 | // TODO: We only support MACPayload 149 | LOG("LoRa| BODY:\n"); 150 | LOG("LoRa| - mac.port: %d\n", p->BODY.MACPayload.FPort); 151 | LOG("LoRa| - mac.payloadLength: %d\n", p->BODY.MACPayload.payloadLength); 152 | LOG("LoRa| - mac.FCnt16: %d\n", p->BODY.MACPayload.FHDR.FCnt16); 153 | LOG("LoRa| - mac.DevAddr: %08x\n", p->BODY.MACPayload.FHDR.DevAddr); 154 | 155 | if (uplink) { 156 | // Uplink 157 | LOG("LoRa| - FCtrl: ADR %d, ADRACKReq %d, ACK %d, ClassB %d, FOptsLen %d\n", 158 | p->BODY.MACPayload.FHDR.FCtrl.uplink.ADR, 159 | p->BODY.MACPayload.FHDR.FCtrl.uplink.ADRACKReq, 160 | p->BODY.MACPayload.FHDR.FCtrl.uplink.ACK, 161 | p->BODY.MACPayload.FHDR.FCtrl.uplink.ClassB, 162 | p->BODY.MACPayload.FHDR.FCtrl.uplink.FOptsLen 163 | ); 164 | if (p->BODY.MACPayload.FHDR.FCtrl.uplink.FOptsLen > 0) { 165 | LOG("LoRa| - FOpts: "); 166 | for (int i = 0; i < p->BODY.MACPayload.FHDR.FCtrl.uplink.FOptsLen; i++) { 167 | LOG("%02x", p->BODY.MACPayload.FHDR.FOpts[i]); 168 | } 169 | LOG("\n"); 170 | } 171 | } else { 172 | // Downlink 173 | LOG("LoRa| - FCtrl: ADR %d, RFU: %d, ACK %d, FPending %d, FOptsLen %d\n", 174 | p->BODY.MACPayload.FHDR.FCtrl.downlink.ADR, 175 | p->BODY.MACPayload.FHDR.FCtrl.downlink.RFU, 176 | p->BODY.MACPayload.FHDR.FCtrl.downlink.ACK, 177 | p->BODY.MACPayload.FHDR.FCtrl.downlink.FPending, 178 | p->BODY.MACPayload.FHDR.FCtrl.downlink.FOptsLen 179 | ); 180 | if (p->BODY.MACPayload.FHDR.FCtrl.downlink.FOptsLen > 0) { 181 | LOG("LoRa| - FOpts: "); 182 | for (int i = 0; i < p->BODY.MACPayload.FHDR.FCtrl.downlink.FOptsLen; i++) { 183 | LOG("%02x", p->BODY.MACPayload.FHDR.FOpts[i]); 184 | } 185 | LOG("\n"); 186 | } 187 | } 188 | // Log out payload as hex 189 | LOG("LoRa| PAYLOAD:"); 190 | if (p->BODY.MACPayload.payloadLength == 0) { 191 | LOG(" [none]"); 192 | } else { 193 | for (uint16_t i = 0; i < p->BODY.MACPayload.payloadLength; i++) { 194 | LOG(" %02x", p->pPayload[i]); 195 | } 196 | } 197 | LOG("\n"); 198 | } 199 | 200 | 201 | lorawan_packet_t *LoRaWAN_NewPacket(const uint8_t *payload, uint8_t length) { 202 | lobaroASSERT(lib.initDone); 203 | lobaroASSERT(length <= 222); // max payload size of lorawan EU868 (see 2.1.6 lorawan 1.1 regional parameters) 204 | 205 | lorawan_packet_t *packet = (lorawan_packet_t *) lib.api.malloc(sizeof(lorawan_packet_t)); 206 | if (packet == NULL) { 207 | return NULL; 208 | } 209 | memset(packet, 0, sizeof(lorawan_packet_t)); 210 | 211 | if (payload != NULL && length > 0) { 212 | uint8_t *dataCpy = (uint8_t *) lib.api.malloc(length); 213 | if (dataCpy == NULL) { 214 | lib.api.free(packet); 215 | return NULL; 216 | } 217 | memcpy(dataCpy, payload, length); 218 | 219 | packet->BODY.MACPayload.payloadLength = length; 220 | packet->pPayload = dataCpy; // just to get sure if user creates a packet with payload but uses it as join packet afterwards (see also DeletePacket fkt) 221 | } 222 | 223 | // static field 224 | packet->MHDR.version = LORAWAN_R1; 225 | return packet; 226 | } 227 | 228 | void LoRaWAN_DeletePayload(lorawan_packet_t *packet) { 229 | lobaroASSERT(lib.initDone); 230 | 231 | // don't rely on packets MHDR type if there is any payload memory to free 232 | if (packet != NULL && packet->pPayload != NULL) { 233 | lib.api.free(packet->pPayload); 234 | packet->pPayload = NULL; 235 | packet->BODY.MACPayload.payloadLength = 0; 236 | } 237 | } 238 | 239 | void LoRaWAN_DeletePacket(lorawan_packet_t *packet) { 240 | lobaroASSERT(lib.initDone); 241 | 242 | if (packet == NULL) { 243 | return; 244 | } 245 | 246 | LoRaWAN_DeletePayload(packet); 247 | lib.api.free(packet); 248 | } 249 | 250 | // Marshal the packet into a given buffer, returns the actual size 251 | // Returns -1 when the buffer is too small 252 | 253 | uint8_t LoRaWAN_MarshalPacket(lorawan_packet_t *packet, uint8_t *outBuffer, uint8_t bufferSize) { 254 | uint8_t pos = 0; 255 | int optLen = 0; 256 | lw_mic_t mic; // 4 byte lorawan message integrity code (last bytes of PHYPayload) 257 | lw_key_t lw_key; // lorawan aes de/encrypt input struct (see crypto.c for details) 258 | 259 | lobaroASSERT(lib.initDone); 260 | 261 | if (bufferSize < 4) { 262 | return pos; 263 | } 264 | 265 | // MHDR 266 | outBuffer[pos++] = (packet->MHDR.type << 5u) | (packet->MHDR.version); 267 | 268 | if (packet->MHDR.type == MTYPE_UNCONFIRMED_DATA_UP 269 | || packet->MHDR.type == MTYPE_CONFIRMED_DATA_UP) { 270 | lw_key.link = LW_UPLINK; 271 | // marshaling continues below if 272 | 273 | } else if (packet->MHDR.type == MTYPE_UNCONFIRMED_DATA_DOWN 274 | || packet->MHDR.type == MTYPE_CONFIRMED_DATA_DOWN) { 275 | lw_key.link = LW_DOWNLINK; 276 | // marshaling continues below if 277 | 278 | } else if (packet->MHDR.type == MTYPE_JOIN_REQUEST) { 279 | // EUI are 8 bytes multi-octet fields and are transmitted as little endian. (LoRaWAN Specification) 280 | // -> if the EUI-64 is 70-B3-D5-7E-F0-00-48-9C it would be in the air as 9C-48-00... 281 | // convertInPlaceEUI64bufLittleEndian performs this byte order inversion in place 282 | 283 | if (bufferSize < pos + 8) { 284 | return 0; 285 | } 286 | memcpy(outBuffer + pos, lib.state.pDevCfg->JoinEUI, 8); 287 | convertInPlaceEUI64bufLittleEndian(outBuffer + pos); 288 | pos += 8; 289 | 290 | if (bufferSize < pos + 8) { 291 | return 0; 292 | } 293 | memcpy(outBuffer + pos, lib.state.pDevCfg->DevEUI, 8); 294 | convertInPlaceEUI64bufLittleEndian(outBuffer + pos); 295 | pos += 8; 296 | 297 | if (bufferSize < pos + 2) { 298 | return 0; 299 | } 300 | outBuffer[pos++] = (uint8_t) (lib.state.pDevCfg->DevNonce & 0xffu); 301 | outBuffer[pos++] = (uint8_t) (lib.state.pDevCfg->DevNonce >> 8u); 302 | 303 | lw_key.aeskey = lib.state.pDevCfg->NwkKey; 304 | lw_key.in = outBuffer; 305 | lw_key.len = pos; 306 | lw_join_mic(&mic, &lw_key); 307 | 308 | if (bufferSize < pos + 4) { 309 | return 0; 310 | } 311 | memcpy(outBuffer + pos, mic.buf, 4); 312 | packet->MIC = mic.data; 313 | pos += 4; 314 | 315 | return pos; 316 | 317 | } else { 318 | LOG_ERROR("LoRa| unknown msg type for marshaling!"); 319 | return 0; 320 | } 321 | 322 | // FHDR 323 | if (bufferSize < pos + 4) { 324 | return 0; 325 | } 326 | outBuffer[pos++] = (uint8_t) (packet->BODY.MACPayload.FHDR.DevAddr & 0xffu); 327 | outBuffer[pos++] = (uint8_t) (packet->BODY.MACPayload.FHDR.DevAddr >> 8u); 328 | outBuffer[pos++] = (uint8_t) (packet->BODY.MACPayload.FHDR.DevAddr >> 16u); 329 | outBuffer[pos++] = (uint8_t) (packet->BODY.MACPayload.FHDR.DevAddr >> 24u); 330 | lw_key.devaddr.data = packet->BODY.MACPayload.FHDR.DevAddr; 331 | 332 | if (lw_key.link == LW_UPLINK) { 333 | // uplink packet 334 | if (bufferSize < pos + 1) { 335 | return 0; 336 | } 337 | outBuffer[pos++] = (packet->BODY.MACPayload.FHDR.FCtrl.uplink.ADR << 7u) 338 | | (packet->BODY.MACPayload.FHDR.FCtrl.uplink.ADRACKReq << 6u) 339 | | (packet->BODY.MACPayload.FHDR.FCtrl.uplink.ACK << 5u) 340 | | (packet->BODY.MACPayload.FHDR.FCtrl.uplink.FOptsLen); 341 | 342 | optLen = packet->BODY.MACPayload.FHDR.FCtrl.uplink.FOptsLen; 343 | } else { 344 | lobaroASSERT(false); // "join accept, request not implemented yet! (we aren't a network server yet!)"); 345 | } 346 | 347 | // Little endian 348 | if (bufferSize < pos + 2) { 349 | return 0; 350 | } 351 | outBuffer[pos++] = (uint8_t) (packet->BODY.MACPayload.FHDR.FCnt16 & 0xffu); 352 | outBuffer[pos++] = (uint8_t) (packet->BODY.MACPayload.FHDR.FCnt16 >> 8u); 353 | //lw_key.fcnt32 = packet->BODY.MACPayload.FHDR.FCnt16; 354 | lobaroASSERT((lib.state.pFCntCtrl->FCntUp & 0xffffu) == packet->BODY.MACPayload.FHDR.FCnt16); 355 | lw_key.fcnt32 = lib.state.pFCntCtrl->FCntUp; 356 | 357 | if (lib.state.pDevCfg->LorawanVersion >= LORAWAN_VERSION_1_1) { 358 | // LOG_INFO("v1.1, enc FOpts\n"); 359 | // FOpts are only encrypted starting v1.1 (spec fails to state no encryption for 1.0) 360 | // see https://lora-alliance.org/sites/default/files/2019-08/00001.002.00001.001.cr-fcntdwn-usage-in-fopts-encryption-v2-r1.pdf 361 | encrypt_fopts( 362 | packet->BODY.MACPayload.FHDR.FOpts, 363 | packet->BODY.MACPayload.FHDR.FCtrl.uplink.FOptsLen, 364 | lib.state.pDevCfg->NwkSEncKey, 365 | false, 366 | true, 367 | &lw_key.devaddr, 368 | lw_key.fcnt32 369 | ); 370 | } else { 371 | // LOG_INFO("v1.0, DON'T FOpts\n"); 372 | } 373 | 374 | if (optLen) { 375 | if (bufferSize < pos + optLen) { 376 | return 0; 377 | } 378 | memcpy(outBuffer + pos, packet->BODY.MACPayload.FHDR.FOpts, optLen); 379 | pos += optLen; 380 | } 381 | 382 | // encrypt payload (if present) 383 | if (packet->BODY.MACPayload.payloadLength != 0) { 384 | if (bufferSize < pos + 1) { 385 | return 0; 386 | } 387 | outBuffer[pos++] = packet->BODY.MACPayload.FPort; 388 | if (packet->BODY.MACPayload.FPort == 0) { 389 | lw_key.aeskey = lib.state.pDevCfg->NwkSEncKey; // todo maybe add this as parameter? 390 | } else { 391 | lw_key.aeskey = lib.state.pDevCfg->AppSKey; 392 | } 393 | 394 | lw_key.in = packet->pPayload; 395 | lw_key.len = packet->BODY.MACPayload.payloadLength; 396 | 397 | int cryptedPayloadLength = lw_encrypt(outBuffer + pos, &lw_key); 398 | pos += cryptedPayloadLength; 399 | if (bufferSize < pos) { // TODO: This is too late, we should predict or limit the buffer inside lw_encrypt 400 | lobaroASSERT(false); 401 | return 0; 402 | } 403 | } 404 | 405 | // 4 byte MIC 406 | if (bufferSize < pos + 4) { 407 | return 0; 408 | } 409 | 410 | // note that this code is not run for OTAA Join Requests (see return above!) 411 | if (lib.state.pDevCfg->LorawanVersion == LORAWAN_VERSION_1_0) { 412 | // v1.0 has MIC calculated with the only used key [spec:1.1:800] 413 | lw_key.aeskey = lib.state.pDevCfg->FNwkSIntKey; 414 | lw_key.in = outBuffer; 415 | lw_key.len = pos; 416 | lw_msg_mic(&mic, &lw_key); 417 | memcpy(outBuffer + pos, mic.buf, 4); 418 | pos += 4; 419 | } else if (lib.state.pDevCfg->LorawanVersion == LORAWAN_VERSION_1_1) { 420 | // v1.1 uses forwarding and serving network key for MIC and uses a combination of both [spec:1.1:803] 421 | lw_key_mic11_t lw_key11; 422 | lw_key11.fnwksintkey = lib.state.pDevCfg->FNwkSIntKey; 423 | lw_key11.snwksintkey = lib.state.pDevCfg->SNwkSIntKey; 424 | lw_key11.devaddr = &lw_key.devaddr; // just copy from other lw_key version 425 | lw_key11.fcnt32 = lw_key.fcnt32; 426 | lw_key11.confFCnt = packet->UplinkMeta.confFCnt; 427 | lw_key11.txDr = packet->UplinkMeta.txDr; 428 | lw_key11.txCh = packet->UplinkMeta.txCh; 429 | lw_key11.in = outBuffer; 430 | lw_key11.len = pos; 431 | lw_msg_mic11(&mic, &lw_key11); 432 | memcpy(outBuffer + pos, mic.buf, 4); 433 | pos += 4; 434 | } else { 435 | lobaroASSERT(false); 436 | } 437 | return pos; 438 | } 439 | 440 | // Like LoRaWAN_NewPacket but takes a marshaled packet as input 441 | // MUST be freed with LoRaWAN_DeletePacket 442 | // data is the raw packet as produced by LoRaWAN_MarshalPacket 443 | lorawan_packet_t *LoRaWAN_UnmarshalPacketFor(const uint8_t *dataToParse, uint8_t length, uint32_t address) { // todo add keys as parameter 444 | uint8_t idx; 445 | lw_mic_t micCalc; // calculated mic 446 | lw_key_t lw_key; 447 | 448 | lobaroASSERT(lib.initDone); 449 | if (length < 3) { 450 | return NULL; 451 | } 452 | 453 | lorawan_packet_t *packet = LoRaWAN_NewPacket(NULL, 0); 454 | if (packet == NULL) { 455 | LOG_ERROR("LoRa| OOM\n"); 456 | return NULL; 457 | } 458 | 459 | // MHDR 460 | idx = 0; 461 | packet->MHDR.type = dataToParse[idx] >> 5u; 462 | packet->MHDR.version = dataToParse[idx] & 0x3u; 463 | idx++; 464 | 465 | if (packet->MHDR.type == MTYPE_PROPRIETARY) { 466 | LOG_ERROR("LoRa| Got proprietary MHDR -> drop packet\n"); 467 | LoRaWAN_DeletePacket(packet); 468 | return NULL; 469 | } 470 | 471 | if (address != 0) { 472 | // receive for specific address can never be a join accept 473 | if (packet->MHDR.type == MTYPE_JOIN_ACCEPT) { 474 | LOG_INFO("LoRa| join accept -> drop packet\n"); 475 | LoRaWAN_DeletePacket(packet); 476 | return NULL; 477 | } 478 | 479 | } 480 | 481 | switch (packet->MHDR.type) { 482 | case MTYPE_UNCONFIRMED_DATA_DOWN: 483 | case MTYPE_CONFIRMED_DATA_DOWN: 484 | idx = 1; // skip already parsed MHDR 485 | 486 | // get devAdr since we need it for MIC check 487 | packet->BODY.MACPayload.FHDR.DevAddr = parseUInt32LittleEndian(&(dataToParse[idx])); 488 | idx += 4; 489 | // if we got an address (<>0), we only try to unmarshal messages for that address 490 | if (address != 0) { 491 | if (packet->BODY.MACPayload.FHDR.DevAddr == address) { 492 | LOG_ERROR("LoRa| Received msg for addr %08x, that's me\n", address); 493 | } else { 494 | // that message is not for us, ignore it 495 | LOG_ERROR("LoRa| Received msg for addr %08x (I am %08x), ignoring\n", packet->BODY.MACPayload.FHDR.DevAddr, address); 496 | LoRaWAN_DeletePacket(packet); 497 | return NULL; 498 | } 499 | } 500 | 501 | // Port is needed to pick correct counter and key, so we do this first: 502 | packet->BODY.MACPayload.FPort = 0; 503 | const uint8_t FCTRLPOS = 5; 504 | 505 | if (length > FCTRLPOS) { 506 | uint8_t foptslen = dataToParse[FCTRLPOS] & 0xfu; 507 | uint8_t portPos = 1 + 4 + 1 + 2 + foptslen; // MHDR(1) + DevAddr(4) + FCtrl(1) + FCnt(2) + FOpts(foptslen) 508 | if (length - 4 > portPos) { // -4 Bytes for trailing MIC 509 | packet->BODY.MACPayload.FPort = dataToParse[portPos]; 510 | } 511 | } 512 | // LOG_INFO("PORT: %d\n", packet->BODY.MACPayload.FPort); 513 | 514 | uint8_t fctrl = dataToParse[idx]; 515 | idx++; 516 | packet->BODY.MACPayload.FHDR.FCnt16 = parseUInt16LittleEndian(&(dataToParse[idx])); 517 | idx += 2; 518 | 519 | if (packet->BODY.MACPayload.FPort == 0) { 520 | lw_key.aeskey = lib.state.pDevCfg->NwkSEncKey; 521 | } else { 522 | lw_key.aeskey = lib.state.pDevCfg->AppSKey; 523 | } 524 | lw_key.in = (uint8_t *) dataToParse; 525 | lw_key.len = length - 4; 526 | lw_key.devaddr.data = packet->BODY.MACPayload.FHDR.DevAddr; 527 | 528 | uint32_t currFCnt32; 529 | lw_key.link = LW_DOWNLINK; 530 | bool useAFCntDwn = false; 531 | if (lib.state.pDevCfg->LorawanVersion >= LORAWAN_VERSION_1_1) { 532 | // LoRaWAN 1.1 -- separate DL counters 533 | if (packet->BODY.MACPayload.FPort == 0) { 534 | // LOG_INFO("NFCntDwn: %d\n", lib.state.pFCntCtrl->NFCntDwn); 535 | currFCnt32 = lib.state.pFCntCtrl->NFCntDwn; 536 | } else { 537 | // LOG_INFO("AFCntDwn: %d\n", lib.state.pFCntCtrl->AFCntDwn); 538 | currFCnt32 = lib.state.pFCntCtrl->AFCntDwn; 539 | useAFCntDwn = true; 540 | } 541 | } else { 542 | // LoRaWAN 1.0 -- use only one counter 543 | // LOG_INFO("FCntDwn: %d\n", lib.state.pFCntCtrl->NFCntDwn); 544 | currFCnt32 = lib.state.pFCntCtrl->NFCntDwn; 545 | } 546 | packet->BODY.MACPayload.FHDR.FCtrl.downlink.ADR = fctrl >> 7u; 547 | packet->BODY.MACPayload.FHDR.FCtrl.downlink.ACK = (fctrl & (1u << 5u)) >> 5u; 548 | packet->BODY.MACPayload.FHDR.FCtrl.downlink.FPending = (fctrl & (1u << 4u)) >> 4u; 549 | packet->BODY.MACPayload.FHDR.FCtrl.downlink.FOptsLen = (fctrl & 0x0fu); 550 | 551 | 552 | // currFCnt32 holds the next expected FCnt for received packet (since the first FCnt is 0) 553 | uint16_t currFCnt32_LSB = (uint16_t) currFCnt32; 554 | uint16_t currFCnt32_MSB = (uint16_t) (currFCnt32 >> 16u); 555 | // LOG_INFO("Lobawan| counter: %cFCntDwn, current: %08x\n", (useAFCntDwn?'A':'N'), currFCnt32); 556 | // In LoRaWAN 1.. it's allowed to re-transmit the last downlink (due to LCTT) 557 | // TODO: Clarify: In LoRaWAN 1.1 retransmissions are not allowed (but we still allow a retransmission of the last packet yet!) 558 | // See: https://lcttbugs.lora-alliance.com/bugzilla/show_bug.cgi?id=172 559 | // Thus the "- 1" 560 | if (packet->BODY.MACPayload.FHDR.FCnt16 < currFCnt32_LSB - 1) { 561 | // this is either a replay or a 16bit overflow 562 | // we expect overflow, replays will have invalid MIC after overflow (since 32bit counter is different) 563 | currFCnt32_MSB++; 564 | } 565 | 566 | // LoRaWAN 1.0.x only, when 567 | if (lib.state.pDevCfg->LorawanVersion >= LORAWAN_VERSION_1_0) { 568 | const int MAX_FCNT_GAP = 16384; 569 | if (packet->BODY.MACPayload.FHDR.FCnt16 - currFCnt32_LSB > MAX_FCNT_GAP) { 570 | LOG_ERROR("LoRa| Downlink FCnt increased by more than MAX_FCNT_GAP (%d): FCnt=%d expected FCnt=%d -> drop packet\n", 571 | MAX_FCNT_GAP, packet->BODY.MACPayload.FHDR.FCnt16, currFCnt32_LSB); 572 | LoRaWAN_DeletePacket(packet); 573 | return NULL; 574 | } 575 | } 576 | 577 | currFCnt32 = (((uint32_t) currFCnt32_MSB) << 16u) + packet->BODY.MACPayload.FHDR.FCnt16; 578 | lw_key.fcnt32 = currFCnt32; 579 | // LOG_INFO("Lobawan| FCnt16: %04x, FCnt32: %08x\n", packet->BODY.MACPayload.FHDR.FCnt16, currFCnt32); 580 | 581 | // calc & compare mic 582 | packet->MIC = parseUInt32LittleEndian(dataToParse + length - 4); 583 | lw_key.aeskey = lib.state.pDevCfg->SNwkSIntKey; 584 | lw_msg_mic(&micCalc, &lw_key); 585 | 586 | if (micCalc.data != packet->MIC) { // check if mic is ok 587 | LOG_ERROR("LoRa| Data MIC error 0x%8X != 0x%8X (expected) -> drop packet\n", packet->MIC, micCalc.data); 588 | LOG_ERROR("lwKey: fCnt: %d len: %d\n", lw_key.fcnt32, lw_key.len, lw_key.devaddr); 589 | lorawan_logLoraPacket(packet, false); 590 | LoRaWAN_DeletePacket(packet); 591 | return NULL; 592 | } 593 | 594 | // write back counter only if MIC was correct, otherwise replay attacks could corrupt our counter 595 | // counter is set to next expected value 596 | if (useAFCntDwn) { 597 | lib.state.pFCntCtrl->AFCntDwn = currFCnt32 + 1; 598 | } else { 599 | lib.state.pFCntCtrl->NFCntDwn = currFCnt32 + 1; 600 | } 601 | 602 | memcpy(packet->BODY.MACPayload.FHDR.FOpts, &(dataToParse[idx]), packet->BODY.MACPayload.FHDR.FCtrl.downlink.FOptsLen); 603 | if (lib.state.pDevCfg->LorawanVersion >= LORAWAN_VERSION_1_1) { 604 | // TODO: this only for 1.1? 1.1 spec is not specific about this, but i cannot find encryption of FOpts in 1.0 605 | encrypt_fopts( 606 | packet->BODY.MACPayload.FHDR.FOpts, 607 | packet->BODY.MACPayload.FHDR.FCtrl.downlink.FOptsLen, 608 | lib.state.pDevCfg->NwkSEncKey, 609 | useAFCntDwn, 610 | false, 611 | &lw_key.devaddr, 612 | currFCnt32 613 | ); 614 | } 615 | idx += packet->BODY.MACPayload.FHDR.FCtrl.downlink.FOptsLen; 616 | 617 | 618 | // copy other fields & decrypt payload (if present) 619 | uint8_t lengthWithoutPayloadAndPort = (1 + 7 + packet->BODY.MACPayload.FHDR.FCtrl.downlink.FOptsLen + 4); // MHDR(1) + FHDR(7) + FHDR_OPTS(x) + MIC (4) 620 | if (length > lengthWithoutPayloadAndPort) { 621 | // skip port, we did that at the beginning: 622 | idx++; 623 | if (length == lengthWithoutPayloadAndPort + 1) { // no payload, but port 624 | packet->BODY.MACPayload.payloadLength = 0; 625 | LOG_ERROR("LoRa| warn packet with port but without payload\n"); 626 | } else { 627 | packet->BODY.MACPayload.payloadLength = length - 4 - idx; 628 | 629 | if (packet->BODY.MACPayload.FPort == 0) { 630 | lw_key.aeskey = lib.state.pDevCfg->NwkSEncKey; 631 | } else { 632 | lw_key.aeskey = lib.state.pDevCfg->AppSKey; 633 | } 634 | lw_key.in = (uint8_t *) &(dataToParse[idx]); 635 | lw_key.len = packet->BODY.MACPayload.payloadLength; 636 | 637 | packet->pPayload = (uint8_t *) lib.api.malloc(packet->BODY.MACPayload.payloadLength); 638 | 639 | if (packet->pPayload == NULL) { 640 | LOG_ERROR("LoRa| LoRaWAN_UnmarshalPacket OOM!\n"); 641 | LoRaWAN_DeletePacket(packet); 642 | return NULL; 643 | } 644 | 645 | // decrypt by encrypt 646 | if (lw_encrypt(packet->pPayload, &lw_key) <= 0) { 647 | LOG_ERROR("LoRaWAN_UnmarshalPacket decrypt fail\n"); 648 | LoRaWAN_DeletePacket(packet); 649 | return NULL; 650 | } 651 | } 652 | 653 | } else { // no payload, no port, no cry 654 | packet->BODY.MACPayload.payloadLength = 0; 655 | packet->pPayload = NULL; 656 | } 657 | 658 | uint8_t fOptsLen = packet->BODY.MACPayload.FHDR.FCtrl.downlink.FOptsLen; 659 | uint8_t fPort = packet->BODY.MACPayload.FPort; 660 | uint8_t payloadLen = packet->BODY.MACPayload.payloadLength; 661 | 662 | // LoRaWAN 1.1 - 4.3.1.6 Frame options 663 | // 677 MAC commands cannot be simultaneously present in the payload field and the frame 664 | // 678 options field. Should this occur, the device SHALL ignore the frame. 665 | // Do not handle Port 0 with fOpts and payload! -> Required by LCTT 666 | if (fPort == 0 && fOptsLen > 0 && payloadLen > 0) { 667 | LOG_ERROR("LoRa| Port 0: fOptsLen & payloadLen set -> drop packet\n"); 668 | LoRaWAN_DeletePacket(packet); 669 | return NULL; 670 | } 671 | 672 | return packet; 673 | 674 | case MTYPE_JOIN_ACCEPT: 675 | 676 | // MHDR(1) + [sizeof(JoinAccept_t)(12) + optional CFlist(16)] + MIC(4), max len: 33 byte 677 | if (length == 17) { 678 | packet->BODY.JoinAccept.hasCFlist = false; 679 | } else if (length == 17 + 16) { 680 | packet->BODY.JoinAccept.hasCFlist = true; // optional frequency list send by network server 681 | } else { 682 | LOG_ERROR("LoRa| Got JoinRequest with unexpected length -> drop packet\n"); 683 | LoRaWAN_DeletePacket(packet); 684 | return NULL; 685 | } 686 | 687 | // (1) beside MHDR whole the message is encrypted -> decrypt it first 688 | uint8_t decryptedData[33]; // temp buffer 689 | lw_key.aeskey = lib.state.pDevCfg->NwkKey; // TODO: for rejoins, this uses JSEncKey 690 | lw_key.in = dataToParse + 1; // skip MHDR 691 | lw_key.len = length - 1; 692 | decryptedData[0] = dataToParse[0]; // MHDR can be copied as it's not encrypted 693 | int pl_len = lw_join_decrypt(decryptedData + 1, &lw_key); 694 | /* LOG_INFO("Lobawan: uncryp: "); 695 | for (int i=0; i> 7u); 708 | 709 | // (2) check MIC 710 | packet->MIC = parseUInt32LittleEndian(decryptedData + length - 4); 711 | if (useVersion11) { 712 | // LOG_INFO("v1.1\n"); 713 | // JoinReqType | JoinEUI | DevNonce | MHDR | JoinNonce | NetID | DevAddr | DLSettings | RxDelay | CFList 714 | uint8_t bb[48]; // length is 17 or 33, +11 -4 -> 40 -> 48 for padding 715 | memset(bb, 0, 48); 716 | bb[0] = 0xff; // TODO: this is for join - add rejoin requests 717 | memcpy(bb + 1, lib.state.pDevCfg->JoinEUI, 8); 718 | convertInPlaceEUI64bufLittleEndian(bb + 1); 719 | bb[9] = lib.state.pDevCfg->DevNonce & 0xffu; // TODO: is this mixed up? 720 | bb[10] = lib.state.pDevCfg->DevNonce >> 8u; 721 | // bb[10] = lib.state.pDevCfg->DevNonce & 0xffu; // TODO: is this mixed up? 722 | // bb[9] = lib.state.pDevCfg->DevNonce >> 8u; 723 | memcpy(bb + 11, decryptedData, length - 4); 724 | lw_key.aeskey = lib.state.pDevCfg->JSIntKey; 725 | lw_key.in = bb; 726 | lw_key.len = 11 + length - 4; // skip MIC 727 | lw_join_mic(&micCalc, &lw_key); 728 | // TODO: does this work? 729 | } else { 730 | // LOG_INFO("v1.0\n"); 731 | lw_key.aeskey = lib.state.pDevCfg->NwkKey; 732 | lw_key.in = decryptedData; 733 | lw_key.len = length - 4; // skip MIC 734 | lw_join_mic(&micCalc, &lw_key); 735 | } 736 | // LOG_INFO("Lobawan| MIC: calc=%08x, pack=%08x\n", micCalc.data, packet->MIC); 737 | if (micCalc.data != packet->MIC) { // check if mic is ok 738 | LOG_ERROR("LoRa| Join accept mic error -> drop packet\n"); 739 | LoRaWAN_DeletePacket(packet); 740 | return NULL; 741 | } 742 | 743 | // (3) parse fields 744 | idx = 1; // skip already parsed MHDR 745 | packet->BODY.JoinAccept.JoinNonce = decryptedData[idx++]; 746 | packet->BODY.JoinAccept.JoinNonce |= ((uint32_t) decryptedData[idx++] << 8u); 747 | packet->BODY.JoinAccept.JoinNonce |= ((uint32_t) decryptedData[idx++] << 16u); 748 | 749 | packet->BODY.JoinAccept.HomeNetID = decryptedData[idx++]; 750 | packet->BODY.JoinAccept.HomeNetID |= ((uint32_t) decryptedData[idx++] << 8u); 751 | packet->BODY.JoinAccept.HomeNetID |= ((uint32_t) decryptedData[idx++] << 16u); 752 | 753 | packet->BODY.JoinAccept.DevAddr = parseUInt32LittleEndian(&(decryptedData[idx])); 754 | idx += 4; 755 | packet->BODY.JoinAccept.DLsettings.OptNeg = ((decryptedData[idx] & 0x80u) >> 7u); 756 | packet->BODY.JoinAccept.DLsettings.Rx1DRoffset = ((decryptedData[idx] & 0x70u) >> 4u); 757 | packet->BODY.JoinAccept.DLsettings.Rx2DR = (decryptedData[idx] & 0x0fu); 758 | idx++; 759 | 760 | packet->BODY.JoinAccept.RxDelay = decryptedData[idx++]; 761 | 762 | if (packet->BODY.JoinAccept.hasCFlist) { 763 | memcpy(packet->BODY.JoinAccept.CFlist.FreqCH4, decryptedData + idx, 3); 764 | memcpy(packet->BODY.JoinAccept.CFlist.FreqCH5, decryptedData + idx + 3, 3); 765 | memcpy(packet->BODY.JoinAccept.CFlist.FreqCH6, decryptedData + idx + 6, 3); 766 | memcpy(packet->BODY.JoinAccept.CFlist.FreqCH7, decryptedData + idx + 9, 3); 767 | memcpy(packet->BODY.JoinAccept.CFlist.FreqCH8, decryptedData + idx + 12, 3); 768 | } 769 | 770 | // (4) derive keys 771 | if (packet->BODY.JoinAccept.DLsettings.OptNeg) { 772 | // LoRaWAN v1.1 773 | lw_skey_seed_11_t lw_skey_seed; 774 | lw_skey_seed.nwkkey = lib.state.pDevCfg->NwkKey; 775 | lw_skey_seed.appkey = lib.state.pDevCfg->AppKey; 776 | lw_skey_seed.jnonce.data = packet->BODY.JoinAccept.JoinNonce; 777 | lw_skey_seed.joineui = lib.state.pDevCfg->JoinEUI; 778 | lw_skey_seed.dnonce.data = lib.state.pDevCfg->DevNonce; 779 | lw_get_skeys_11( 780 | packet->BODY.JoinAccept.derived_fnwksintkey, 781 | packet->BODY.JoinAccept.derived_snwksintkey, 782 | packet->BODY.JoinAccept.derived_nwksenckey, 783 | packet->BODY.JoinAccept.derived_appskey, 784 | &lw_skey_seed); // todo maybe add as special "payload" to packet? 785 | packet->BODY.JoinAccept.usesVersion11 = true; 786 | } else { 787 | lw_skey_seed_t lw_skey_seed; 788 | lw_skey_seed.aeskey = lib.state.pDevCfg->NwkKey; 789 | lw_skey_seed.anonce.data = packet->BODY.JoinAccept.JoinNonce; 790 | lw_skey_seed.netid.data = packet->BODY.JoinAccept.HomeNetID; 791 | lw_skey_seed.dnonce.data = lib.state.pDevCfg->DevNonce; 792 | lw_get_skeys(packet->BODY.JoinAccept.derived_fnwksintkey, packet->BODY.JoinAccept.derived_appskey, 793 | &lw_skey_seed); // todo maybe add as special "payload" to packet? 794 | packet->BODY.JoinAccept.usesVersion11 = false; 795 | } 796 | 797 | // app should adjust nwkskey, appskey, devAdr, netId, appnounce 798 | return packet; 799 | 800 | default: 801 | LOG_ERROR("LoRa| unknown MHDR type -> drop packet\n"); 802 | LoRaWAN_DeletePacket(packet); 803 | return NULL; 804 | } 805 | 806 | return packet; 807 | } 808 | 809 | // Like LoRaWAN_NewPacket but takes a marshaled packet as input 810 | // MUST be freed with LoRaWAN_DeletePacket 811 | // data is the raw packet as produced by LoRaWAN_MarshalPacket 812 | lorawan_packet_t *LoRaWAN_UnmarshalPacket(const uint8_t *dataToParse, uint8_t length) { // todo add keys as parameter 813 | return LoRaWAN_UnmarshalPacketFor(dataToParse, length, 0); 814 | } 815 | -------------------------------------------------------------------------------- /lw_packets.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 Theodor Tobias Rohde (tr@lobaro.com) 3 | Lobaro - Industrial IoT Solutions 4 | www.lobaro.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | *****************************************************************************/ 25 | 26 | #ifndef DRV_LOBARO_LW_PACKETS_H_ 27 | #define DRV_LOBARO_LW_PACKETS_H_ 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "lw_state.h" 34 | // not supported yet! 35 | // yet only used to throw compiler warning at important positons 36 | #define USE_LORAWAN_1_1 (1) 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | #define LORAWAN_MAX_FOPTS_LEN (15) 43 | 44 | 45 | // LoRaWAN MAC header (MHDR) 46 | typedef enum { 47 | MTYPE_JOIN_REQUEST = 0, 48 | MTYPE_JOIN_ACCEPT, 49 | MTYPE_UNCONFIRMED_DATA_UP, 50 | MTYPE_UNCONFIRMED_DATA_DOWN, 51 | MTYPE_CONFIRMED_DATA_UP, 52 | MTYPE_CONFIRMED_DATA_DOWN, 53 | MTYPE_REJOIN_REQUEST, 54 | MTYPE_PROPRIETARY = 0b111 55 | } MHDR_Mtype_t; 56 | 57 | typedef enum { 58 | LORAWAN_R1 = 0, 59 | } MHDR_LoRaWAN_MajorVersion_t; 60 | 61 | typedef struct { 62 | MHDR_Mtype_t type; 63 | MHDR_LoRaWAN_MajorVersion_t version; 64 | } MHDR_t; 65 | 66 | // Downlink mac commands 67 | typedef enum { 68 | // From here LoRaWAN 1.0 69 | GwLinkCheckAns = 0x02, 70 | GwLinkADRReq = 0x03, 71 | GwDutyCycleReq = 0x04, 72 | GwRXParamSetupReq = 0x05, 73 | GwDevStatusReq = 0x06, 74 | GwNewChannelReq = 0x07, 75 | GwRXTimingSetupReq = 0x08, 76 | // From here LoRaWAN 1.1 77 | GwResetConf = 0x01, 78 | GwTxParamSetupReq = 0x09, 79 | GwDlChannelReq = 0x0A, 80 | GwRekeyConf = 0x0B, 81 | GwADRParamSetupReq = 0x0C, 82 | GwDeviceTimeAns = 0x0D, 83 | GwForceRejoinReq = 0x0E, 84 | GwRejoinParamSetupReq = 0x0F, 85 | // [1.1:2359] MAC commands for Class C devices: 86 | GwDeviceModeConf = 0x20, 87 | // 0x80 .. 0xFF Reserved for proprietary network command extensions 88 | } Lorawan_MacCommandDown_t; // Corresponds to the CID 89 | 90 | // Uplink mac commands 91 | typedef enum { 92 | // From here LoRaWAN 1.0 93 | DevLinkCheckReq = 0x02, 94 | DevLinkADRAns = 0x03, 95 | DevDutyCycleAns = 0x04, 96 | DevRXParamSetupAns = 0x05, // Repeat until downlink 97 | DevDevStatusAns = 0x06, 98 | DevNewChannelAns = 0x07, 99 | DevRXTimingSetupAns = 0x08, // Repeat until downlink 100 | // From here LoRaWAN 1.1 101 | DevResetInd = 0x01, // Send by Device 102 | DevTxParamSetupAns = 0x09, 103 | DevDlChannelAns = 0x0A, // Repeat until downlink 104 | DevRekeyInd = 0x0B, // Send by Device 105 | DevADRParamSetupAns = 0x0C, 106 | DevDeviceTimeReq = 0x0D, // Send by Device 107 | DevRejoinParamSetupAns = 0x0F, 108 | // [1.1:2359] MAC commands for Class C devices: 109 | DevDeviceModeInd = 0x20, // Send by Device 110 | // 0x80 .. 0xFF Reserved for proprietary network command extensions 111 | } Lorawan_MacCommandUp_t; // Corresponds to the CID 112 | 113 | 114 | 115 | // part of FHDR_FCtrl_t 116 | typedef struct { 117 | uint8_t ADR :1; // Adaptive data rate control bit 118 | uint8_t RFU :1; // Reserved for Future Use 119 | uint8_t ACK :1; 120 | uint8_t FPending :1; 121 | uint8_t FOptsLen :4; 122 | } FHDR_FCtrl_downlink_t; 123 | 124 | // part of FHDR_FCtrl_t 125 | typedef struct { 126 | uint8_t ADR :1; // Adaptive data rate control bit 127 | uint8_t ADRACKReq :1; 128 | uint8_t ACK :1; 129 | uint8_t ClassB :1; 130 | uint8_t FOptsLen :4; 131 | } FHDR_FCtrl_uplink_t; 132 | 133 | // part of FHDR_t 134 | typedef union { 135 | FHDR_FCtrl_downlink_t downlink; 136 | FHDR_FCtrl_uplink_t uplink; 137 | } FHDR_FCtrl_t; 138 | 139 | 140 | 141 | // part of MACPayload_t 142 | typedef struct { 143 | uint32_t DevAddr; 144 | FHDR_FCtrl_t FCtrl; 145 | uint16_t FCnt16; // only LSB of 32 bit frame Counter 146 | uint8_t FOpts[LORAWAN_MAX_FOPTS_LEN]; 147 | } FHDR_t; 148 | 149 | // part of MsgBody_t (union) 150 | typedef struct { 151 | FHDR_t FHDR; // LoRaWAN Frame header 152 | //uint8_t* payload; // optional, NOTE: payload pointer is in lorawan_packet_t struct 153 | uint8_t payloadLength; 154 | uint8_t FPort; // must be set if payload is present else optional 155 | } MACPayload_t; 156 | 157 | // part of MsgBody_t (union) 158 | typedef struct { 159 | uint8_t joinEUI[8]; // before LoRaWAN1.1 this was also called the appEUI 160 | uint8_t devEUI[8]; 161 | uint16_t devnonce; // must be random for each join request 162 | } JoinRequest_t; 163 | 164 | // part of JoinAccept_t 165 | typedef struct { 166 | uint8_t Rx2DR :4; 167 | uint8_t Rx1DRoffset :3; 168 | uint8_t OptNeg :1; 169 | } DLsettings_t; 170 | 171 | // part of JoinAccept_t 172 | typedef struct { 173 | uint8_t FreqCH4[3]; 174 | uint8_t FreqCH5[3]; 175 | uint8_t FreqCH6[3]; 176 | uint8_t FreqCH7[3]; 177 | uint8_t FreqCH8[3]; 178 | // + RFU (1 Byte) 179 | } CFlist_t; 180 | 181 | // part of MsgBody_t (union) 182 | typedef struct { 183 | uint32_t JoinNonce; // 24 bit (3 Byte), server nonce 184 | uint32_t HomeNetID; // 24 bit (3 Byte), network identifier 185 | uint32_t DevAddr; // 32 bit (4 Byte), end-device address 186 | DLsettings_t DLsettings; // 8 bit (1 Byte), providing some of the downlink parameter 187 | uint8_t RxDelay; // 8 bit (1 Byte), the delay between TX and RX 188 | // total: 12 189 | CFlist_t CFlist; // 16 byte, optional list of network parameters (e.g. frequencies for EU868) 190 | // total: 12+16=28 191 | bool hasCFlist; 192 | bool usesVersion11; 193 | 194 | uint8_t derived_fnwksintkey[16]; // todo use malloc instead? 195 | uint8_t derived_snwksintkey[16]; 196 | uint8_t derived_nwksenckey[16]; 197 | uint8_t derived_appskey[16]; 198 | } JoinAccept_t; 199 | 200 | typedef union { 201 | MACPayload_t MACPayload; 202 | JoinRequest_t JoinRequest; 203 | JoinAccept_t JoinAccept; // For Join-Accept, the MIC field is encrypted with the payload and is not a separate field 204 | } MsgBody_t; 205 | 206 | typedef struct { 207 | Time_t DeviceTime; // From DeviceTimeAns, 0 if not set 208 | } DecodedMacResponse_t; 209 | 210 | typedef enum { 211 | LORAWAN_SwitchModeClassA = 1u << 0u, 212 | // LORAWAN_SwitchModeClassB = 1u << 1u, 213 | LORAWAN_SwitchModeClassC = 1u << 2u, 214 | LORAWAN_SwitchMode = 0b101, // any of the three above 215 | } Lorawan_PostAction_t; 216 | 217 | typedef struct { 218 | uint16_t confFCnt; 219 | uint8_t txDr; 220 | uint8_t txCh; 221 | } lorawan_uplink_meta_t; 222 | 223 | // Complete PHYPayload packet 224 | typedef struct { 225 | // user mutable fields 226 | MHDR_t MHDR; // LoRaWAN MAC header (1 Byte) 227 | MsgBody_t BODY; // MHDR defines either MACPayload OR Join/Rejoin-Request OR Join-Accept (then MIC encrypted inside payload) 228 | 229 | // calculated field 230 | uint32_t MIC; 231 | 232 | // internal control flag 233 | // Length is saved in BODY.MACPayload.payloadLength 234 | uint8_t* pPayload; // != NULL if the body contains some memory that must be freed (maybe the case for dataUp/dataDown msg) 235 | // this ensures a graceful delete of packet independent of MHDR type 236 | 237 | DecodedMacResponse_t MacResp; // Field to store decoded mac responses for the application 238 | 239 | uint8_t PostTransmissionAction; // Indicator for actions/changes that must be executed after the successful transmission/reception of a message 240 | 241 | // information needed for 1.1 during message marshaling 242 | lorawan_uplink_meta_t UplinkMeta; 243 | } lorawan_packet_t; 244 | 245 | // external function dependencies 246 | // function pointers maybe NULL if using the defaults 247 | typedef struct { 248 | void* (* malloc)(size_t size); // default: malloc (stdlib.h) 249 | void (* free)(void* buf); // default: free (stdlib.h) 250 | void (* LogInfo)(const char* format, ...); // default: "logNothingDummy()" function 251 | void (* LogError)(const char* format, ...); // default: "logNothingDummy()" function 252 | } lwPackets_api_t; 253 | 254 | // external state dependencies 255 | // these parameters should be known by your LoRaWAN stack which uses this lib 256 | // maybe a simple wrapper is needed 257 | typedef struct { 258 | Lorawan_fcnt_t* pFCntCtrl; // pointer to external App netCtrl structure (see lw_state.h) 259 | Lorawan_devCfg_t* pDevCfg; // pointer to external App devCtrl structure (see lw_state.h) 260 | } lwPackets_state_t; 261 | 262 | // Setup external dependencies 263 | // must be called at least once before usage 264 | void LoRaWAN_PacketsUtil_Init(lwPackets_api_t api, lwPackets_state_t state); 265 | 266 | void lorawan_logLoraPacket(lorawan_packet_t *p, bool uplink); 267 | // LoRaWAN packet parser 268 | lorawan_packet_t* LoRaWAN_UnmarshalPacket(const uint8_t* dataToParse, uint8_t length); // must be deleted again! 269 | lorawan_packet_t* LoRaWAN_UnmarshalPacketFor(const uint8_t* dataToParse, uint8_t length, uint32_t addr); // must be deleted again! 270 | 271 | // payload: optional external payload buffer with data to be copied into new packet 272 | // length: size of external payload 273 | // result: lorawan_packet_t* which must be deleted again by user! 274 | lorawan_packet_t* LoRaWAN_NewPacket(const uint8_t* payload, uint8_t length); // must be deleted again! 275 | uint8_t LoRaWAN_MarshalPacket(lorawan_packet_t* packet, uint8_t* buffer, uint8_t bufferSize); 276 | 277 | void LoRaWAN_DeletePacket(lorawan_packet_t* packet); 278 | void LoRaWAN_DeletePayload(lorawan_packet_t* packet); 279 | 280 | #ifdef __cplusplus 281 | } 282 | #endif 283 | 284 | #endif 285 | -------------------------------------------------------------------------------- /lw_state.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 Theodor Tobias Rohde (tr@lobaro.com) 3 | Lobaro - Industrial IoT Solutions 4 | www.lobaro.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | *****************************************************************************/ 25 | 26 | #ifndef _LW_STATE_H_ 27 | #define _LW_STATE_H_ 28 | 29 | #include 30 | 31 | typedef enum { 32 | LORAWAN_VERSION_UNKNOWN = 0x00, 33 | LORAWAN_VERSION_1_0 = 0x10, 34 | LORAWAN_VERSION_1_1 = 0x11, 35 | } Lorawan_version_t; 36 | 37 | // LoRaWAN device config / state parameter 38 | // todo add LoRaWAN 1.1 functionality 39 | typedef struct { 40 | // this stores the version actually used (after OTAA negotiation) 41 | Lorawan_version_t LorawanVersion; 42 | 43 | // 4 Byte address assigned in OTAA Join or by ABP 44 | uint32_t DevAddr; 45 | 46 | // EUIs (used for OTAA join only) 47 | // EUI are 8 bytes multi-octet fields and are transmitted as little endian. (LoRaWAN Specification) 48 | // -> if the EUI-64 is 70-B3-D5-7E-F0-00-48-9C it would be in the air as 9C-48-00... 49 | // LoRaWAN_MarshalPacket will take care of this (make the little endian conversion) 50 | uint8_t JoinEUI[8]; // before LoRaWAN1.1 this was also called the appEUI 51 | uint8_t DevEUI[8]; 52 | 53 | // 128 Bit keys 54 | 55 | // device root keys, used to derive the four session keys during join 56 | // [spec:1.1:1333] 57 | uint8_t AppKey[16]; // OTAA only 58 | uint8_t NwkKey[16]; // OTAA only, since 1.1 59 | 60 | // OTAA lifetime keys (derived from NwkKey) [spec:1.1:1366] 61 | uint8_t JSIntKey[16]; 62 | uint8_t JSEncKey[16]; 63 | 64 | // session keys, set directly for ABP or set during join for OTAA [spec:1.1:1375] 65 | uint8_t NwkSEncKey[16]; 66 | uint8_t SNwkSIntKey[16]; 67 | uint8_t FNwkSIntKey[16]; 68 | uint8_t AppSKey[16]; 69 | 70 | // OTAA only: 71 | // used for/in join request msg (issued by client/sensor) [spec:1.1:1500] 72 | uint16_t DevNonce; // counter starting from 0 and increments for every join request. SHALL NEVER be reused for given JoinEUI 73 | // [spec:1.1:1550] sent by server, never repeats itself, SHALL be persisted in non-volatile memory. 74 | uint16_t JoinNonce; // aka AppNonce in LoRaWAN 1.0 75 | 76 | // network identifier, 24 bits [Spec:1.1:1543] 77 | uint32_t NetID; 78 | } Lorawan_devCfg_t; 79 | 80 | // LoRaWAN network control / state parameter 81 | typedef struct { 82 | uint32_t FCntUp; 83 | 84 | // NFCntDwn is FCntDown (LW 1.0) for all communications on LoRaWAN 1.0.1 85 | // NFCntDwn is used for MAC communication on port 0 and when the FPort field is missing (LoRaWAN 1.1 only) 86 | // In the two counters scheme the NFCntDown is managed by the Network Server, whereas 87 | // the AFCntDown is managed by the application server 88 | uint32_t NFCntDwn; 89 | // AFCntDwn is used for all ports > 0 when the device operates as a LoRaWAN 1.1 90 | uint32_t AFCntDwn; 91 | 92 | } Lorawan_fcnt_t; 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /module_logging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef configLOG_LORAWAN_PACKETS 4 | #define configLOG_LORAWAN_PACKETS 1 5 | #endif 6 | 7 | #if configLOG_LORAWAN_PACKETS == 1 8 | #define LOG_ERROR(...) lib.api.LogError(__VA_ARGS__) 9 | #define LOG_INFO(...) lib.api.LogInfo(__VA_ARGS__) 10 | #else 11 | #define LOG_ERROR(...) {} 12 | #define LOG_INFO(...) {} 13 | #endif 14 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] --------------------------------------------------------------------------------