From f3ad4f113fa17ddd816f85cde3d195f9acb1029d Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Fri, 19 Jan 2024 17:03:36 +0200 Subject: [PATCH 01/12] Modify secrets generation command logic --- command/polybftsecrets/params.go | 14 ++++- command/polybftsecrets/utils.go | 8 ++- go.mod | 3 +- go.sum | 16 +++++ secrets/encryptedlocal/encryptedlocal.go | 64 +++++++++++++++++++ secrets/encryptedlocal/encryption.go | 78 ++++++++++++++++++++++++ secrets/encryptedlocal/prompt.go | 23 +++++++ secrets/helper/helper.go | 41 +++++++++++-- 8 files changed, 238 insertions(+), 9 deletions(-) create mode 100644 secrets/encryptedlocal/encryptedlocal.go create mode 100644 secrets/encryptedlocal/encryption.go create mode 100644 secrets/encryptedlocal/prompt.go diff --git a/command/polybftsecrets/params.go b/command/polybftsecrets/params.go index 1e1f6cabc4..695524ff1a 100644 --- a/command/polybftsecrets/params.go +++ b/command/polybftsecrets/params.go @@ -21,6 +21,7 @@ const ( numFlag = "num" outputFlag = "output" chainIDFlag = "chain-id" + networkKeyFlag = "network-key" // maxInitNum is the maximum value for "num" flag maxInitNum = 30 @@ -42,6 +43,8 @@ type initParams struct { output bool chainID int64 + + networkKey string } func (ip *initParams) validateFlags() error { @@ -78,6 +81,13 @@ func (ip *initParams) setFlags(cmd *cobra.Command) { "the flag indicating how many secrets should be created, only for the local FS", ) + cmd.Flags().StringVar( + &ip.networkKey, + networkKeyFlag, + "", + "the flag providing already created network key to be used", + ) + // Don't accept data-dir and config flags because they are related to different secrets managers. // data-dir is about the local FS as secrets storage, config is about remote secrets manager. cmd.MarkFlagsMutuallyExclusive(AccountDirFlag, AccountConfigFlag) @@ -85,6 +95,8 @@ func (ip *initParams) setFlags(cmd *cobra.Command) { // num flag should be used with data-dir flag only so it should not be used with config flag. cmd.MarkFlagsMutuallyExclusive(numFlag, AccountConfigFlag) + cmd.MarkFlagsMutuallyExclusive(numFlag, networkKeyFlag) + cmd.Flags().BoolVar( &ip.generatesAccount, accountFlag, @@ -171,7 +183,7 @@ func (ip *initParams) initKeys(secretsManager secrets.SecretsManager) ([]string, if ip.generatesNetwork { if !secretsManager.HasSecret(secrets.NetworkKey) { - if _, err := helper.InitNetworkingPrivateKey(secretsManager); err != nil { + if _, err := helper.InitNetworkingPrivateKey(secretsManager, []byte(ip.networkKey)); err != nil { return generated, fmt.Errorf("error initializing network-key: %w", err) } diff --git a/command/polybftsecrets/utils.go b/command/polybftsecrets/utils.go index 655f9b9e87..e42512389d 100644 --- a/command/polybftsecrets/utils.go +++ b/command/polybftsecrets/utils.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/secrets/encryptedlocal" "github.com/0xPolygon/polygon-edge/secrets/helper" ) @@ -52,8 +53,13 @@ func GetSecretsManager(dataPath, configPath string, insecureLocalStore bool) (se // to raise awareness that it should be only used in development/testing environments. // Production setups should use one of the supported secrets managers if !insecureLocalStore { - return nil, ErrSecureLocalStoreNotImplemented + helper.SetupEncryptedLocalSecretsManager(dataPath) } return helper.SetupLocalSecretsManager(dataPath) } + +func isEncryptedLocalSecretsManager(sm secrets.SecretsManager) bool { + _, ok := sm.(*encryptedlocal.EncryptedLocalSecretsManager) + return ok +} diff --git a/go.mod b/go.mod index ec37a687ca..dfb292cf29 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/umbracle/ethgo v0.1.4-0.20231006072852-6b068360fc97 github.com/valyala/fastjson v1.6.3 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/tools v0.13.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 // indirect @@ -99,6 +99,7 @@ require ( go.uber.org/dig v1.16.1 // indirect go.uber.org/fx v1.19.2 // indirect golang.org/x/exp v0.0.0-20230725012225-302865e7556b // indirect + golang.org/x/term v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect nhooyr.io/websocket v1.8.7 // indirect diff --git a/go.sum b/go.sum index 3941f2f3ac..2ac860ce08 100644 --- a/go.sum +++ b/go.sum @@ -81,7 +81,9 @@ github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pY github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= @@ -93,6 +95,7 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -144,6 +147,7 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6Uh github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= @@ -200,6 +204,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -374,16 +379,20 @@ github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABo github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -485,6 +494,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -516,6 +526,7 @@ github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -791,6 +802,7 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -910,10 +922,14 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/secrets/encryptedlocal/encryptedlocal.go b/secrets/encryptedlocal/encryptedlocal.go new file mode 100644 index 0000000000..cb2d7da35c --- /dev/null +++ b/secrets/encryptedlocal/encryptedlocal.go @@ -0,0 +1,64 @@ +package encryptedlocal + +import ( + "errors" + + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/secrets/local" +) + +// LocalSecretsManager is a SecretsManager that +// stores secrets encrypted locally on disk +type EncryptedLocalSecretsManager struct { + *local.LocalSecretsManager + cryptHandler CryptHandler +} + +// SecretsManagerFactory implements the factory method +func SecretsManagerFactory( + _ *secrets.SecretsManagerConfig, + params *secrets.SecretsManagerParams, +) (secrets.SecretsManager, error) { + baseSM, err := local.SecretsManagerFactory( + nil, // Local secrets manager doesn't require a config + params) + if err != nil { + return nil, err + } + + localSM, ok := baseSM.(*local.LocalSecretsManager) + if !ok { + return nil, errors.New("invalid type assertion") + } + + prompt := NewPrompt() + cryptHandler := NewCryptHandler( + prompt, + ) + + // Set up the base object + esm := &EncryptedLocalSecretsManager{ + localSM, + cryptHandler, + } + + return esm, esm.Setup() +} + +func (esm *EncryptedLocalSecretsManager) SetSecret(name string, value []byte) error { + encryptedValue, err := esm.cryptHandler.Encrypt(value) + if err != nil { + return err + } + + return esm.LocalSecretsManager.SetSecret(name, encryptedValue) +} + +func (esm *EncryptedLocalSecretsManager) GetSecret(name string) ([]byte, error) { + encryptedValue, err := esm.LocalSecretsManager.GetSecret(name) + if err != nil { + return nil, err + } + + return esm.cryptHandler.Decrypt(encryptedValue) +} diff --git a/secrets/encryptedlocal/encryption.go b/secrets/encryptedlocal/encryption.go new file mode 100644 index 0000000000..d3ef94e7f8 --- /dev/null +++ b/secrets/encryptedlocal/encryption.go @@ -0,0 +1,78 @@ +package encryptedlocal + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "io" +) + +type PasswordHandler interface { + InputPassword() ([]byte, error) +} + +type CryptHandler interface { + Encrypt(data []byte) ([]byte, error) + Decrypt(data []byte) ([]byte, error) +} + +type cryptHandler struct { + passHandler PasswordHandler +} + +func NewCryptHandler(passHandler PasswordHandler) CryptHandler { + return &cryptHandler{ + passHandler: passHandler, + } +} + +func (ch *cryptHandler) Encrypt(data []byte) ([]byte, error) { + key, err := ch.passHandler.InputPassword() + if err != nil { + return nil, err + } + + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + + nonce := make([]byte, gcm.NonceSize()) + + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + + return gcm.Seal(nonce, nonce, data, nil), nil +} + +func (ch *cryptHandler) Decrypt(data []byte) ([]byte, error) { + key, err := ch.passHandler.InputPassword() + if err != nil { + return nil, err + } + + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + + nonceSize := gcm.NonceSize() + if len(data) < nonceSize { + return nil, err + } + + nonce, ciphertext := data[:nonceSize], data[nonceSize:] + + return gcm.Open(nil, nonce, ciphertext, nil) +} diff --git a/secrets/encryptedlocal/prompt.go b/secrets/encryptedlocal/prompt.go new file mode 100644 index 0000000000..2b77a15071 --- /dev/null +++ b/secrets/encryptedlocal/prompt.go @@ -0,0 +1,23 @@ +package encryptedlocal + +import ( + "syscall" + + "golang.org/x/term" +) + +type Prompt struct { +} + +func NewPrompt() *Prompt { + return &Prompt{} +} + +func (p *Prompt) InputPassword() ([]byte, error) { + bytePassword, err := term.ReadPassword(syscall.Stdin) + if err != nil { + return nil, err + } + + return bytePassword, nil +} diff --git a/secrets/helper/helper.go b/secrets/helper/helper.go index 3926cacd50..d1cf74b87d 100644 --- a/secrets/helper/helper.go +++ b/secrets/helper/helper.go @@ -15,12 +15,26 @@ import ( "github.com/0xPolygon/polygon-edge/network" "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/secrets/awsssm" + "github.com/0xPolygon/polygon-edge/secrets/encryptedlocal" "github.com/0xPolygon/polygon-edge/secrets/gcpssm" "github.com/0xPolygon/polygon-edge/secrets/hashicorpvault" "github.com/0xPolygon/polygon-edge/secrets/local" "github.com/0xPolygon/polygon-edge/types" ) +// SetupLocalSecretsManager is a helper method for boilerplate local secrets manager setup +func SetupEncryptedLocalSecretsManager(dataDir string) (secrets.SecretsManager, error) { + return encryptedlocal.SecretsManagerFactory( + nil, // Local secrets manager doesn't require a config + &secrets.SecretsManagerParams{ + Logger: hclog.NewNullLogger(), + Extra: map[string]interface{}{ + secrets.Path: dataDir, + }, + }, + ) +} + // SetupLocalSecretsManager is a helper method for boilerplate local secrets manager setup func SetupLocalSecretsManager(dataDir string) (secrets.SecretsManager, error) { return local.SecretsManagerFactory( @@ -120,15 +134,30 @@ func InitBLSValidatorKey(secretsManager secrets.SecretsManager) ([]byte, error) return pubkeyBytes, nil } -func InitNetworkingPrivateKey(secretsManager secrets.SecretsManager) (libp2pCrypto.PrivKey, error) { +func InitNetworkingPrivateKey(secretsManager secrets.SecretsManager, predefinedSecret []byte) (libp2pCrypto.PrivKey, error) { if secretsManager.HasSecret(secrets.NetworkKey) { return nil, fmt.Errorf(`secrets "%s" has been already initialized`, secrets.NetworkKey) } - // Generate the libp2p private key - libp2pKey, libp2pKeyEncoded, keyErr := network.GenerateAndEncodeLibp2pKey() - if keyErr != nil { - return nil, keyErr + var ( + libp2pKey libp2pCrypto.PrivKey + libp2pKeyEncoded []byte + err error + ) + + if predefinedSecret != nil && len(predefinedSecret) > 0 { + libp2pKey, err = network.ParseLibp2pKey(predefinedSecret) + if err != nil { + return nil, fmt.Errorf("invalid private network key provided: %w", err) + } + + libp2pKeyEncoded = predefinedSecret + } else { + // Generate the libp2p private key + libp2pKey, libp2pKeyEncoded, err = network.GenerateAndEncodeLibp2pKey() + if err != nil { + return nil, err + } } // Write the networking private key to the secrets manager storage @@ -139,7 +168,7 @@ func InitNetworkingPrivateKey(secretsManager secrets.SecretsManager) (libp2pCryp return nil, setErr } - return libp2pKey, keyErr + return libp2pKey, err } // LoadValidatorAddress loads ECDSA key by SecretsManager and returns validator address From 34bb2e1c66b35c9df80e12264f3f6c74b53d2f70 Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Thu, 25 Jan 2024 18:13:49 +0200 Subject: [PATCH 02/12] Improve secrets handling --- command/polybftsecrets/utils.go | 2 +- command/secrets/init/params.go | 2 +- secrets/encryptedlocal/encryptedlocal.go | 53 +++++++- secrets/encryptedlocal/encryption.go | 51 ++++++-- secrets/encryptedlocal/prompt.go | 157 ++++++++++++++++++++++- secrets/helper/helper.go | 5 +- secrets/secrets.go | 13 +- 7 files changed, 259 insertions(+), 24 deletions(-) diff --git a/command/polybftsecrets/utils.go b/command/polybftsecrets/utils.go index e42512389d..a0d0311021 100644 --- a/command/polybftsecrets/utils.go +++ b/command/polybftsecrets/utils.go @@ -53,7 +53,7 @@ func GetSecretsManager(dataPath, configPath string, insecureLocalStore bool) (se // to raise awareness that it should be only used in development/testing environments. // Production setups should use one of the supported secrets managers if !insecureLocalStore { - helper.SetupEncryptedLocalSecretsManager(dataPath) + return helper.SetupEncryptedLocalSecretsManager(dataPath) } return helper.SetupLocalSecretsManager(dataPath) diff --git a/command/secrets/init/params.go b/command/secrets/init/params.go index 77e46de7e2..cc3f9d2594 100644 --- a/command/secrets/init/params.go +++ b/command/secrets/init/params.go @@ -133,7 +133,7 @@ func (ip *initParams) initValidatorKey() error { func (ip *initParams) initNetworkingKey() error { if ip.generatesNetwork { - if _, err := helper.InitNetworkingPrivateKey(ip.secretsManager); err != nil { + if _, err := helper.InitNetworkingPrivateKey(ip.secretsManager, nil); err != nil { return err } } diff --git a/secrets/encryptedlocal/encryptedlocal.go b/secrets/encryptedlocal/encryptedlocal.go index cb2d7da35c..df44eded39 100644 --- a/secrets/encryptedlocal/encryptedlocal.go +++ b/secrets/encryptedlocal/encryptedlocal.go @@ -5,13 +5,17 @@ import ( "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/secrets/local" + "github.com/hashicorp/go-hclog" ) // LocalSecretsManager is a SecretsManager that // stores secrets encrypted locally on disk type EncryptedLocalSecretsManager struct { + prompt *Prompt + logger hclog.Logger *local.LocalSecretsManager cryptHandler CryptHandler + pwd []byte } // SecretsManagerFactory implements the factory method @@ -31,22 +35,49 @@ func SecretsManagerFactory( return nil, errors.New("invalid type assertion") } - prompt := NewPrompt() + prompt := NewPrompt("") cryptHandler := NewCryptHandler( prompt, ) + logger := params.Logger.Named(string(secrets.EncryptedLocal)) // Set up the base object esm := &EncryptedLocalSecretsManager{ + prompt, + logger, localSM, cryptHandler, + nil, } return esm, esm.Setup() } func (esm *EncryptedLocalSecretsManager) SetSecret(name string, value []byte) error { - encryptedValue, err := esm.cryptHandler.Encrypt(value) + esm.logger.Info("Configuring secret", "name", name) + // hexValue := hex.EncodeToString(value) + esm.logger.Info("Here is the raw hex value of your secret. \nPlease copy it and store it in a safe place.", name, string(value)) + + confirmValue, err := esm.prompt.DefaultPrompt("Please rewrite the secret value to confirm that you have copied it down correctly.", "") + if err != nil { + return err + } + + if confirmValue != string(value) { + esm.logger.Error("The secret value you entered does not match the original value. Please try again.") + return errors.New("secret value mismatch") + } else { + esm.logger.Info("The secret value you entered matches the original value. Continuing.") + } + + if esm.pwd == nil || len(esm.pwd) == 0 { + esm.pwd, err = esm.prompt.GeneratePassword() + if err != nil { + return err + } + } + + encryptedValue, err := esm.cryptHandler.Encrypt(value, esm.pwd) if err != nil { return err } @@ -60,5 +91,21 @@ func (esm *EncryptedLocalSecretsManager) GetSecret(name string) ([]byte, error) return nil, err } - return esm.cryptHandler.Decrypt(encryptedValue) + if esm.pwd == nil || len(esm.pwd) == 0 { + esm.pwd, err = esm.prompt.InputPassword(false) + if err != nil { + return nil, err + } + } + + return esm.cryptHandler.Decrypt(encryptedValue, esm.pwd) } + +type SecretHelper interface { + beforeSet(name string, value []byte) error + afterSet(name string) ([]byte, error) +} + +type SecretHelperFactory func() (SecretHelper, error) + +var secretHandlers = map[secrets.SecretType]SecretHelperFactory{} diff --git a/secrets/encryptedlocal/encryption.go b/secrets/encryptedlocal/encryption.go index d3ef94e7f8..5e7b8159c3 100644 --- a/secrets/encryptedlocal/encryption.go +++ b/secrets/encryptedlocal/encryption.go @@ -4,30 +4,36 @@ import ( "crypto/aes" "crypto/cipher" "crypto/rand" + "fmt" "io" + + "golang.org/x/crypto/scrypt" ) type PasswordHandler interface { - InputPassword() ([]byte, error) + GeneratePassword() ([]byte, error) + InputPassword(bool) ([]byte, error) } type CryptHandler interface { - Encrypt(data []byte) ([]byte, error) - Decrypt(data []byte) ([]byte, error) + Encrypt(data []byte, pwd []byte) ([]byte, error) + Decrypt(data []byte, pwd []byte) ([]byte, error) } type cryptHandler struct { passHandler PasswordHandler + pwd string } func NewCryptHandler(passHandler PasswordHandler) CryptHandler { return &cryptHandler{ passHandler: passHandler, + pwd: "", } } -func (ch *cryptHandler) Encrypt(data []byte) ([]byte, error) { - key, err := ch.passHandler.InputPassword() +func (ch *cryptHandler) Encrypt(data []byte, pwd []byte) ([]byte, error) { + key, salt, err := DeriveKey(pwd, nil) if err != nil { return nil, err } @@ -43,16 +49,18 @@ func (ch *cryptHandler) Encrypt(data []byte) ([]byte, error) { } nonce := make([]byte, gcm.NonceSize()) - if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } - return gcm.Seal(nonce, nonce, data, nil), nil + cipherText := gcm.Seal(nonce, nonce, data, nil) + + return append(cipherText, salt...), nil } -func (ch *cryptHandler) Decrypt(data []byte) ([]byte, error) { - key, err := ch.passHandler.InputPassword() +func (ch *cryptHandler) Decrypt(data []byte, pwd []byte) ([]byte, error) { + salt, data := data[len(data)-32:], data[:len(data)-32] + key, _, err := DeriveKey(pwd, salt) if err != nil { return nil, err } @@ -73,6 +81,29 @@ func (ch *cryptHandler) Decrypt(data []byte) ([]byte, error) { } nonce, ciphertext := data[:nonceSize], data[nonceSize:] + fmt.Println("nonce", nonce) + fmt.Println("ciphertext", ciphertext) + fmt.Println("salt", salt) + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, err + } + + return plaintext, nil +} + +func DeriveKey(password, salt []byte) ([]byte, []byte, error) { + if salt == nil { + salt = make([]byte, 32) + if _, err := rand.Read(salt); err != nil { + return nil, nil, err + } + } + + key, err := scrypt.Key(password, salt, 1048576, 8, 1, 32) + if err != nil { + return nil, nil, err + } - return gcm.Open(nil, nonce, ciphertext, nil) + return key, salt, nil } diff --git a/secrets/encryptedlocal/prompt.go b/secrets/encryptedlocal/prompt.go index 2b77a15071..e6181030da 100644 --- a/secrets/encryptedlocal/prompt.go +++ b/secrets/encryptedlocal/prompt.go @@ -1,23 +1,172 @@ package encryptedlocal import ( + "bufio" + "bytes" + "errors" + "fmt" + "os" + "strings" "syscall" + "unicode" "golang.org/x/term" ) +var ( + ErrInvalidPassword = errors.New("Password must contain at least one number, one uppercase letter, one special character, and be at least 8 characters long") + ErrPasswordMismatch = errors.New("Passwords do not match") + ErrTerminatedOperation = errors.New("Operation terminated") +) + type Prompt struct { + terminal *term.Terminal } -func NewPrompt() *Prompt { - return &Prompt{} +func NewPrompt(name string) *Prompt { + terminal := term.NewTerminal(os.Stdin, name) + return &Prompt{ + terminal, + } } -func (p *Prompt) InputPassword() ([]byte, error) { - bytePassword, err := term.ReadPassword(syscall.Stdin) +func (p *Prompt) GeneratePassword() ([]byte, error) { + bytePassword, err := p.InputPassword(true) + if err != nil { + return nil, err + } + + _, err = p.ConfirmPassword(bytePassword) if err != nil { return nil, err } return bytePassword, nil } + +func (p *Prompt) InputPassword(verify bool) ([]byte, error) { + return p.promptUntil(func() ([]byte, error) { + if verify { + fmt.Println("\nYou must generate a password to encrypt your secrets.") + } else { + fmt.Println("\nYou must enter your password to decrypt your secrets.") + } + + fmt.Print("Enter password: ") + bytePassword, err := p.readPassword() + if err != nil { + return nil, err + } + + password := string(bytePassword) + if verify && !verifyPassword(password) { + return nil, ErrInvalidPassword + } + + return bytePassword, nil + }) +} + +func (p *Prompt) ConfirmPassword(password []byte) (pass []byte, err error) { + return p.promptUntil(func() ([]byte, error) { + fmt.Print("\nConfirm password: ") + rePassword, err := p.readPassword() + if err != nil { + return nil, fmt.Errorf("error reading password: %w", err) + } + + if !bytes.Equal(password, rePassword) { + return nil, ErrPasswordMismatch + } + + return pass, err + }) +} + +func (p *Prompt) readPassword() ([]byte, error) { + return term.ReadPassword(syscall.Stdin) +} + +// DefaultPrompt prompts the user for any text and performs no validation. If nothing is entered it returns the default. +func (p *Prompt) DefaultPrompt(promptText, defaultValue string) (string, error) { + var response string + if defaultValue != "" { + fmt.Printf("%s %s:\n", promptText, fmt.Sprintf("(default: %s)", defaultValue)) + } else { + fmt.Printf("%s:\n", promptText) + } + + scanner := bufio.NewScanner(os.Stdin) + if ok := scanner.Scan(); ok { + item := scanner.Text() + response = strings.TrimRight(item, "\r\n") + if response == "" { + return defaultValue, nil + } + return response, nil + } + + return "", errors.New("could not scan text input") +} + +func verifyPassword(s string) (ok bool) { + var ( + number bool + upper bool + special bool + ) + + for _, c := range s { + switch { + case unicode.IsNumber(c): + number = true + case unicode.IsUpper(c): + upper = true + case unicode.IsPunct(c) || unicode.IsSymbol(c): + special = true + } + } + + eightOrMore := len(s) > 7 + + return number && upper && special && eightOrMore +} + +func (p *Prompt) promptUntil(action func() (res []byte, err error)) (res []byte, err error) { + for { + res, err := action() + if err != nil { + fmt.Printf("\n %s \n", err) + agree, err := p.tryAgain() + if err != nil { + return nil, err + } + + if !agree { + return nil, ErrTerminatedOperation + } + + continue + } + + return res, nil + } +} + +func (p *Prompt) tryAgain() (agree bool, err error) { + res, err := p.DefaultPrompt("Try again? [y/n]", "y") + if err != nil { + return false, err + } + + res = strings.ToLower(res) + switch res { + case "y": + return true, nil + case "n": + return false, nil + default: + fmt.Println("Invalid input") + return p.tryAgain() + } +} diff --git a/secrets/helper/helper.go b/secrets/helper/helper.go index d1cf74b87d..352b2f7458 100644 --- a/secrets/helper/helper.go +++ b/secrets/helper/helper.go @@ -27,7 +27,10 @@ func SetupEncryptedLocalSecretsManager(dataDir string) (secrets.SecretsManager, return encryptedlocal.SecretsManagerFactory( nil, // Local secrets manager doesn't require a config &secrets.SecretsManagerParams{ - Logger: hclog.NewNullLogger(), + Logger: hclog.New(&hclog.LoggerOptions{ + Name: "polybft-secrets", + Level: hclog.Info, + }), Extra: map[string]interface{}{ secrets.Path: dataDir, }, diff --git a/secrets/secrets.go b/secrets/secrets.go index d9a9c9070b..6e280f8738 100644 --- a/secrets/secrets.go +++ b/secrets/secrets.go @@ -36,12 +36,14 @@ const ( ValidatorBLSSignature = "validator-bls-signature" ) +type SecretType string + // Define constant file names for the local StorageManager const ( - ValidatorKeyLocal = "validator.key" - ValidatorBLSKeyLocal = "validator-bls.key" - NetworkKeyLocal = "libp2p.key" - ValidatorBLSSignatureLocal = "validator.sig" + ValidatorKeyLocal SecretType = "validator.key" + ValidatorBLSKeyLocal SecretType = "validator-bls.key" + NetworkKeyLocal SecretType = "libp2p.key" + ValidatorBLSSignatureLocal SecretType = "validator.sig" ) // Define constant folder names for the local StorageManager @@ -69,6 +71,9 @@ const ( // GCPSSM pertains to the Google Cloud Computing secret store manager GCPSSM SecretsManagerType = "gcp-ssm" + + // Encrypted Local pertains to the local FS but the data is encrypted with password + EncryptedLocal SecretsManagerType = "encrypted-local" ) // SecretsManager defines the base public interface that all From 879285e2b93ea580242a1058ce75f4897746c6ae Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Mon, 29 Jan 2024 12:26:22 +0200 Subject: [PATCH 03/12] finish encrypted secrets storage implementation --- command/polybftsecrets/params.go | 57 ++++++++++++++++++-- go.mod | 2 +- go.sum | 14 ----- secrets/encryptedlocal/encryptedlocal.go | 69 ++++++++++++++++-------- secrets/encryptedlocal/encryption.go | 4 -- secrets/encryptedlocal/prompt.go | 37 +++++++++++++ secrets/local/local.go | 8 +-- 7 files changed, 142 insertions(+), 49 deletions(-) diff --git a/command/polybftsecrets/params.go b/command/polybftsecrets/params.go index 695524ff1a..6e2be5f694 100644 --- a/command/polybftsecrets/params.go +++ b/command/polybftsecrets/params.go @@ -6,11 +6,13 @@ import ( "strings" "github.com/0xPolygon/polygon-edge/command" + bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/secrets/helper" "github.com/0xPolygon/polygon-edge/types" "github.com/spf13/cobra" + ethWallet "github.com/umbracle/ethgo/wallet" ) const ( @@ -22,6 +24,8 @@ const ( outputFlag = "output" chainIDFlag = "chain-id" networkKeyFlag = "network-key" + ecdsaKeyFlag = "ecdsa-key" + blsKeyFlag = "bls-key" // maxInitNum is the maximum value for "num" flag maxInitNum = 30 @@ -45,6 +49,8 @@ type initParams struct { chainID int64 networkKey string + ecdsaKey string + blsKey string } func (ip *initParams) validateFlags() error { @@ -88,6 +94,20 @@ func (ip *initParams) setFlags(cmd *cobra.Command) { "the flag providing already created network key to be used", ) + cmd.Flags().StringVar( + &ip.ecdsaKey, + ecdsaKeyFlag, + "", + "the flag providing already created ecdsa key to be used", + ) + + cmd.Flags().StringVar( + &ip.blsKey, + blsKeyFlag, + "", + "the flag providing already created bls key to be used", + ) + // Don't accept data-dir and config flags because they are related to different secrets managers. // data-dir is about the local FS as secrets storage, config is about remote secrets manager. cmd.MarkFlagsMutuallyExclusive(AccountDirFlag, AccountConfigFlag) @@ -188,7 +208,12 @@ func (ip *initParams) initKeys(secretsManager secrets.SecretsManager) ([]string, } generated = append(generated, secrets.NetworkKey) + } else { + if ip.networkKey != "" { + return generated, fmt.Errorf("network-key already exists") + } } + } if ip.generatesAccount { @@ -198,9 +223,31 @@ func (ip *initParams) initKeys(secretsManager secrets.SecretsManager) ([]string, ) if !secretsManager.HasSecret(secrets.ValidatorKey) && !secretsManager.HasSecret(secrets.ValidatorBLSKey) { - a, err = wallet.GenerateAccount() - if err != nil { - return generated, fmt.Errorf("error generating account: %w", err) + if ip.ecdsaKey != "" && ip.blsKey != "" { + blsKey, err := bls.UnmarshalPrivateKey([]byte(ip.blsKey)) + if err != nil { + return nil, fmt.Errorf("failed to retrieve bls key: %w", err) + } + + ecdsaRaw, err := hex.DecodeString(ip.ecdsaKey) + if err != nil { + return nil, fmt.Errorf("failed to retrieve ecdsa key: %w", err) + } + + key, err := ethWallet.NewWalletFromPrivKey(ecdsaRaw) + if err != nil { + return nil, fmt.Errorf("failed to retrieve ecdsa key: %w", err) + } + + a = &wallet.Account{ + Ecdsa: key, + Bls: blsKey, + } + } else { + a, err = wallet.GenerateAccount() + if err != nil { + return generated, fmt.Errorf("error generating account: %w", err) + } } if err = a.Save(secretsManager); err != nil { @@ -209,6 +256,10 @@ func (ip *initParams) initKeys(secretsManager secrets.SecretsManager) ([]string, generated = append(generated, secrets.ValidatorKey, secrets.ValidatorBLSKey) } else { + if ip.ecdsaKey != "" || ip.blsKey != "" { + return generated, fmt.Errorf("ecdsa-key or bls-key already exists") + } + a, err = wallet.NewAccountFromSecret(secretsManager) if err != nil { return generated, fmt.Errorf("error loading account: %w", err) diff --git a/go.mod b/go.mod index dfb292cf29..0760991a89 100644 --- a/go.mod +++ b/go.mod @@ -69,6 +69,7 @@ require ( github.com/quasilyte/go-ruleguard/dsl v0.3.22 github.com/sethvargo/go-retry v0.2.4 golang.org/x/sync v0.4.0 + golang.org/x/term v0.16.0 google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 gopkg.in/DataDog/dd-trace-go.v1 v1.55.0 pgregory.net/rapid v1.1.0 @@ -99,7 +100,6 @@ require ( go.uber.org/dig v1.16.1 // indirect go.uber.org/fx v1.19.2 // indirect golang.org/x/exp v0.0.0-20230725012225-302865e7556b // indirect - golang.org/x/term v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect nhooyr.io/websocket v1.8.7 // indirect diff --git a/go.sum b/go.sum index 2ac860ce08..b6dbbb1bbb 100644 --- a/go.sum +++ b/go.sum @@ -81,9 +81,7 @@ github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pY github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= @@ -95,7 +93,6 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -147,7 +144,6 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6Uh github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= @@ -204,7 +200,6 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -379,20 +374,16 @@ github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABo github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -494,7 +485,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -526,7 +516,6 @@ github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -802,7 +791,6 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -920,8 +908,6 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/secrets/encryptedlocal/encryptedlocal.go b/secrets/encryptedlocal/encryptedlocal.go index df44eded39..2eba4d89cf 100644 --- a/secrets/encryptedlocal/encryptedlocal.go +++ b/secrets/encryptedlocal/encryptedlocal.go @@ -55,34 +55,18 @@ func SecretsManagerFactory( func (esm *EncryptedLocalSecretsManager) SetSecret(name string, value []byte) error { esm.logger.Info("Configuring secret", "name", name) - // hexValue := hex.EncodeToString(value) - esm.logger.Info("Here is the raw hex value of your secret. \nPlease copy it and store it in a safe place.", name, string(value)) - - confirmValue, err := esm.prompt.DefaultPrompt("Please rewrite the secret value to confirm that you have copied it down correctly.", "") - if err != nil { - return err - } - - if confirmValue != string(value) { - esm.logger.Error("The secret value you entered does not match the original value. Please try again.") - return errors.New("secret value mismatch") - } else { - esm.logger.Info("The secret value you entered matches the original value. Continuing.") - } - if esm.pwd == nil || len(esm.pwd) == 0 { - esm.pwd, err = esm.prompt.GeneratePassword() + onSetHandler, ok := onSetHandlers[secrets.SecretType(name)] + if ok { + res, err := onSetHandler(esm, name, value) if err != nil { return err } - } - encryptedValue, err := esm.cryptHandler.Encrypt(value, esm.pwd) - if err != nil { - return err + value = res } - return esm.LocalSecretsManager.SetSecret(name, encryptedValue) + return esm.LocalSecretsManager.SetSecret(name, value) } func (esm *EncryptedLocalSecretsManager) GetSecret(name string) ([]byte, error) { @@ -106,6 +90,45 @@ type SecretHelper interface { afterSet(name string) ([]byte, error) } -type SecretHelperFactory func() (SecretHelper, error) +type OnSetHandlerFunc func(esm *EncryptedLocalSecretsManager, name string, value []byte) ([]byte, error) + +var onSetHandlers = map[secrets.SecretType]OnSetHandlerFunc{ + secrets.NetworkKey: baseOnSetHandler, + secrets.ValidatorBLSKey: baseOnSetHandler, + secrets.ValidatorKey: baseOnSetHandler, +} + +func baseOnSetHandler(esm *EncryptedLocalSecretsManager, name string, value []byte) ([]byte, error) { + // hexValue := hex.EncodeToString(value) + esm.logger.Info("Here is the raw hex value of your secret. \nPlease copy it and store it in a safe place.", name, string(value)) + + confirmValue, err := esm.prompt.DefaultPrompt("Please rewrite the secret value to confirm that you have copied it down correctly.", "") + if err != nil { + return nil, err + } + + if confirmValue != string(value) { + esm.logger.Error("The secret value you entered does not match the original value. Please try again.") + return nil, errors.New("secret value mismatch") + } else { + esm.logger.Info("The secret value you entered matches the original value. Continuing.") + } + + if esm.pwd == nil || len(esm.pwd) == 0 { + esm.pwd, err = esm.prompt.GeneratePassword() + if err != nil { + return nil, err + } + } + + encryptedValue, err := esm.cryptHandler.Encrypt(value, esm.pwd) + if err != nil { + return nil, err + } + + return encryptedValue, nil +} -var secretHandlers = map[secrets.SecretType]SecretHelperFactory{} +func ecdsaKeyOnSetHandler(esm *EncryptedLocalSecretsManager, name string, value []byte) ([]byte, error) { + return nil, nil +} diff --git a/secrets/encryptedlocal/encryption.go b/secrets/encryptedlocal/encryption.go index 5e7b8159c3..8dcb8292a5 100644 --- a/secrets/encryptedlocal/encryption.go +++ b/secrets/encryptedlocal/encryption.go @@ -4,7 +4,6 @@ import ( "crypto/aes" "crypto/cipher" "crypto/rand" - "fmt" "io" "golang.org/x/crypto/scrypt" @@ -81,9 +80,6 @@ func (ch *cryptHandler) Decrypt(data []byte, pwd []byte) ([]byte, error) { } nonce, ciphertext := data[:nonceSize], data[nonceSize:] - fmt.Println("nonce", nonce) - fmt.Println("ciphertext", ciphertext) - fmt.Println("salt", salt) plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, err diff --git a/secrets/encryptedlocal/prompt.go b/secrets/encryptedlocal/prompt.go index e6181030da..c2a2257966 100644 --- a/secrets/encryptedlocal/prompt.go +++ b/secrets/encryptedlocal/prompt.go @@ -44,6 +44,43 @@ func (p *Prompt) GeneratePassword() ([]byte, error) { return bytePassword, nil } +type MnemonicGenerator interface { + GenerateMnemonic() (string, error) +} + +func (p *Prompt) GenerateMnemonic(generator MnemonicGenerator) (string, error) { + fmt.Println("\nWe must generate a mnemonic which will represent your node account.") + fmt.Println("\nKeep it safe and do not share it with anyone.") + fmt.Println("\nYou will need this mnemonic to recover your node account if you lose it.") + start, err := p.DefaultPrompt("Do you want to start the process? [y/n]", "y") + if err != nil { + return "", err + } + + start = strings.ToLower(start) + if start != "y" { + return "", ErrTerminatedOperation + } + + mnemonic, err := generator.GenerateMnemonic() + + fmt.Println("\nHere is your mnemonic. Please copy it and store it in a safe place.") + repeatMnemonic, err := p.DefaultPrompt("Please rewrite the mnemonic to confirm that you have copied it down correctly.", "") + if err != nil { + return "", err + } + + if repeatMnemonic != mnemonic { + return "", errors.New("mnemonic mismatch") + } + + if err != nil { + return "", err + } + + return mnemonic, nil +} + func (p *Prompt) InputPassword(verify bool) ([]byte, error) { return p.promptUntil(func() ([]byte, error) { if verify { diff --git a/secrets/local/local.go b/secrets/local/local.go index dcf44de407..7c1abdc911 100644 --- a/secrets/local/local.go +++ b/secrets/local/local.go @@ -74,28 +74,28 @@ func (l *LocalSecretsManager) Setup() error { l.secretPathMap[secrets.ValidatorKey] = filepath.Join( l.path, secrets.ConsensusFolderLocal, - secrets.ValidatorKeyLocal, + string(secrets.ValidatorKeyLocal), ) // baseDir/consensus/validator-bls.key l.secretPathMap[secrets.ValidatorBLSKey] = filepath.Join( l.path, secrets.ConsensusFolderLocal, - secrets.ValidatorBLSKeyLocal, + string(secrets.ValidatorBLSKeyLocal), ) // baseDir/consensus/validator.sig l.secretPathMap[secrets.ValidatorBLSSignature] = filepath.Join( l.path, secrets.ConsensusFolderLocal, - secrets.ValidatorBLSSignatureLocal, + string(secrets.ValidatorBLSSignatureLocal), ) // baseDir/libp2p/libp2p.key l.secretPathMap[secrets.NetworkKey] = filepath.Join( l.path, secrets.NetworkFolderLocal, - secrets.NetworkKeyLocal, + string(secrets.NetworkKeyLocal), ) return nil From 974bc336b6e797e065d080f3170158a97678dc07 Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Mon, 29 Jan 2024 14:33:56 +0200 Subject: [PATCH 04/12] Modify mutually exclusive params --- command/polybftsecrets/params.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/command/polybftsecrets/params.go b/command/polybftsecrets/params.go index 6e2be5f694..e3c3555d9f 100644 --- a/command/polybftsecrets/params.go +++ b/command/polybftsecrets/params.go @@ -108,15 +108,6 @@ func (ip *initParams) setFlags(cmd *cobra.Command) { "the flag providing already created bls key to be used", ) - // Don't accept data-dir and config flags because they are related to different secrets managers. - // data-dir is about the local FS as secrets storage, config is about remote secrets manager. - cmd.MarkFlagsMutuallyExclusive(AccountDirFlag, AccountConfigFlag) - - // num flag should be used with data-dir flag only so it should not be used with config flag. - cmd.MarkFlagsMutuallyExclusive(numFlag, AccountConfigFlag) - - cmd.MarkFlagsMutuallyExclusive(numFlag, networkKeyFlag) - cmd.Flags().BoolVar( &ip.generatesAccount, accountFlag, @@ -158,6 +149,23 @@ func (ip *initParams) setFlags(cmd *cobra.Command) { command.DefaultChainID, "the ID of the chain", ) + + // Don't accept data-dir and config flags because they are related to different secrets managers. + // data-dir is about the local FS as secrets storage, config is about remote secrets manager. + cmd.MarkFlagsMutuallyExclusive(AccountDirFlag, AccountConfigFlag) + + // num flag should be used with data-dir flag only so it should not be used with config flag. + cmd.MarkFlagsMutuallyExclusive(numFlag, AccountConfigFlag) + + // Encryptedlocal secrets manager with preset keys can be setup for a single bunch of secrets only, so num flag is not allowed. + cmd.MarkFlagsMutuallyExclusive(numFlag, networkKeyFlag) + cmd.MarkFlagsMutuallyExclusive(numFlag, blsKeyFlag) + cmd.MarkFlagsMutuallyExclusive(numFlag, ecdsaKeyFlag) + + // network-key, ecdsa-key and bls-key flags should be used with data-dir flag only because they are related to local FS. + cmd.MarkFlagsMutuallyExclusive(AccountConfigFlag, networkKeyFlag) + cmd.MarkFlagsMutuallyExclusive(AccountConfigFlag, blsKeyFlag) + cmd.MarkFlagsMutuallyExclusive(AccountConfigFlag, ecdsaKeyFlag) } func (ip *initParams) Execute() (Results, error) { From 04b0beebdefb6aa4206a0c9ef8ed48c24054e229 Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Mon, 29 Jan 2024 14:52:02 +0200 Subject: [PATCH 05/12] Modify required together flags and fix return value of initKeys --- command/polybftsecrets/params.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/command/polybftsecrets/params.go b/command/polybftsecrets/params.go index e3c3555d9f..1bdd97f65f 100644 --- a/command/polybftsecrets/params.go +++ b/command/polybftsecrets/params.go @@ -166,6 +166,9 @@ func (ip *initParams) setFlags(cmd *cobra.Command) { cmd.MarkFlagsMutuallyExclusive(AccountConfigFlag, networkKeyFlag) cmd.MarkFlagsMutuallyExclusive(AccountConfigFlag, blsKeyFlag) cmd.MarkFlagsMutuallyExclusive(AccountConfigFlag, ecdsaKeyFlag) + + // Currently we handle ecdsaKey and blsKey generation from flag together only. + cmd.MarkFlagsRequiredTogether(ecdsaKeyFlag, blsKeyFlag) } func (ip *initParams) Execute() (Results, error) { @@ -221,7 +224,6 @@ func (ip *initParams) initKeys(secretsManager secrets.SecretsManager) ([]string, return generated, fmt.Errorf("network-key already exists") } } - } if ip.generatesAccount { @@ -234,17 +236,17 @@ func (ip *initParams) initKeys(secretsManager secrets.SecretsManager) ([]string, if ip.ecdsaKey != "" && ip.blsKey != "" { blsKey, err := bls.UnmarshalPrivateKey([]byte(ip.blsKey)) if err != nil { - return nil, fmt.Errorf("failed to retrieve bls key: %w", err) + return generated, fmt.Errorf("failed to retrieve bls key: %w", err) } ecdsaRaw, err := hex.DecodeString(ip.ecdsaKey) if err != nil { - return nil, fmt.Errorf("failed to retrieve ecdsa key: %w", err) + return generated, fmt.Errorf("failed to retrieve ecdsa key: %w", err) } key, err := ethWallet.NewWalletFromPrivKey(ecdsaRaw) if err != nil { - return nil, fmt.Errorf("failed to retrieve ecdsa key: %w", err) + return generated, fmt.Errorf("failed to retrieve ecdsa key: %w", err) } a = &wallet.Account{ From 5618f79ad16a83fbd8954738a9a0e930aa48e310 Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Mon, 29 Jan 2024 14:55:17 +0200 Subject: [PATCH 06/12] Fix comments --- command/polybftsecrets/utils.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/command/polybftsecrets/utils.go b/command/polybftsecrets/utils.go index a0d0311021..668bcc1a74 100644 --- a/command/polybftsecrets/utils.go +++ b/command/polybftsecrets/utils.go @@ -49,9 +49,8 @@ func GetSecretsManager(dataPath, configPath string, insecureLocalStore bool) (se return helper.InitCloudSecretsManager(secretsConfig) } - // Storing secrets on a local file system should only be allowed with --insecure flag, - // to raise awareness that it should be only used in development/testing environments. - // Production setups should use one of the supported secrets managers + // Storing secrets on a local file system should only be allowed when files encrypted with password only. + // Otherwsie --insecure flag must be added if !insecureLocalStore { return helper.SetupEncryptedLocalSecretsManager(dataPath) } From 470c213fb5124067409de1d0a8049adab23ac2ec Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Mon, 29 Jan 2024 14:56:30 +0200 Subject: [PATCH 07/12] Remove redundant func --- command/polybftsecrets/utils.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/command/polybftsecrets/utils.go b/command/polybftsecrets/utils.go index 668bcc1a74..d365807dd4 100644 --- a/command/polybftsecrets/utils.go +++ b/command/polybftsecrets/utils.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/0xPolygon/polygon-edge/secrets" - "github.com/0xPolygon/polygon-edge/secrets/encryptedlocal" "github.com/0xPolygon/polygon-edge/secrets/helper" ) @@ -57,8 +56,3 @@ func GetSecretsManager(dataPath, configPath string, insecureLocalStore bool) (se return helper.SetupLocalSecretsManager(dataPath) } - -func isEncryptedLocalSecretsManager(sm secrets.SecretsManager) bool { - _, ok := sm.(*encryptedlocal.EncryptedLocalSecretsManager) - return ok -} From db105ac734800115daad03155d3ac54308eb274a Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Mon, 29 Jan 2024 15:04:00 +0200 Subject: [PATCH 08/12] Remove redundant type and simplify logic --- secrets/encryptedlocal/encryptedlocal.go | 4 ++-- secrets/local/local.go | 8 ++++---- secrets/secrets.go | 10 ++++------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/secrets/encryptedlocal/encryptedlocal.go b/secrets/encryptedlocal/encryptedlocal.go index 2eba4d89cf..f9a09ebdb6 100644 --- a/secrets/encryptedlocal/encryptedlocal.go +++ b/secrets/encryptedlocal/encryptedlocal.go @@ -56,7 +56,7 @@ func SecretsManagerFactory( func (esm *EncryptedLocalSecretsManager) SetSecret(name string, value []byte) error { esm.logger.Info("Configuring secret", "name", name) - onSetHandler, ok := onSetHandlers[secrets.SecretType(name)] + onSetHandler, ok := onSetHandlers[name] if ok { res, err := onSetHandler(esm, name, value) if err != nil { @@ -92,7 +92,7 @@ type SecretHelper interface { type OnSetHandlerFunc func(esm *EncryptedLocalSecretsManager, name string, value []byte) ([]byte, error) -var onSetHandlers = map[secrets.SecretType]OnSetHandlerFunc{ +var onSetHandlers = map[string]OnSetHandlerFunc{ secrets.NetworkKey: baseOnSetHandler, secrets.ValidatorBLSKey: baseOnSetHandler, secrets.ValidatorKey: baseOnSetHandler, diff --git a/secrets/local/local.go b/secrets/local/local.go index 7c1abdc911..dcf44de407 100644 --- a/secrets/local/local.go +++ b/secrets/local/local.go @@ -74,28 +74,28 @@ func (l *LocalSecretsManager) Setup() error { l.secretPathMap[secrets.ValidatorKey] = filepath.Join( l.path, secrets.ConsensusFolderLocal, - string(secrets.ValidatorKeyLocal), + secrets.ValidatorKeyLocal, ) // baseDir/consensus/validator-bls.key l.secretPathMap[secrets.ValidatorBLSKey] = filepath.Join( l.path, secrets.ConsensusFolderLocal, - string(secrets.ValidatorBLSKeyLocal), + secrets.ValidatorBLSKeyLocal, ) // baseDir/consensus/validator.sig l.secretPathMap[secrets.ValidatorBLSSignature] = filepath.Join( l.path, secrets.ConsensusFolderLocal, - string(secrets.ValidatorBLSSignatureLocal), + secrets.ValidatorBLSSignatureLocal, ) // baseDir/libp2p/libp2p.key l.secretPathMap[secrets.NetworkKey] = filepath.Join( l.path, secrets.NetworkFolderLocal, - string(secrets.NetworkKeyLocal), + secrets.NetworkKeyLocal, ) return nil diff --git a/secrets/secrets.go b/secrets/secrets.go index 6e280f8738..13635c4141 100644 --- a/secrets/secrets.go +++ b/secrets/secrets.go @@ -36,14 +36,12 @@ const ( ValidatorBLSSignature = "validator-bls-signature" ) -type SecretType string - // Define constant file names for the local StorageManager const ( - ValidatorKeyLocal SecretType = "validator.key" - ValidatorBLSKeyLocal SecretType = "validator-bls.key" - NetworkKeyLocal SecretType = "libp2p.key" - ValidatorBLSSignatureLocal SecretType = "validator.sig" + ValidatorKeyLocal = "validator.key" + ValidatorBLSKeyLocal = "validator-bls.key" + NetworkKeyLocal = "libp2p.key" + ValidatorBLSSignatureLocal = "validator.sig" ) // Define constant folder names for the local StorageManager From ad4c45a7b43dd2508cff5328f9b9577c12801304 Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Mon, 29 Jan 2024 15:10:00 +0200 Subject: [PATCH 09/12] Modify func docs --- secrets/helper/helper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/secrets/helper/helper.go b/secrets/helper/helper.go index 352b2f7458..f8489ce926 100644 --- a/secrets/helper/helper.go +++ b/secrets/helper/helper.go @@ -22,7 +22,7 @@ import ( "github.com/0xPolygon/polygon-edge/types" ) -// SetupLocalSecretsManager is a helper method for boilerplate local secrets manager setup +// SetupEncryptedLocalSecretsManager is a helper method for encrypted local secrets manager setup func SetupEncryptedLocalSecretsManager(dataDir string) (secrets.SecretsManager, error) { return encryptedlocal.SecretsManagerFactory( nil, // Local secrets manager doesn't require a config From 46f1e66d1400ee3b41b3f1056f0a117045e88e0b Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Mon, 29 Jan 2024 15:41:07 +0200 Subject: [PATCH 10/12] refactoring --- secrets/encryptedlocal/encryptedlocal.go | 58 +++++++++++++----------- secrets/encryptedlocal/encryption.go | 17 +++---- secrets/encryptedlocal/prompt.go | 8 +--- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/secrets/encryptedlocal/encryptedlocal.go b/secrets/encryptedlocal/encryptedlocal.go index f9a09ebdb6..f8098b464c 100644 --- a/secrets/encryptedlocal/encryptedlocal.go +++ b/secrets/encryptedlocal/encryptedlocal.go @@ -8,14 +8,14 @@ import ( "github.com/hashicorp/go-hclog" ) -// LocalSecretsManager is a SecretsManager that +// EncryptedLocalSecretsManager is a SecretsManager that // stores secrets encrypted locally on disk type EncryptedLocalSecretsManager struct { prompt *Prompt logger hclog.Logger *local.LocalSecretsManager - cryptHandler CryptHandler - pwd []byte + encryption Encryption + pwd []byte } // SecretsManagerFactory implements the factory method @@ -35,27 +35,23 @@ func SecretsManagerFactory( return nil, errors.New("invalid type assertion") } - prompt := NewPrompt("") - cryptHandler := NewCryptHandler( - prompt, - ) - + prompt := NewPrompt() + encryption := NewEncryption() logger := params.Logger.Named(string(secrets.EncryptedLocal)) // Set up the base object esm := &EncryptedLocalSecretsManager{ prompt, logger, localSM, - cryptHandler, + encryption, nil, } - return esm, esm.Setup() + return esm, nil } func (esm *EncryptedLocalSecretsManager) SetSecret(name string, value []byte) error { esm.logger.Info("Configuring secret", "name", name) - onSetHandler, ok := onSetHandlers[name] if ok { res, err := onSetHandler(esm, name, value) @@ -70,38 +66,34 @@ func (esm *EncryptedLocalSecretsManager) SetSecret(name string, value []byte) er } func (esm *EncryptedLocalSecretsManager) GetSecret(name string) ([]byte, error) { - encryptedValue, err := esm.LocalSecretsManager.GetSecret(name) + value, err := esm.LocalSecretsManager.GetSecret(name) if err != nil { return nil, err } - if esm.pwd == nil || len(esm.pwd) == 0 { - esm.pwd, err = esm.prompt.InputPassword(false) + onGetHandler, ok := onGetHandlers[name] + if ok { + value, err = onGetHandler(esm, name, value) if err != nil { return nil, err } } - return esm.cryptHandler.Decrypt(encryptedValue, esm.pwd) + return value, nil } -type SecretHelper interface { - beforeSet(name string, value []byte) error - afterSet(name string) ([]byte, error) -} +// --------- Custom Additional handlers --------- -type OnSetHandlerFunc func(esm *EncryptedLocalSecretsManager, name string, value []byte) ([]byte, error) +type AdditionalHandlerFunc func(esm *EncryptedLocalSecretsManager, name string, value []byte) ([]byte, error) -var onSetHandlers = map[string]OnSetHandlerFunc{ +var onSetHandlers = map[string]AdditionalHandlerFunc{ secrets.NetworkKey: baseOnSetHandler, secrets.ValidatorBLSKey: baseOnSetHandler, secrets.ValidatorKey: baseOnSetHandler, } func baseOnSetHandler(esm *EncryptedLocalSecretsManager, name string, value []byte) ([]byte, error) { - // hexValue := hex.EncodeToString(value) esm.logger.Info("Here is the raw hex value of your secret. \nPlease copy it and store it in a safe place.", name, string(value)) - confirmValue, err := esm.prompt.DefaultPrompt("Please rewrite the secret value to confirm that you have copied it down correctly.", "") if err != nil { return nil, err @@ -121,7 +113,7 @@ func baseOnSetHandler(esm *EncryptedLocalSecretsManager, name string, value []by } } - encryptedValue, err := esm.cryptHandler.Encrypt(value, esm.pwd) + encryptedValue, err := esm.encryption.Encrypt(value, esm.pwd) if err != nil { return nil, err } @@ -129,6 +121,20 @@ func baseOnSetHandler(esm *EncryptedLocalSecretsManager, name string, value []by return encryptedValue, nil } -func ecdsaKeyOnSetHandler(esm *EncryptedLocalSecretsManager, name string, value []byte) ([]byte, error) { - return nil, nil +var onGetHandlers = map[string]AdditionalHandlerFunc{ + secrets.NetworkKey: baseOnGetHandler, + secrets.ValidatorBLSKey: baseOnGetHandler, + secrets.ValidatorKey: baseOnGetHandler, +} + +func baseOnGetHandler(esm *EncryptedLocalSecretsManager, name string, value []byte) ([]byte, error) { + if esm.pwd == nil || len(esm.pwd) == 0 { + var err error + esm.pwd, err = esm.prompt.InputPassword(false) + if err != nil { + return nil, err + } + } + + return esm.encryption.Decrypt(value, esm.pwd) } diff --git a/secrets/encryptedlocal/encryption.go b/secrets/encryptedlocal/encryption.go index 8dcb8292a5..85130a32d2 100644 --- a/secrets/encryptedlocal/encryption.go +++ b/secrets/encryptedlocal/encryption.go @@ -14,24 +14,19 @@ type PasswordHandler interface { InputPassword(bool) ([]byte, error) } -type CryptHandler interface { +type Encryption interface { Encrypt(data []byte, pwd []byte) ([]byte, error) Decrypt(data []byte, pwd []byte) ([]byte, error) } -type cryptHandler struct { - passHandler PasswordHandler - pwd string +type encryption struct { } -func NewCryptHandler(passHandler PasswordHandler) CryptHandler { - return &cryptHandler{ - passHandler: passHandler, - pwd: "", - } +func NewEncryption() Encryption { + return &encryption{} } -func (ch *cryptHandler) Encrypt(data []byte, pwd []byte) ([]byte, error) { +func (ch *encryption) Encrypt(data []byte, pwd []byte) ([]byte, error) { key, salt, err := DeriveKey(pwd, nil) if err != nil { return nil, err @@ -57,7 +52,7 @@ func (ch *cryptHandler) Encrypt(data []byte, pwd []byte) ([]byte, error) { return append(cipherText, salt...), nil } -func (ch *cryptHandler) Decrypt(data []byte, pwd []byte) ([]byte, error) { +func (ch *encryption) Decrypt(data []byte, pwd []byte) ([]byte, error) { salt, data := data[len(data)-32:], data[:len(data)-32] key, _, err := DeriveKey(pwd, salt) if err != nil { diff --git a/secrets/encryptedlocal/prompt.go b/secrets/encryptedlocal/prompt.go index c2a2257966..640a107080 100644 --- a/secrets/encryptedlocal/prompt.go +++ b/secrets/encryptedlocal/prompt.go @@ -20,14 +20,10 @@ var ( ) type Prompt struct { - terminal *term.Terminal } -func NewPrompt(name string) *Prompt { - terminal := term.NewTerminal(os.Stdin, name) - return &Prompt{ - terminal, - } +func NewPrompt() *Prompt { + return &Prompt{} } func (p *Prompt) GeneratePassword() ([]byte, error) { From b084b1fffe5c6865fa868160acd73a216f77e5f8 Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Mon, 29 Jan 2024 15:46:06 +0200 Subject: [PATCH 11/12] remove comment --- secrets/encryptedlocal/encryptedlocal.go | 1 - 1 file changed, 1 deletion(-) diff --git a/secrets/encryptedlocal/encryptedlocal.go b/secrets/encryptedlocal/encryptedlocal.go index f8098b464c..e849a70715 100644 --- a/secrets/encryptedlocal/encryptedlocal.go +++ b/secrets/encryptedlocal/encryptedlocal.go @@ -38,7 +38,6 @@ func SecretsManagerFactory( prompt := NewPrompt() encryption := NewEncryption() logger := params.Logger.Named(string(secrets.EncryptedLocal)) - // Set up the base object esm := &EncryptedLocalSecretsManager{ prompt, logger, From b29ee54a0d0c7870cb743bfe614a507828a2be0a Mon Sep 17 00:00:00 2001 From: Rosen Santev Date: Wed, 14 Feb 2024 09:31:15 +0200 Subject: [PATCH 12/12] Fix typos --- command/polybftsecrets/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/command/polybftsecrets/utils.go b/command/polybftsecrets/utils.go index d365807dd4..dd7f9ce4c3 100644 --- a/command/polybftsecrets/utils.go +++ b/command/polybftsecrets/utils.go @@ -48,8 +48,8 @@ func GetSecretsManager(dataPath, configPath string, insecureLocalStore bool) (se return helper.InitCloudSecretsManager(secretsConfig) } - // Storing secrets on a local file system should only be allowed when files encrypted with password only. - // Otherwsie --insecure flag must be added + // Storing secrets on the local file system should be allowed only when files are encrypted with password. + // For plaintext storage of the secrets --insecure flag must be added if !insecureLocalStore { return helper.SetupEncryptedLocalSecretsManager(dataPath) }