tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/lora/lorawan/otaa.go (about) 1 package lorawan 2 3 import ( 4 "bytes" 5 "crypto/aes" 6 "encoding/hex" 7 ) 8 9 // Otaa is used to store Over The Air Activation data of a LoRaWAN session 10 type Otaa struct { 11 DevEUI [8]uint8 12 AppEUI [8]uint8 13 AppKey [16]uint8 14 devNonce [2]uint8 15 appNonce [3]uint8 16 NetID [3]uint8 17 buf []uint8 18 } 19 20 // Initialize DevNonce 21 func (o *Otaa) Init() { 22 o.buf = make([]uint8, 0) 23 o.generateDevNonce() 24 } 25 26 func (o *Otaa) generateDevNonce() { 27 // TODO: handle error 28 rnd, _ := GetRand16() 29 o.devNonce[0] = rnd[0] 30 o.devNonce[1] = rnd[1] 31 } 32 33 func (o *Otaa) incrementDevNonce() { 34 nonce := uint16(o.devNonce[1])<<8 | uint16(o.devNonce[0]) + 1 35 o.devNonce[0] = uint8(nonce) 36 o.devNonce[1] = uint8((nonce >> 8)) 37 } 38 39 // Set configures the Otaa AppEUI, DevEUI, AppKey for the device 40 func (o *Otaa) Set(appEUI []uint8, devEUI []uint8, appKey []uint8) { 41 o.SetAppEUI(appEUI) 42 o.SetDevEUI(devEUI) 43 o.SetAppKey(appKey) 44 } 45 46 // SetAppEUI configures the Otaa AppEUI 47 func (o *Otaa) SetAppEUI(appEUI []uint8) error { 48 if len(appEUI) != 8 { 49 return ErrInvalidEuiLength 50 } 51 52 copy(o.AppEUI[:], appEUI) 53 54 return nil 55 } 56 57 func (o *Otaa) GetAppEUI() string { 58 return hex.EncodeToString(o.AppEUI[:]) 59 } 60 61 // SetDevEUI configures the Otaa DevEUI 62 func (o *Otaa) SetDevEUI(devEUI []uint8) error { 63 if len(devEUI) != 8 { 64 return ErrInvalidEuiLength 65 } 66 67 copy(o.DevEUI[:], devEUI) 68 69 return nil 70 } 71 72 func (o *Otaa) GetDevEUI() string { 73 return hex.EncodeToString(o.DevEUI[:]) 74 } 75 76 // SetAppKey configures the Otaa AppKey 77 func (o *Otaa) SetAppKey(appKey []uint8) error { 78 if len(appKey) != 16 { 79 return ErrInvalidAppKeyLength 80 } 81 82 copy(o.AppKey[:], appKey) 83 84 return nil 85 } 86 87 func (o *Otaa) GetAppKey() string { 88 return hex.EncodeToString(o.AppKey[:]) 89 } 90 91 func (o *Otaa) GetNetID() string { 92 return hex.EncodeToString(o.NetID[:]) 93 } 94 95 func (o *Otaa) SetNetID(netID []uint8) error { 96 if len(netID) != 3 { 97 return ErrInvalidNetIDLength 98 } 99 100 copy(o.NetID[:], netID) 101 102 return nil 103 } 104 105 // GenerateJoinRequest Generates a LoraWAN Join request 106 func (o *Otaa) GenerateJoinRequest() ([]uint8, error) { 107 o.incrementDevNonce() 108 109 // TODO: Add checks 110 o.buf = o.buf[:0] 111 o.buf = append(o.buf, 0x00) 112 o.buf = append(o.buf, reverseBytes(o.AppEUI[:])...) 113 o.buf = append(o.buf, reverseBytes(o.DevEUI[:])...) 114 o.buf = append(o.buf, o.devNonce[:]...) 115 mic := genPayloadMIC(o.buf, o.AppKey) 116 o.buf = append(o.buf, mic[:]...) 117 118 return o.buf, nil 119 } 120 121 // DecodeJoinAccept Decodes a Lora Join Accept packet 122 func (o *Otaa) DecodeJoinAccept(phyPload []uint8, s *Session) error { 123 if len(phyPload) < 12 { 124 return ErrInvalidPacketLength 125 } 126 data := phyPload[1:] // Remove trailing 0x20 127 128 // Prepare AES Cipher 129 block, err := aes.NewCipher(o.AppKey[:]) 130 if err != nil { 131 return err 132 } 133 buf := make([]byte, len(data)) 134 for k := 0; k < len(data)/aes.BlockSize; k++ { 135 block.Encrypt(buf[k*aes.BlockSize:], data[k*aes.BlockSize:]) 136 } 137 138 copy(o.appNonce[:], buf[0:3]) 139 copy(o.NetID[:], buf[3:6]) 140 copy(s.DevAddr[:], buf[6:10]) 141 s.DLSettings = buf[10] 142 s.RXDelay = buf[11] 143 144 if len(buf) > 16 { 145 copy(s.CFList[:], buf[12:28]) 146 } 147 rxMic := buf[len(buf)-4:] 148 149 dataMic := []byte{} 150 dataMic = append(dataMic, phyPload[0]) 151 dataMic = append(dataMic, o.appNonce[:]...) 152 dataMic = append(dataMic, o.NetID[:]...) 153 dataMic = append(dataMic, s.DevAddr[:]...) 154 dataMic = append(dataMic, s.DLSettings) 155 dataMic = append(dataMic, s.RXDelay) 156 dataMic = append(dataMic, s.CFList[:]...) 157 computedMic := genPayloadMIC(dataMic[:], o.AppKey) 158 if !bytes.Equal(computedMic[:], rxMic[:]) { 159 return ErrInvalidMic 160 } 161 // Generate NwkSKey 162 // NwkSKey = aes128_encrypt(AppKey, 0x01|AppNonce|NetID|DevNonce|pad16) 163 sKey := []byte{} 164 sKey = append(sKey, 0x01) 165 sKey = append(sKey, o.appNonce[:]...) 166 sKey = append(sKey, o.NetID[:]...) 167 sKey = append(sKey, o.devNonce[:]...) 168 for i := 0; i < 7; i++ { 169 sKey = append(sKey, 0x00) // PAD to 16 170 } 171 block.Encrypt(buf, sKey) 172 copy(s.NwkSKey[:], buf[0:16]) 173 174 // Generate AppSKey 175 // AppSKey = aes128_encrypt(AppKey, 0x02|AppNonce|NetID|DevNonce|pad16) 176 sKey[0] = 0x02 177 block.Encrypt(buf, sKey) 178 copy(s.AppSKey[:], buf[0:16]) 179 180 // Reset counters 181 s.FCntDown = 0 182 s.FCntUp = 0 183 184 return nil 185 }