github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/crypto/crypto.go (about)

     1  package crypto
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"crypto/ecdsa"
     7  	"crypto/elliptic"
     8  	"crypto/rand"
     9  	"crypto/sha256"
    10  	"fmt"
    11  	"io"
    12  	"os"
    13  
    14  	"encoding/hex"
    15  	"encoding/json"
    16  	"errors"
    17  
    18  	"code.google.com/p/go-uuid/uuid"
    19  	"code.google.com/p/go.crypto/pbkdf2"
    20  	"code.google.com/p/go.crypto/ripemd160"
    21  	"github.com/jonasnick/go-ethereum/crypto/ecies"
    22  	"github.com/jonasnick/go-ethereum/crypto/secp256k1"
    23  	"github.com/jonasnick/go-ethereum/crypto/sha3"
    24  	"github.com/jonasnick/go-ethereum/ethutil"
    25  )
    26  
    27  func init() {
    28  	// specify the params for the s256 curve
    29  	ecies.AddParamsForCurve(S256(), ecies.ECIES_AES128_SHA256)
    30  }
    31  
    32  func Sha3(data ...[]byte) []byte {
    33  	d := sha3.NewKeccak256()
    34  	for _, b := range data {
    35  		d.Write(b)
    36  	}
    37  	return d.Sum(nil)
    38  }
    39  
    40  // Creates an ethereum address given the bytes and the nonce
    41  func CreateAddress(b []byte, nonce uint64) []byte {
    42  	return Sha3(ethutil.NewValue([]interface{}{b, nonce}).Encode())[12:]
    43  }
    44  
    45  func Sha256(data []byte) []byte {
    46  	hash := sha256.Sum256(data)
    47  
    48  	return hash[:]
    49  }
    50  
    51  func Ripemd160(data []byte) []byte {
    52  	ripemd := ripemd160.New()
    53  	ripemd.Write(data)
    54  
    55  	return ripemd.Sum(nil)
    56  }
    57  
    58  func Ecrecover(data []byte) []byte {
    59  	var in = struct {
    60  		hash []byte
    61  		sig  []byte
    62  	}{data[:32], data[32:]}
    63  
    64  	r, _ := secp256k1.RecoverPubkey(in.hash, in.sig)
    65  
    66  	return r
    67  }
    68  
    69  // New methods using proper ecdsa keys from the stdlib
    70  func ToECDSA(prv []byte) *ecdsa.PrivateKey {
    71  	if len(prv) == 0 {
    72  		return nil
    73  	}
    74  
    75  	priv := new(ecdsa.PrivateKey)
    76  	priv.PublicKey.Curve = S256()
    77  	priv.D = ethutil.BigD(prv)
    78  	priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(prv)
    79  	return priv
    80  }
    81  
    82  func FromECDSA(prv *ecdsa.PrivateKey) []byte {
    83  	if prv == nil {
    84  		return nil
    85  	}
    86  	return prv.D.Bytes()
    87  }
    88  
    89  func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
    90  	if len(pub) == 0 {
    91  		return nil
    92  	}
    93  	x, y := elliptic.Unmarshal(S256(), pub)
    94  	return &ecdsa.PublicKey{S256(), x, y}
    95  }
    96  
    97  func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
    98  	if pub == nil || pub.X == nil || pub.Y == nil {
    99  		return nil
   100  	}
   101  	return elliptic.Marshal(S256(), pub.X, pub.Y)
   102  }
   103  
   104  // HexToECDSA parses a secp256k1 private key.
   105  func HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) {
   106  	b, err := hex.DecodeString(hexkey)
   107  	if err != nil {
   108  		return nil, errors.New("invalid hex string")
   109  	}
   110  	if len(b) != 32 {
   111  		return nil, errors.New("invalid length, need 256 bits")
   112  	}
   113  	return ToECDSA(b), nil
   114  }
   115  
   116  // LoadECDSA loads a secp256k1 private key from the given file.
   117  func LoadECDSA(file string) (*ecdsa.PrivateKey, error) {
   118  	buf := make([]byte, 32)
   119  	fd, err := os.Open(file)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	defer fd.Close()
   124  	if _, err := io.ReadFull(fd, buf); err != nil {
   125  		return nil, err
   126  	}
   127  	return ToECDSA(buf), nil
   128  }
   129  
   130  func GenerateKey() (*ecdsa.PrivateKey, error) {
   131  	return ecdsa.GenerateKey(S256(), rand.Reader)
   132  }
   133  
   134  func SigToPub(hash, sig []byte) *ecdsa.PublicKey {
   135  	s := Ecrecover(append(hash, sig...))
   136  	x, y := elliptic.Unmarshal(S256(), s)
   137  
   138  	return &ecdsa.PublicKey{S256(), x, y}
   139  }
   140  
   141  func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
   142  	if len(hash) != 32 {
   143  		return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
   144  	}
   145  
   146  	sig, err = secp256k1.Sign(hash, ethutil.LeftPadBytes(prv.D.Bytes(), prv.Params().BitSize/8))
   147  	return
   148  }
   149  
   150  func Encrypt(pub *ecdsa.PublicKey, message []byte) ([]byte, error) {
   151  	return ecies.Encrypt(rand.Reader, ecies.ImportECDSAPublic(pub), message, nil, nil)
   152  }
   153  
   154  func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) {
   155  	key := ecies.ImportECDSA(prv)
   156  	return key.Decrypt(rand.Reader, ct, nil, nil)
   157  }
   158  
   159  // creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
   160  func ImportPreSaleKey(keyStore KeyStore2, keyJSON []byte, password string) (*Key, error) {
   161  	key, err := decryptPreSaleKey(keyJSON, password)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	key.Id = uuid.NewRandom()
   166  	err = keyStore.StoreKey(key, password)
   167  	return key, err
   168  }
   169  
   170  func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) {
   171  	preSaleKeyStruct := struct {
   172  		EncSeed string
   173  		EthAddr string
   174  		Email   string
   175  		BtcAddr string
   176  	}{}
   177  	err = json.Unmarshal(fileContent, &preSaleKeyStruct)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
   182  	iv := encSeedBytes[:16]
   183  	cipherText := encSeedBytes[16:]
   184  	/*
   185  		See https://github.com/jonasnick/pyethsaletool
   186  
   187  		pyethsaletool generates the encryption key from password by
   188  		2000 rounds of PBKDF2 with HMAC-SHA-256 using password as salt (:().
   189  		16 byte key length within PBKDF2 and resulting key is used as AES key
   190  	*/
   191  	passBytes := []byte(password)
   192  	derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New)
   193  	plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
   194  	ethPriv := Sha3(plainText)
   195  	ecKey := ToECDSA(ethPriv)
   196  	key = &Key{
   197  		Id:         nil,
   198  		Address:    PubkeyToAddress(ecKey.PublicKey),
   199  		PrivateKey: ecKey,
   200  	}
   201  	derivedAddr := ethutil.Bytes2Hex(key.Address)
   202  	expectedAddr := preSaleKeyStruct.EthAddr
   203  	if derivedAddr != expectedAddr {
   204  		err = errors.New("decrypted addr not equal to expected addr")
   205  	}
   206  	return key, err
   207  }
   208  
   209  func aesCBCDecrypt(key []byte, cipherText []byte, iv []byte) (plainText []byte, err error) {
   210  	aesBlock, err := aes.NewCipher(key)
   211  	if err != nil {
   212  		return plainText, err
   213  	}
   214  	decrypter := cipher.NewCBCDecrypter(aesBlock, iv)
   215  	paddedPlainText := make([]byte, len(cipherText))
   216  	decrypter.CryptBlocks(paddedPlainText, cipherText)
   217  	plainText = PKCS7Unpad(paddedPlainText)
   218  	if plainText == nil {
   219  		err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
   220  	}
   221  	return plainText, err
   222  }
   223  
   224  // From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
   225  func PKCS7Pad(in []byte) []byte {
   226  	padding := 16 - (len(in) % 16)
   227  	if padding == 0 {
   228  		padding = 16
   229  	}
   230  	for i := 0; i < padding; i++ {
   231  		in = append(in, byte(padding))
   232  	}
   233  	return in
   234  }
   235  
   236  func PKCS7Unpad(in []byte) []byte {
   237  	if len(in) == 0 {
   238  		return nil
   239  	}
   240  
   241  	padding := in[len(in)-1]
   242  	if int(padding) > len(in) || padding > aes.BlockSize {
   243  		return nil
   244  	} else if padding == 0 {
   245  		return nil
   246  	}
   247  
   248  	for i := len(in) - 1; i > len(in)-int(padding)-1; i-- {
   249  		if in[i] != padding {
   250  			return nil
   251  		}
   252  	}
   253  	return in[:len(in)-int(padding)]
   254  }
   255  
   256  func PubkeyToAddress(p ecdsa.PublicKey) []byte {
   257  	pubBytes := FromECDSAPub(&p)
   258  	return Sha3(pubBytes[1:])[12:]
   259  }