@ -69,9 +69,10 @@ import (
"code.google.com/p/go.crypto/scrypt"
"code.google.com/p/go.crypto/scrypt"
"crypto/aes"
"crypto/aes"
"crypto/cipher"
"crypto/cipher"
"encoding/hex "
crand "crypto/rand "
"encoding/json"
"encoding/json"
"errors"
"errors"
"io"
"os"
"os"
"path"
"path"
)
)
@ -94,25 +95,24 @@ func NewKeyStorePassphrase(path string) KeyStore2 {
return ks
return ks
}
}
func ( ks keyStorePassphrase ) GenerateNewKey ( auth string ) ( key * Key , err error ) {
func ( ks keyStorePassphrase ) GenerateNewKey ( rand io . Reader , auth string ) ( key * Key , err error ) {
return GenerateNewKeyDefault ( ks , auth )
return GenerateNewKeyDefault ( ks , rand , auth )
}
}
func ( ks keyStorePassphrase ) GetKey ( keyId * uuid . UUID , auth string ) ( key * Key , err error ) {
func ( ks keyStorePassphrase ) GetKey ( keyId * uuid . UUID , auth string ) ( key * Key , err error ) {
keyBytes , flags , err := DecryptKey ( ks , keyId , auth )
keyBytes , err := DecryptKey ( ks , keyId , auth )
if err != nil {
if err != nil {
return nil , err
return nil , err
}
}
key = new ( Key )
key = new ( Key )
key . Id = keyId
key . Id = keyId
copy ( key . Flags [ : ] , flags [ 0 : 4 ] )
key . PrivateKey = ToECDSA ( keyBytes )
key . PrivateKey = ToECDSA ( keyBytes )
return key , err
return key , err
}
}
func ( ks keyStorePassphrase ) StoreKey ( key * Key , auth string ) ( err error ) {
func ( ks keyStorePassphrase ) StoreKey ( key * Key , auth string ) ( err error ) {
authArray := [ ] byte ( auth )
authArray := [ ] byte ( auth )
salt := G etEntropyCSPRNG( 32 )
salt := g etEntropyCSPRNG( 32 )
derivedKey , err := scrypt . Key ( authArray , salt , scryptN , scryptr , scryptp , scryptdkLen )
derivedKey , err := scrypt . Key ( authArray , salt , scryptN , scryptr , scryptp , scryptdkLen )
if err != nil {
if err != nil {
return err
return err
@ -127,19 +127,18 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
return err
return err
}
}
iv := G etEntropyCSPRNG( aes . BlockSize ) // 16
iv := g etEntropyCSPRNG( aes . BlockSize ) // 16
AES256CBCEncrypter := cipher . NewCBCEncrypter ( AES256Block , iv )
AES256CBCEncrypter := cipher . NewCBCEncrypter ( AES256Block , iv )
cipherText := make ( [ ] byte , len ( toEncrypt ) )
cipherText := make ( [ ] byte , len ( toEncrypt ) )
AES256CBCEncrypter . CryptBlocks ( cipherText , toEncrypt )
AES256CBCEncrypter . CryptBlocks ( cipherText , toEncrypt )
cipherStruct := C ipherJSON{
cipherStruct := c ipherJSON{
hex . EncodeToString ( salt ) ,
salt ,
hex . EncodeToString ( iv ) ,
iv ,
hex . EncodeToString ( cipherText ) ,
cipherText ,
}
}
keyStruct := EncryptedKeyJSON {
keyStruct := encryptedKeyJSON {
key . Id . String ( ) ,
* key . Id ,
hex . EncodeToString ( key . Flags [ : ] ) ,
cipherStruct ,
cipherStruct ,
}
}
keyJSON , err := json . Marshal ( keyStruct )
keyJSON , err := json . Marshal ( keyStruct )
@ -152,7 +151,7 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
func ( ks keyStorePassphrase ) DeleteKey ( keyId * uuid . UUID , auth string ) ( err error ) {
func ( ks keyStorePassphrase ) DeleteKey ( keyId * uuid . UUID , auth string ) ( err error ) {
// only delete if correct passphrase is given
// only delete if correct passphrase is given
_ , _ , err = DecryptKey ( ks , keyId , auth )
_ , err = DecryptKey ( ks , keyId , auth )
if err != nil {
if err != nil {
return err
return err
}
}
@ -161,44 +160,30 @@ func (ks keyStorePassphrase) DeleteKey(keyId *uuid.UUID, auth string) (err error
return os . RemoveAll ( keyDirPath )
return os . RemoveAll ( keyDirPath )
}
}
func DecryptKey ( ks keyStorePassphrase , keyId * uuid . UUID , auth string ) ( keyBytes [ ] byte , flags [ ] byte , err error ) {
func DecryptKey ( ks keyStorePassphrase , keyId * uuid . UUID , auth string ) ( keyBytes [ ] byte , err error ) {
fileContent , err := GetKeyFile ( ks . keysDirPath , keyId )
fileContent , err := GetKeyFile ( ks . keysDirPath , keyId )
if err != nil {
if err != nil {
return nil , nil , err
return nil , err
}
}
keyProtected := new ( E ncryptedKeyJSON)
keyProtected := new ( e ncryptedKeyJSON)
err = json . Unmarshal ( fileContent , keyProtected )
err = json . Unmarshal ( fileContent , keyProtected )
flags , err = hex . DecodeString ( keyProtected . Flags )
salt := keyProtected . Crypto . Salt
if err != nil {
return nil , nil , err
}
salt , err := hex . DecodeString ( keyProtected . Crypto . Salt )
iv := keyProtected . Crypto . IV
if err != nil {
return nil , nil , err
}
iv , err := hex . DecodeString ( keyProtected . Crypto . IV )
cipherText := keyProtected . Crypto . CipherText
if err != nil {
return nil , nil , err
}
cipherText , err := hex . DecodeString ( keyProtected . Crypto . CipherText )
if err != nil {
return nil , nil , err
}
authArray := [ ] byte ( auth )
authArray := [ ] byte ( auth )
derivedKey , err := scrypt . Key ( authArray , salt , scryptN , scryptr , scryptp , scryptdkLen )
derivedKey , err := scrypt . Key ( authArray , salt , scryptN , scryptr , scryptp , scryptdkLen )
if err != nil {
if err != nil {
return nil , nil , err
return nil , err
}
}
AES256Block , err := aes . NewCipher ( derivedKey )
AES256Block , err := aes . NewCipher ( derivedKey )
if err != nil {
if err != nil {
return nil , nil , err
return nil , err
}
}
AES256CBCDecrypter := cipher . NewCBCDecrypter ( AES256Block , iv )
AES256CBCDecrypter := cipher . NewCBCDecrypter ( AES256Block , iv )
@ -208,16 +193,26 @@ func DecryptKey(ks keyStorePassphrase, keyId *uuid.UUID, auth string) (keyBytes
plainText := PKCS7Unpad ( paddedPlainText )
plainText := PKCS7Unpad ( paddedPlainText )
if plainText == nil {
if plainText == nil {
err = errors . New ( "Decryption failed: PKCS7Unpad failed after decryption" )
err = errors . New ( "Decryption failed: PKCS7Unpad failed after decryption" )
return nil , nil , err
return nil , err
}
}
keyBytes = plainText [ : len ( plainText ) - 32 ]
keyBytes = plainText [ : len ( plainText ) - 32 ]
keyBytesHash := plainText [ len ( plainText ) - 32 : ]
keyBytesHash := plainText [ len ( plainText ) - 32 : ]
if ! bytes . Equal ( Sha3 ( keyBytes ) , keyBytesHash ) {
if ! bytes . Equal ( Sha3 ( keyBytes ) , keyBytesHash ) {
err = errors . New ( "Decryption failed: checksum mismatch" )
err = errors . New ( "Decryption failed: checksum mismatch" )
return nil , nil , err
return nil , err
}
return keyBytes , err
}
// plain crypto/rand. this is /dev/urandom on Unix-like systems.
func getEntropyCSPRNG ( n int ) [ ] byte {
mainBuff := make ( [ ] byte , n )
_ , err := io . ReadFull ( crand . Reader , mainBuff )
if err != nil {
panic ( "key generation: reading from crypto/rand failed: " + err . Error ( ) )
}
}
return keyBytes , flags , err
return mainBuff
}
}
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes