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 }