|
|
- package keys
-
- import (
- "encoding/hex"
- "fmt"
-
- cmn "github.com/tendermint/tmlibs/common"
-
- "github.com/tendermint/go-crypto"
- "github.com/tendermint/go-crypto/keys/bcrypt"
- )
-
- const (
- blockTypePrivKey = "TENDERMINT PRIVATE KEY"
- blockTypeKeyInfo = "TENDERMINT KEY INFO"
- blockTypePubKey = "TENDERMINT PUBLIC KEY"
- )
-
- func armorInfoBytes(bz []byte) string {
- return armorBytes(bz, blockTypeKeyInfo)
- }
-
- func armorPubKeyBytes(bz []byte) string {
- return armorBytes(bz, blockTypePubKey)
- }
-
- func armorBytes(bz []byte, blockType string) string {
- header := map[string]string{
- "type": "Info",
- "version": "0.0.0",
- }
- return crypto.EncodeArmor(blockType, header, bz)
- }
-
- func unarmorInfoBytes(armorStr string) (bz []byte, err error) {
- return unarmorBytes(armorStr, blockTypeKeyInfo)
- }
-
- func unarmorPubKeyBytes(armorStr string) (bz []byte, err error) {
- return unarmorBytes(armorStr, blockTypePubKey)
- }
-
- func unarmorBytes(armorStr, blockType string) (bz []byte, err error) {
- bType, header, bz, err := crypto.DecodeArmor(armorStr)
- if err != nil {
- return
- }
- if bType != blockType {
- err = fmt.Errorf("Unrecognized armor type %q, expected: %q", bType, blockType)
- return
- }
- if header["version"] != "0.0.0" {
- err = fmt.Errorf("Unrecognized version: %v", header["version"])
- return
- }
- return
- }
-
- func encryptArmorPrivKey(privKey crypto.PrivKey, passphrase string) string {
- saltBytes, encBytes := encryptPrivKey(privKey, passphrase)
- header := map[string]string{
- "kdf": "bcrypt",
- "salt": fmt.Sprintf("%X", saltBytes),
- }
- armorStr := crypto.EncodeArmor(blockTypePrivKey, header, encBytes)
- return armorStr
- }
-
- func unarmorDecryptPrivKey(armorStr string, passphrase string) (crypto.PrivKey, error) {
- var privKey crypto.PrivKey
- blockType, header, encBytes, err := crypto.DecodeArmor(armorStr)
- if err != nil {
- return privKey, err
- }
- if blockType != blockTypePrivKey {
- return privKey, fmt.Errorf("Unrecognized armor type: %v", blockType)
- }
- if header["kdf"] != "bcrypt" {
- return privKey, fmt.Errorf("Unrecognized KDF type: %v", header["KDF"])
- }
- if header["salt"] == "" {
- return privKey, fmt.Errorf("Missing salt bytes")
- }
- saltBytes, err := hex.DecodeString(header["salt"])
- if err != nil {
- return privKey, fmt.Errorf("Error decoding salt: %v", err.Error())
- }
- privKey, err = decryptPrivKey(saltBytes, encBytes, passphrase)
- return privKey, err
- }
-
- func encryptPrivKey(privKey crypto.PrivKey, passphrase string) (saltBytes []byte, encBytes []byte) {
- saltBytes = crypto.CRandBytes(16)
- key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 12) // TODO parameterize. 12 is good today (2016)
- if err != nil {
- cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error())
- }
- key = crypto.Sha256(key) // Get 32 bytes
- privKeyBytes := privKey.Bytes()
- return saltBytes, crypto.EncryptSymmetric(privKeyBytes, key)
- }
-
- func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privKey crypto.PrivKey, err error) {
- key, err := bcrypt.GenerateFromPassword(saltBytes, []byte(passphrase), 12) // TODO parameterize. 12 is good today (2016)
- if err != nil {
- cmn.Exit("Error generating bcrypt key from passphrase: " + err.Error())
- }
- key = crypto.Sha256(key) // Get 32 bytes
- privKeyBytes, err := crypto.DecryptSymmetric(encBytes, key)
- if err != nil {
- return privKey, err
- }
- privKey, err = crypto.PrivKeyFromBytes(privKeyBytes)
- return privKey, err
- }
|