decred.org/dcrdex@v1.0.5/server/cmd/dcrdex/key.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 package main 5 6 import ( 7 "errors" 8 "fmt" 9 "os" 10 11 "decred.org/dcrdex/dex/encode" 12 "decred.org/dcrdex/dex/encrypt" 13 "github.com/decred/dcrd/dcrec/secp256k1/v4" 14 ) 15 16 func dexKey(path string, pass []byte) (*secp256k1.PrivateKey, error) { 17 var privKey *secp256k1.PrivateKey 18 if _, err := os.Stat(path); os.IsNotExist(err) { 19 log.Infof("Creating new DEX signing key file at %s...", path) 20 privKey, err = createAndStoreKey(path, pass) 21 if err != nil { 22 return nil, fmt.Errorf("failed to load DEX private key from file %s: %v", 23 path, err) 24 } 25 } else { 26 log.Infof("Loading DEX signing key from %s...", path) 27 privKey, err = loadKeyFile(path, pass) 28 if err != nil { 29 return nil, fmt.Errorf("failed to load DEX private key from file %s: %v", 30 path, err) 31 } 32 } 33 return privKey, nil 34 } 35 36 func loadKeyFile(path string, pass []byte) (*secp256k1.PrivateKey, error) { 37 // Load and decrypt it. 38 pkFileBuffer, err := os.ReadFile(path) 39 if err != nil { 40 return nil, fmt.Errorf("ReadFile: %v", err) 41 } 42 43 ver, pushes, err := encode.DecodeBlob(pkFileBuffer) 44 if err != nil { 45 return nil, fmt.Errorf("failed to unmarshal DEX signing key data: %v", err) 46 } 47 if ver != 0 { 48 return nil, fmt.Errorf("unrecognized key file version %d: %v", ver, err) 49 } 50 if len(pushes) != 2 { 51 return nil, fmt.Errorf("invalid signing key file, "+ 52 "containing %d data pushes instead of 2", len(pushes)) 53 } 54 keyParams := pushes[0] 55 encKey := pushes[1] 56 57 crypter, err := encrypt.Deserialize(pass, keyParams) 58 if err != nil { 59 return nil, err 60 } 61 62 keyB, err := crypter.Decrypt(encKey) 63 if err != nil { 64 return nil, err 65 } 66 // secp256k1.PrivKeyFromBytes() but don't trust that the DB has a valid key. 67 var priv secp256k1.PrivateKey 68 if overflow := priv.Key.SetByteSlice(keyB); overflow || priv.Key.IsZero() { 69 return nil, errors.New("invalid decrypted private key bytes") 70 } 71 return &priv, nil 72 } 73 74 func createAndStoreKey(path string, pass []byte) (*secp256k1.PrivateKey, error) { 75 // Disallow an empty password. 76 if len(pass) == 0 { 77 return nil, fmt.Errorf("empty password") 78 } 79 // Do not overwrite existing key files. 80 if _, err := os.Stat(path); err == nil { 81 return nil, fmt.Errorf("key file exists") 82 } 83 84 // Create and store a new key. 85 privKey, err := secp256k1.GeneratePrivateKey() 86 if err != nil { 87 return nil, fmt.Errorf("failed to generate DEX signing key: %v", err) 88 } 89 90 // Encrypt the private key. 91 crypter := encrypt.NewCrypter(pass) 92 keyParams := crypter.Serialize() 93 encKey, err := crypter.Encrypt(privKey.Serialize()) 94 if err != nil { 95 return nil, fmt.Errorf("failed to encrypt DEX signing key: %v", err) 96 } 97 // Check a round trip with this key data. 98 _, err = crypter.Decrypt(encKey) 99 if err != nil { 100 return nil, fmt.Errorf("failed to decrypt DEX signing key: %v", err) 101 } 102 103 // Store it. 104 data := encode.BuildyBytes{0}.AddData(keyParams).AddData(encKey) 105 err = os.WriteFile(path, data, 0644) 106 if err != nil { 107 return nil, fmt.Errorf("failed to write DEX signing key: %v", err) 108 } 109 110 return privKey, nil 111 }