1package keycard 2 3import ( 4 "crypto/rand" 5 "crypto/sha256" 6 "encoding/base64" 7 "fmt" 8 "math/big" 9 10 "github.com/status-im/keycard-go/crypto" 11 "golang.org/x/crypto/pbkdf2" 12 "golang.org/x/text/unicode/norm" 13) 14 15const ( 16 maxPukNumber = int64(999999999999) 17 maxPinNumber = int64(999999) 18) 19 20// Secrets contains the secret data needed to pair a client with a card. 21type Secrets struct { 22 pin string 23 puk string 24 pairingPass string 25 pairingToken []byte 26} 27 28func NewSecrets(pin, puk, pairingPass string) *Secrets { 29 return &Secrets{ 30 pin: pin, 31 puk: puk, 32 pairingPass: pairingPass, 33 } 34} 35 36// GenerateSecrets generate a new Secrets with random puk and pairing password. 37func GenerateSecrets() (*Secrets, error) { 38 pairingPass, err := generatePairingPass() 39 if err != nil { 40 return nil, err 41 } 42 43 puk, err := rand.Int(rand.Reader, big.NewInt(maxPukNumber)) 44 if err != nil { 45 return nil, err 46 } 47 48 pin, err := rand.Int(rand.Reader, big.NewInt(maxPinNumber)) 49 if err != nil { 50 return nil, err 51 } 52 53 return &Secrets{ 54 pin: fmt.Sprintf("%06d", pin.Int64()), 55 puk: fmt.Sprintf("%012d", puk.Int64()), 56 pairingPass: pairingPass, 57 pairingToken: generatePairingToken(pairingPass), 58 }, nil 59} 60 61// Pin returns the pin string. 62func (s *Secrets) Pin() string { 63 return s.pin 64} 65 66// Puk returns the puk string. 67func (s *Secrets) Puk() string { 68 return s.puk 69} 70 71// PairingPass returns the pairing password string. 72func (s *Secrets) PairingPass() string { 73 return s.pairingPass 74} 75 76// PairingToken returns the pairing token generated from the random pairing password. 77func (s *Secrets) PairingToken() []byte { 78 return s.pairingToken 79} 80 81func generatePairingPass() (string, error) { 82 r := make([]byte, 12) 83 _, err := rand.Read(r) 84 if err != nil { 85 return "", err 86 } 87 88 return base64.URLEncoding.EncodeToString(r), nil 89} 90 91func generatePairingToken(pass string) []byte { 92 return pbkdf2.Key(norm.NFKD.Bytes([]byte(pass)), norm.NFKD.Bytes([]byte(crypto.PairingTokenSalt)), 50000, 32, sha256.New) 93} 94