This repository has been archived by the owner on Sep 4, 2023. It is now read-only.
/
armor.go
138 lines (109 loc) · 4.44 KB
/
armor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package key
import (
"encoding/hex"
"fmt"
"github.com/Moonyongjung/xpla.go/types"
"github.com/Moonyongjung/xpla.go/types/errors"
"github.com/Moonyongjung/xpla.go/util"
"github.com/cosmos/cosmos-sdk/codec/legacy"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/tendermint/crypto/bcrypt"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/armor"
"github.com/tendermint/tendermint/crypto/xsalsa20symmetric"
)
const (
blockTypePrivKey = "TENDERMINT PRIVATE KEY"
blockTypeKeyInfo = "TENDERMINT KEY INFO"
blockTypePubKey = "TENDERMINT PUBLIC KEY"
headerVersion = "version"
headerType = "type"
)
var BcryptSecurityParameter = 12
var DefaultEncryptPassphrase = "xplaDefaultPassphrase"
// Encrypt secp-256k1 private key to make armored key.
func EncryptArmorPrivKey(privKey cryptotypes.PrivKey, passphrase string) string {
return encryptPrivKey(privKey, passphrase)
}
// Encrypt secp-256k1 private key to make armored key without passphrase for keyring. (for test)
func EncryptArmorPrivKeyWithoutPassphrase(privKey cryptotypes.PrivKey) string {
return encryptPrivKey(privKey, DefaultEncryptPassphrase)
}
// Encrypt private key.
func encryptPrivKey(privKey cryptotypes.PrivKey, passphrase string) string {
saltBytes := crypto.CRandBytes(16)
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter)
if err != nil {
panic(util.LogErr(errors.ErrInvalidRequest, "error generating bcrypt key from passphrase", err))
}
key = crypto.Sha256(key) // get 32 bytes
encodingConfig := util.MakeEncodingConfig()
privKeyBytes := encodingConfig.Amino.MustMarshal(privKey)
encBytes := xsalsa20symmetric.EncryptSymmetric(privKeyBytes, key)
header := map[string]string{
"kdf": "bcrypt",
"salt": fmt.Sprintf("%X", saltBytes),
}
header[headerType] = types.DefaultXplaKeyAlgo
return armor.EncodeArmor(blockTypePrivKey, header, encBytes)
}
// Decrypt armored private key.
func UnarmorDecryptPrivKey(armorStr string, passphrase string) (privKey cryptotypes.PrivKey, algo string, err error) {
saltBytes, encBytes, header, err := decodingArmoredPrivKey(armorStr)
if err != nil {
return privKey, "", err
}
privKey, err = decryptPrivKey(saltBytes, encBytes, passphrase)
if header[headerType] == "" {
header[headerType] = types.DefaultXplaKeyAlgo
}
return privKey, header[headerType], err
}
// Decrypt armored private key without passpharse for keyring. (for test)
func UnarmorDecryptPrivKeyWithoutPassphrase(armorStr string) (privKey cryptotypes.PrivKey, algo string, err error) {
saltBytes, encBytes, header, err := decodingArmoredPrivKey(armorStr)
if err != nil {
return privKey, "", err
}
privKey, err = decryptPrivKey(saltBytes, encBytes, DefaultEncryptPassphrase)
if header[headerType] == "" {
header[headerType] = types.DefaultXplaKeyAlgo
}
return privKey, header[headerType], err
}
// Decode armored private key.
func decodingArmoredPrivKey(armorStr string) ([]byte, []byte, map[string]string, error) {
blockType, header, encBytes, err := armor.DecodeArmor(armorStr)
if err != nil {
return nil, nil, nil, err
}
if blockType != blockTypePrivKey {
return nil, nil, nil, util.LogErr(errors.ErrInvalidRequest, "unrecognized armor type: ", blockType)
}
if header["kdf"] != "bcrypt" {
return nil, nil, nil, util.LogErr(errors.ErrInvalidRequest, "unrecognized KDF type: ", header["kdf"])
}
if header["salt"] == "" {
return nil, nil, nil, util.LogErr(errors.ErrInvalidRequest, "missing salt bytes")
}
saltBytes, err := hex.DecodeString(header["salt"])
if err != nil {
return nil, nil, nil, util.LogErr(errors.ErrInvalidRequest, "error decoding salt: %v", err.Error())
}
return saltBytes, encBytes, header, nil
}
// Decrypt private key.
func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey cryptotypes.PrivKey, err error) {
key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), BcryptSecurityParameter)
if err != nil {
return privKey, util.LogErr(errors.ErrInvalidRequest, err, "error generating bcrypt key from passphrase")
}
key = crypto.Sha256(key) // Get 32 bytes
privKeyBytes, err := xsalsa20symmetric.DecryptSymmetric(encBytes, key)
if err != nil && err.Error() == "Ciphertext decryption failed" {
return privKey, util.LogErr(errors.ErrInvalidRequest, "invalid account password")
} else if err != nil {
return privKey, util.LogErr(errors.ErrParse, err)
}
return legacy.PrivKeyFromBytes(privKeyBytes)
}