Section 4.4 of the LoRaWAN specification is quite clear about MIC calculation. Here's a simplified version of some code I wrote a couple of months ago:
// msg = MHDR | FHDR | FPORT | FRMPayload
var msgbuf bytes.Buffer
msgbuf.WriteByte(mhdr)
msgbuf.Write(fhdr)
msgbuf.WriteByte(fport)
msgbuf.Write(payload)
msg := msgbuf.Bytes()
// B0 = 0x49 | 4x 0x00 | Dir (uplink=0x00/downlink=0x01) | DevAddr | FCnt (4 bytes!) | 0x00 | len(msg)
var blocksbuf bytes.Buffer
blocksbuf.Write([]byte{0x49, 0x0, 0x0, 0x0, 0x0})
switch mType {
case UnconfirmedDataUp, ConfirmedDataUp:
blocksbuf.WriteByte(0x00)
case UnconfirmedDataDown, ConfirmedDataDown:
blocksbuf.WriteByte(0x01)
default:
// nonononono
}
binary.Write(blocksbuf, binary.LittleEndian, dataPayload.FHDR.DevAddr)
binary.Write(blocksbuf, binary.LittleEndian, uint32(dataPayload.FHDR.FCnt))
blocksbuf.WriteByte(0x00)
blocksbuf.WriteByte(byte(len(msg)))
// Append msg to B0
blocksbuf.Write(msg)
blocks := blocksbuf.Bytes()
hash, _ := cmac.New(nwkSKey)
hash.Write(blocks)
return hash.Sum([]byte{})[0:4]
You could also have a look at how it's done in the github.com/brocaar/lorawan package.