@@ -2,6 +2,7 @@ package crypto
2
2
3
3
import (
4
4
"bytes"
5
+ "crypto/sha256"
5
6
"encoding/hex"
6
7
"fmt"
7
8
"io"
@@ -16,6 +17,8 @@ import (
16
17
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
17
18
"github.com/cosmos/cosmos-sdk/crypto/xsalsa20symmetric"
18
19
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
20
+
21
+ pdkdf2 "golang.org/x/crypto/pbkdf2"
19
22
)
20
23
21
24
const (
@@ -149,13 +152,12 @@ func EncryptArmorPrivKey(privKey cryptotypes.PrivKey, passphrase string, algo st
149
152
// encrypted priv key.
150
153
func encryptPrivKey (privKey cryptotypes.PrivKey , passphrase string ) (saltBytes []byte , encBytes []byte ) {
151
154
saltBytes = crypto .CRandBytes (16 )
152
- key , err := bcrypt .GenerateFromPassword (saltBytes , []byte (passphrase ), BcryptSecurityParameter )
153
- if err != nil {
154
- panic (errorsmod .Wrap (err , "error generating bcrypt key from passphrase" ))
155
- }
156
-
155
+ key := pdkdf2 .Key ([]byte (passphrase ), saltBytes , int (BcryptSecurityParameter ), 60 , sha256 .New )
157
156
key = crypto .Sha256 (key ) // get 32 bytes
157
+
158
158
privKeyBytes := legacy .Cdc .MustMarshal (privKey )
159
+ privKeyBytesHash := crypto .Sha256 (privKeyBytes )
160
+ privKeyBytes = append (privKeyBytes , privKeyBytesHash ... ) // Add own hash to differentiate it from old implementation
159
161
160
162
return saltBytes , xsalsa20symmetric .EncryptSymmetric (privKeyBytes , key )
161
163
}
@@ -194,21 +196,47 @@ func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey cryptoty
194
196
}
195
197
196
198
func decryptPrivKey (saltBytes []byte , encBytes []byte , passphrase string ) (privKey cryptotypes.PrivKey , err error ) {
197
- key , err := bcrypt .GenerateFromPassword (saltBytes , []byte (passphrase ), BcryptSecurityParameter )
199
+ key := pdkdf2 .Key ([]byte (passphrase ), saltBytes , int (BcryptSecurityParameter ), 60 , sha256 .New )
200
+
201
+ var privKeyBytes []byte
202
+
203
+ decryptedPrivBytes , err := decryptSymmetric (encBytes , key )
204
+ if err == nil && len (decryptedPrivBytes ) > 32 {
205
+ privBytes := decryptedPrivBytes [:len (decryptedPrivBytes )- 32 ]
206
+ privBytesHash := decryptedPrivBytes [len (decryptedPrivBytes )- 32 :] // SHA-256 hash is 32 bytes
207
+ // If the decrypted hash doesn't match the privateBytes hash, then we are working with the old bcrypt algorithm
208
+ if ! bytes .Equal (crypto .Sha256 (privBytes ), privBytesHash ) {
209
+ privBytes , err = legacyDecryptPrivKey (saltBytes , encBytes , passphrase )
210
+ }
211
+ privKeyBytes = privBytes
212
+ } else {
213
+ privKeyBytes , err = legacyDecryptPrivKey (saltBytes , encBytes , passphrase )
214
+ }
215
+
198
216
if err != nil {
199
- return privKey , errorsmod . Wrap ( err , "error generating bcrypt key from passphrase" )
217
+ return privKey , err
200
218
}
201
219
202
- key = crypto .Sha256 (key ) // Get 32 bytes
220
+ return legacy .PrivKeyFromBytes (privKeyBytes )
221
+ }
203
222
204
- privKeyBytes , err := xsalsa20symmetric .DecryptSymmetric (encBytes , key )
205
- if err != nil && err == xsalsa20symmetric .ErrCiphertextDecrypt {
206
- return privKey , sdkerrors .ErrWrongPassword
223
+ func decryptSymmetric (encBytes []byte , key []byte ) (privKeyBytes []byte , err error ) {
224
+ key = crypto .Sha256 (key )
225
+ privKeyBytes , err = xsalsa20symmetric .DecryptSymmetric (encBytes , key )
226
+ if err != nil && err .Error () == "ciphertext decryption failed" {
227
+ return privKeyBytes , sdkerrors .ErrWrongPassword
207
228
} else if err != nil {
208
- return privKey , err
229
+ return privKeyBytes , err
209
230
}
231
+ return privKeyBytes , nil
232
+ }
210
233
211
- return legacy .PrivKeyFromBytes (privKeyBytes )
234
+ func legacyDecryptPrivKey (saltBytes []byte , encBytes []byte , passphrase string ) (decryptedBytes []byte , err error ) {
235
+ key , err := bcrypt .GenerateFromPassword (saltBytes , []byte (passphrase ), BcryptSecurityParameter )
236
+ if err != nil {
237
+ return decryptedBytes , errorsmod .Wrap (err , "error generating bcrypt key from passphrase" )
238
+ }
239
+ return decryptSymmetric (encBytes , key )
212
240
}
213
241
214
242
//-----------------------------------------------------------------
0 commit comments