github.com/ethersphere/bee/v2@v2.2.0/pkg/keystore/file/service.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package file 6 7 import ( 8 "crypto/ecdsa" 9 "fmt" 10 "os" 11 "path/filepath" 12 13 "github.com/ethersphere/bee/v2/pkg/keystore" 14 ) 15 16 // Service is the file-based keystore.Service implementation. 17 // 18 // Keys are stored in directory where each private key is stored in a file, 19 // which is encrypted with symmetric key using some password. 20 type Service struct { 21 dir string 22 } 23 24 // New creates new file-based keystore.Service implementation. 25 func New(dir string) *Service { 26 return &Service{dir: dir} 27 } 28 29 func (s *Service) Exists(name string) (bool, error) { 30 filename := s.keyFilename(name) 31 32 data, err := os.ReadFile(filename) 33 if err != nil && !os.IsNotExist(err) { 34 return false, fmt.Errorf("read private key: %w", err) 35 } 36 if len(data) == 0 { 37 return false, nil 38 } 39 40 return true, nil 41 } 42 43 func (s *Service) SetKey(name, password string, edg keystore.EDG) (*ecdsa.PrivateKey, error) { 44 pk, err := edg.Generate() 45 if err != nil { 46 return nil, fmt.Errorf("generate key: %w", err) 47 } 48 49 d, err := encryptKey(pk, password, edg) 50 if err != nil { 51 return nil, err 52 } 53 54 filename := s.keyFilename(name) 55 56 if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil { 57 return nil, err 58 } 59 60 if err := os.WriteFile(filename, d, 0600); err != nil { 61 return nil, err 62 } 63 64 return pk, nil 65 } 66 67 func (s *Service) Key(name, password string, edg keystore.EDG) (pk *ecdsa.PrivateKey, created bool, err error) { 68 filename := s.keyFilename(name) 69 70 data, err := os.ReadFile(filename) 71 if err != nil && !os.IsNotExist(err) { 72 return nil, false, fmt.Errorf("read private key: %w", err) 73 } 74 if len(data) == 0 { 75 pk, err := s.SetKey(name, password, edg) 76 return pk, true, err 77 } 78 79 pk, err = decryptKey(data, password, edg) 80 if err != nil { 81 return nil, false, err 82 } 83 return pk, false, nil 84 } 85 86 func (s *Service) keyFilename(name string) string { 87 return filepath.Join(s.dir, fmt.Sprintf("%s.key", name)) 88 }