@ -1,12 +1,19 @@
package crypto
import (
"crypto/aes"
"crypto/cipher"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"errors"
"code.google.com/p/go-uuid/uuid"
"code.google.com/p/go.crypto/pbkdf2"
"code.google.com/p/go.crypto/ripemd160"
"encoding/hex"
"encoding/json"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/ethutil"
@ -113,3 +120,100 @@ func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) {
key := ecies . ImportECDSA ( prv )
return key . Decrypt ( rand . Reader , ct , nil , nil )
}
// creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
func ImportPreSaleKey ( keyStore KeyStore2 , keyJSON [ ] byte , password string ) ( * Key , error ) {
key , err := decryptPreSaleKey ( keyJSON , password )
if err != nil {
return nil , err
}
id := uuid . NewRandom ( )
key . Id = & id
err = keyStore . StoreKey ( key , password )
return key , err
}
func decryptPreSaleKey ( fileContent [ ] byte , password string ) ( key * Key , err error ) {
preSaleKeyStruct := struct {
EncSeed string
EthAddr string
Email string
BtcAddr string
} { }
err = json . Unmarshal ( fileContent , & preSaleKeyStruct )
if err != nil {
return nil , err
}
encSeedBytes , err := hex . DecodeString ( preSaleKeyStruct . EncSeed )
iv := encSeedBytes [ : 16 ]
cipherText := encSeedBytes [ 16 : ]
/ *
See https : //github.com/ethereum/pyethsaletool
pyethsaletool generates the encryption key from password by
2000 rounds of PBKDF2 with HMAC - SHA - 256 using password as salt ( : ( ) .
16 byte key length within PBKDF2 and resulting key is used as AES key
* /
passBytes := [ ] byte ( password )
derivedKey := pbkdf2 . Key ( passBytes , passBytes , 2000 , 16 , sha256 . New )
plainText , err := aes_cbc_decrypt ( derivedKey , cipherText , iv )
ethPriv := Sha3 ( plainText )
ecKey := ToECDSA ( ethPriv )
key = & Key {
Id : nil ,
PrivateKey : ecKey ,
}
derivedAddr := ethutil . Bytes2Hex ( key . Address ( ) )
expectedAddr := preSaleKeyStruct . EthAddr
if derivedAddr != expectedAddr {
err = errors . New ( "decrypted addr not equal to expected addr" )
}
return key , err
}
func aes_cbc_decrypt ( key [ ] byte , cipherText [ ] byte , iv [ ] byte ) ( plainText [ ] byte , err error ) {
aesBlock , err := aes . NewCipher ( key )
if err != nil {
return plainText , err
}
decrypter := cipher . NewCBCDecrypter ( aesBlock , iv )
paddedPlainText := make ( [ ] byte , len ( cipherText ) )
decrypter . CryptBlocks ( paddedPlainText , cipherText )
plainText = PKCS7Unpad ( paddedPlainText )
if plainText == nil {
err = errors . New ( "Decryption failed: PKCS7Unpad failed after decryption" )
}
return plainText , err
}
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
func PKCS7Pad ( in [ ] byte ) [ ] byte {
padding := 16 - ( len ( in ) % 16 )
if padding == 0 {
padding = 16
}
for i := 0 ; i < padding ; i ++ {
in = append ( in , byte ( padding ) )
}
return in
}
func PKCS7Unpad ( in [ ] byte ) [ ] byte {
if len ( in ) == 0 {
return nil
}
padding := in [ len ( in ) - 1 ]
if int ( padding ) > len ( in ) || padding > aes . BlockSize {
return nil
} else if padding == 0 {
return nil
}
for i := len ( in ) - 1 ; i > len ( in ) - int ( padding ) - 1 ; i -- {
if in [ i ] != padding {
return nil
}
}
return in [ : len ( in ) - int ( padding ) ]
}