99package main
1010
1111import (
12+ "crypto/elliptic"
13+ "crypto/sha256"
1214 "encoding/base64"
13- "errors"
15+ "encoding/binary"
16+ "io"
17+ "machine"
18+ "math/big"
19+ "os"
1420 "time"
1521
22+ "golang.org/x/crypto/hkdf"
1623 "tinygo.org/x/bluetooth"
24+ "tinygo.org/x/tinyfs/littlefs"
1725)
1826
19- var adapter = bluetooth .DefaultAdapter
27+ var (
28+ adapter = bluetooth .DefaultAdapter
29+ lfs = littlefs .New (machine .Flash )
30+ )
31+
32+ func getIndex () uint64 {
33+ f , err := lfs .Open ("/haystack" )
34+ if err != nil {
35+ return 0
36+ }
37+ defer f .Close ()
38+
39+ var buf [8 ]byte
40+ _ , err = io .ReadFull (f , buf [:])
41+ must ("read index from file" , err )
42+ return binary .LittleEndian .Uint64 (buf [:])
43+ }
44+
45+ func writeIndex (i uint64 ) error {
46+ f , err := lfs .OpenFile ("/haystack" , os .O_CREATE )
47+ if err != nil {
48+ return err
49+ }
50+ defer f .Close ()
51+
52+ var buf [8 ]byte
53+ binary .LittleEndian .PutUint64 (buf [:], i )
54+ _ , err = f .Write (buf [:])
55+ return err
56+ }
2057
2158func main () {
2259 // wait for USB serial to be available
2360 time .Sleep (2 * time .Second )
2461
25- key , err := getKeyData ()
26- if err != nil {
27- fail ("failed to get key data: " + err .Error ())
62+ config := littlefs.Config {
63+ CacheSize : 64 ,
64+ LookaheadSize : 32 ,
65+ BlockCycles : 512 ,
66+ }
67+ lfs .Configure (& config )
68+ if err := lfs .Mount (); err != nil {
69+ must ("format littlefs" , lfs .Format ())
70+ must ("mount littlefs" , lfs .Mount ())
2871 }
29- println ("key is" , AdvertisingKey , "(" , len (key ), "bytes)" )
72+ println ("littlefs mounted" )
73+
74+ // Get and increment index. Ideally this would be done at the end of 15
75+ // minutes. However writing seems to fail once advertising has started.
76+ derivIndex := getIndex ()
77+ derivIndex ++
78+ must ("write new index to file" , writeIndex (derivIndex ))
79+ println ("derivation secret is" , DerivationSecret )
80+ println ("derivation index is" , derivIndex )
81+
82+ priv , pub , err := getKeyData (derivIndex )
83+ must ("get key data" , err )
84+ println ("private key is" , base64 .StdEncoding .EncodeToString (priv ))
85+ println ("public key is" , base64 .StdEncoding .EncodeToString (pub ))
3086
3187 opts := bluetooth.AdvertisementOptions {
3288 AdvertisementType : bluetooth .AdvertisingTypeNonConnInd ,
3389 Interval : bluetooth .NewDuration (1285000 * time .Microsecond ), // 1285ms
34- ManufacturerData : []bluetooth.ManufacturerDataElement {findMyData (key )},
90+ ManufacturerData : []bluetooth.ManufacturerDataElement {findMyData (pub )},
3591 }
3692
3793 must ("enable BLE stack" , adapter .Enable ())
3894
3995 // Set the address to the first 6 bytes of the public key.
40- adapter .SetRandomAddress (bluetooth.MAC {key [5 ], key [4 ], key [3 ], key [2 ], key [1 ], key [0 ] | 0xC0 })
96+ adapter .SetRandomAddress (bluetooth.MAC {pub [5 ], pub [4 ], pub [3 ], pub [2 ], pub [1 ], pub [0 ] | 0xC0 })
4197
4298 println ("configure advertising..." )
4399 adv := adapter .DefaultAdvertisement ()
@@ -46,24 +102,48 @@ func main() {
46102 println ("start advertising..." )
47103 must ("start adv" , adv .Start ())
48104
105+ boot := time .Now ()
49106 address , _ := adapter .Address ()
50- for {
51- println ("FindMy device using" , address .MAC .String ())
107+ for uptime := 0 ; ; uptime ++ {
108+ if uptime % 100 == 0 {
109+ println ("FindMy device using" , address .MAC .String (), "uptime" , uptime )
110+ }
52111 time .Sleep (time .Second )
112+ if time .Since (boot ) > 15 * time .Minute {
113+ machine .CPUReset ()
114+ }
53115 }
54116}
55117
56- // getKeyData returns the public key data from the base64 encoded string.
57- func getKeyData () ([]byte , error ) {
58- val , err := base64 .StdEncoding .DecodeString (AdvertisingKey )
118+ const keySize = 28
119+
120+ var curve = elliptic .P224 ()
121+
122+ func getKeyData (i uint64 ) ([]byte , []byte , error ) {
123+ secret , err := base64 .StdEncoding .DecodeString (DerivationSecret )
59124 if err != nil {
60- return nil , err
61- }
62- if len (val ) != 28 {
63- return nil , errors .New ("public key must be 28 bytes long" )
125+ return nil , nil , err
64126 }
65127
66- return val , nil
128+ info := make ([]byte , 8 )
129+ binary .LittleEndian .PutUint64 (info , i )
130+ r := hkdf .New (sha256 .New , secret , nil , info )
131+ for {
132+ priv := make ([]byte , keySize )
133+ if _ , err := io .ReadFull (r , priv ); err != nil {
134+ return nil , nil , err
135+ }
136+
137+ privInt := new (big.Int ).SetBytes (priv )
138+ n := curve .Params ().N
139+ if privInt .Sign () > 0 && privInt .Cmp (n ) < 0 {
140+ xInt , _ := curve .ScalarBaseMult (priv )
141+ xBytes := xInt .Bytes ()
142+ x := make ([]byte , keySize )
143+ copy (x [keySize - len (xBytes ):], xBytes )
144+ return priv , x , nil
145+ }
146+ }
67147}
68148
69149const (
0 commit comments