// TestIntegrity performs the message integrity check (MIC), see LoRaWAN specification 1r0 4.4 func (d *PHYPayload) TestIntegrity(key []byte) (bool, error) { b0 := new(bytes.Buffer) b0.Write([]byte{0x49, 0x0, 0x0, 0x0, 0x0}) b0.WriteByte(0x0) binary.Write(b0, binary.LittleEndian, d.DevAddr) binary.Write(b0, binary.LittleEndian, uint32(d.FCnt)) b0.WriteByte(0x0) b0.WriteByte(byte(1 + len(d.MACPayload))) b0.WriteByte(d.MHDR) b0.Write(d.MACPayload) hash, err := cmac.New(key) if err != nil { log.Printf("Failed to initialize CMAC: %s", err.Error()) return false, err } _, err = hash.Write(b0.Bytes()) if err != nil { log.Printf("Failed to hash data: %s", err.Error()) return false, err } calculatedMIC := hash.Sum([]byte{})[0:4] return bytes.Equal(calculatedMIC, d.MIC), nil }
func (t *HashTest) SumDoesntAffectState() { // Grab a test case. cases := aes_testing.CmacCases() AssertGt(len(cases), 10) c := cases[10] // Create a hash and feed it some of the test case's data. h, err := cmac.New(c.Key) AssertEq(nil, err) AssertGt(len(c.Msg), 5) _, err = h.Write(c.Msg[0:5]) AssertEq(nil, err) // Call Sum. AssertEq(16, len(h.Sum([]byte{}))) // Feed the rest of the data and call Sum again. We should get the correct // result. _, err = h.Write(c.Msg[5:]) AssertEq(nil, err) ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac)) // Calling repeatedly should also work. ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac)) ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac)) ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac)) }
// calculateMIC calculates and returns the MIC. func (p PHYPayload) calculateMIC(key AES128Key) ([]byte, error) { if p.MACPayload == nil { return []byte{}, errors.New("lorawan: MACPayload should not be empty") } macPayload, ok := p.MACPayload.(*MACPayload) if !ok { return []byte{}, errors.New("lorawan: MACPayload should be of type *MACPayload") } var b []byte var err error var micBytes []byte b, err = p.MHDR.MarshalBinary() if err != nil { return nil, err } micBytes = append(micBytes, b...) b, err = macPayload.MarshalBinary() if err != nil { return nil, err } micBytes = append(micBytes, b...) b0 := make([]byte, 16) b0[0] = 0x49 if !p.isUplink() { b0[5] = 1 } b, err = macPayload.FHDR.DevAddr.MarshalBinary() if err != nil { return nil, err } copy(b0[6:10], b) binary.LittleEndian.PutUint32(b0[10:14], macPayload.FHDR.FCnt) b0[15] = byte(len(micBytes)) hash, err := cmac.New(key[:]) if err != nil { return nil, err } if _, err = hash.Write(b0); err != nil { return nil, err } if _, err = hash.Write(micBytes); err != nil { return nil, err } hb := hash.Sum([]byte{}) if len(hb) < 4 { return nil, errors.New("lorawan: the hash returned less than 4 bytes") } return hb[0:4], nil }
func runCmac(key []byte, msg []byte) []byte { h, err := cmac.New(key) AssertEq(nil, err) _, err = h.Write(msg) AssertEq(nil, err) return h.Sum([]byte{}) }
func (t *HashTest) BlockSize() { var h hash.Hash var err error // AES-128 h, err = cmac.New(make([]byte, 16)) AssertEq(nil, err) ExpectEq(16, h.BlockSize()) // AES-192 h, err = cmac.New(make([]byte, 24)) AssertEq(nil, err) ExpectEq(16, h.BlockSize()) // AES-256 h, err = cmac.New(make([]byte, 32)) AssertEq(nil, err) ExpectEq(16, h.BlockSize()) }
// Run the S2V "string to vector" function of RFC 5297 using the input key and // string vector, which must be non-empty. (RFC 5297 defines S2V to handle the // empty vector case, but it is never used that way by higher-level functions.) // // If provided, the supplied scatch space will be used to avoid an allocation. // It should be (but is not required to be) as large as the last element of // strings. // // The result is guaranteed to be of length s2vSize. func s2v(key []byte, strings [][]byte, scratch []byte) []byte { numStrings := len(strings) if numStrings == 0 { panic("strings vector must be non-empty.") } // Create a CMAC hash. h, err := cmac.New(key) if err != nil { panic(fmt.Sprintf("cmac.New: %v", err)) } // Initialize. if _, err := h.Write(s2vZero); err != nil { panic(fmt.Sprintf("h.Write: %v", err)) } d := h.Sum([]byte{}) h.Reset() // Handle all strings but the last. for i := 0; i < numStrings-1; i++ { if _, err := h.Write(strings[i]); err != nil { panic(fmt.Sprintf("h.Write: %v", err)) } common.Xor(d, dbl(d), h.Sum([]byte{})) h.Reset() } // Handle the last string. lastString := strings[numStrings-1] var t []byte if len(lastString) >= aes.BlockSize { // Make an output buffer the length of lastString. if cap(scratch) >= len(lastString) { t = scratch[:len(lastString)] } else { t = make([]byte, len(lastString)) } // XOR d on the end of lastString. xorend(t, lastString, d) } else { t = make([]byte, aes.BlockSize) common.Xor(t, dbl(d), common.PadBlock(lastString)) } if _, err := h.Write(t); err != nil { panic(fmt.Sprintf("h.Write: %v", err)) } return h.Sum([]byte{}) }
func (t *HashTest) SumAppendsToSlice() { // Grab a test case. cases := aes_testing.CmacCases() AssertGt(len(cases), 10) c := cases[10] // Create a hash and feed it the test case's data. h, err := cmac.New(c.Key) AssertEq(nil, err) _, err = h.Write(c.Msg) AssertEq(nil, err) // Ask it to append to a non-empty slice. prefix := []byte{0xde, 0xad, 0xbe, 0xef} mac := h.Sum(prefix) AssertEq(20, len(mac)) ExpectThat(mac[0:4], DeepEquals(prefix)) ExpectThat(mac[4:], DeepEquals(c.Mac)) }
func (t *HashTest) Reset() { // Grab a test case. cases := aes_testing.CmacCases() AssertGt(len(cases), 10) c := cases[10] // Create a hash and feed it some data, then reset it. h, err := cmac.New(c.Key) AssertEq(nil, err) _, err = h.Write([]byte{0xde, 0xad}) AssertEq(nil, err) h.Reset() // Feed the hash the test case's data and make sure the result is correct. _, err = h.Write(c.Msg) AssertEq(nil, err) ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac)) }
// calculateJoinAcceptMIC calculates and returns the join-accept MIC. func (p PHYPayload) calculateJoinAcceptMIC(key AES128Key) ([]byte, error) { if p.MACPayload == nil { return []byte{}, errors.New("lorawan: MACPayload should not be empty") } jaPayload, ok := p.MACPayload.(*JoinAcceptPayload) if !ok { return []byte{}, errors.New("lorawan: MACPayload should be of type *JoinAcceptPayload") } micBytes := make([]byte, 0, 13) b, err := p.MHDR.MarshalBinary() if err != nil { return []byte{}, err } micBytes = append(micBytes, b...) b, err = jaPayload.MarshalBinary() if err != nil { return nil, err } micBytes = append(micBytes, b...) hash, err := cmac.New(key[:]) if err != nil { return []byte{}, err } if _, err = hash.Write(micBytes); err != nil { return nil, err } hb := hash.Sum([]byte{}) if len(hb) < 4 { return []byte{}, errors.New("lorawan: the hash returned less than 4 bytes") } return hb[0:4], nil }
func (t *HashTest) LongKey() { _, err := cmac.New(make([]byte, 33)) ExpectThat(err, Error(HasSubstr("16-"))) ExpectThat(err, Error(HasSubstr("24-"))) ExpectThat(err, Error(HasSubstr("32-"))) }
func (t *HashTest) NilKey() { _, err := cmac.New(nil) ExpectThat(err, Error(HasSubstr("16-"))) ExpectThat(err, Error(HasSubstr("24-"))) ExpectThat(err, Error(HasSubstr("32-"))) }
func (t *HashTest) Size() { h, err := cmac.New(make([]byte, 16)) AssertEq(nil, err) ExpectEq(16, h.Size()) }