Skip to content

Commit

Permalink
feat: tests added using goconvey
Browse files Browse the repository at this point in the history
  • Loading branch information
aeddi authored and moul committed Aug 20, 2018
1 parent 76a13df commit e0310ef
Show file tree
Hide file tree
Showing 17 changed files with 579 additions and 265 deletions.
36 changes: 19 additions & 17 deletions core/crypto/enclave/decrypt.go
Expand Up @@ -13,6 +13,8 @@ func Decrypt(keyID string, cipherText string, label []byte) (plainText string, e
// Check if keyID exists in keyPairs map
if !isKeyIDAlreadyExist(keyID) {
return "", errors.New("Error: keyID doesn't exist")
} else if cipherText == "" {
return "", errors.New("Error: cipherText is empty")
}

// Call the right decryption function
Expand All @@ -29,29 +31,29 @@ func Decrypt(keyID string, cipherText string, label []byte) (plainText string, e
func decryptRSA(keyID string, cipherText string, label []byte) (plainText string, err error) {
// Decrypt ciphertext using private keys
var bytes []byte
bytes, err = rsa.DecryptOAEP(
sha512.New(),
rand.Reader,
keyPairs[keyID].privKey,
[]byte(cipherText),
label,
)
privKey, rsaType := keyPairs[keyID].privKey.(*rsa.PrivateKey)
if rsaType {
bytes, err = rsa.DecryptOAEP(
sha512.New(),
rand.Reader,
privKey,
[]byte(cipherText),
label,
)

if err != nil {
log.Println("Error during cipher text decryption:", err)
return
}

if err != nil {
log.Println("Error during cipher text decryption:", err)
return
plainText = string(bytes)
} else {
err = errors.New("Error: can't cast privKey to *rsa.PrivateKey")
}

plainText = string(bytes)
return
}

// Decrypt ciphertext using ECC
func decryptECC(keyID string, cipherText string, label []byte) (plainText string, err error) {
return "", errors.New("Error: ECC-256 decryption not implemented yet")
}

// Decrypt ciphertext using specific platform API
func decryptEnclave(keyID string, cipherText string, label []byte) (plainText string, err error) {
return "", errors.New("Error: enclave decryption not implemented yet")
}
31 changes: 19 additions & 12 deletions core/crypto/enclave/encrypt.go
Expand Up @@ -13,6 +13,8 @@ func Encrypt(keyID string, plainText string, label []byte) (cipherText string, e
// Check if keyID exists in keyPairs map
if !isKeyIDAlreadyExist(keyID) {
return "", errors.New("Error: keyID doesn't exist")
} else if plainText == "" {
return "", errors.New("Error: plainText is empty")
}

// Call the right encryption function
Expand All @@ -26,20 +28,25 @@ func Encrypt(keyID string, plainText string, label []byte) (cipherText string, e
func encryptRSA(keyID string, plainText string, label []byte) (cipherText string, err error) {
// Encrypt plain text using public key
var bytes []byte
bytes, err = rsa.EncryptOAEP(
sha512.New(),
rand.Reader,
keyPairs[keyID].pubKey,
[]byte(plainText),
label,
)
if err != nil {
log.Println("Error during plain text encryption:", err)
return
pubKey, rsaType := keyPairs[keyID].pubKey.(*rsa.PublicKey)
if rsaType {
bytes, err = rsa.EncryptOAEP(
sha512.New(),
rand.Reader,
pubKey,
[]byte(plainText),
label,
)
if err != nil {
log.Println("Error during plain text encryption:", err)
return
}

cipherText = string(bytes)
} else {
err = errors.New("Error: can't cast pubKey to *rsa.PublicKey")
}

cipherText = string(bytes)

return

}
Expand Down
62 changes: 31 additions & 31 deletions core/crypto/enclave/keygen.go
Expand Up @@ -9,20 +9,20 @@ import (

// Not exported outside the package. Caller only interact using ID
type keyPair struct {
privKey *rsa.PrivateKey
pubKey *rsa.PublicKey
privKey interface{}
pubKey interface{}
keyType KeyType
keyStore KeyStore
}

// Opts is a struct that hold options for key generation, by default, all fallback are disallowed
type Opts struct {
ID string // Optional
IDFallback bool // Optional - false by default
Type KeyType
TypeFallback bool // Optional - false by default
Store KeyStore
StoreFallback bool // Optional - false by default
// KeyOpts is a struct that hold options for key generation, by default, all fallbacks are disallowed
type KeyOpts struct {
ID string // Optional
IDFallback bool // Optional - false by default - Ignored if ID's not specified
Type KeyType // Mandatory
TypeFallback bool // Optional - false by default
Store KeyStore // Mandatory
StoreFallback bool // Optional - false by default
}

// KeyType can be either RSA-2048 or ECC-256
Expand All @@ -44,35 +44,34 @@ const (
)

// NewKeyPair generate software or enclave key pair according to the parameters
func NewKeyPair(options Opts) (keyID string, err error) {
// Check if store parameter is correct
func NewKeyPair(options KeyOpts) (keyID string, err error) {
// Check if type and store parameters are correct
if options.Store != Enclave && options.Store != Software {
return "", errors.New("Error: wrong Opts.Store parameter")
return "", errors.New("Error: wrong KeyOpts.Store parameter")
} else if options.Type != RSA2048 && options.Type != ECC256 {
return "", errors.New("Error: wrong Opts.Type parameter")
return "", errors.New("Error: wrong KeyOpts.Type parameter")
}

// Try to generate enclave key pair if asked
// Try to generate enclave key pair if requested
if options.Store == Enclave {
keyID, err = newKeyPairEnclave(options)
}

// Try to generate software key pair if asked or
// Try to generate software key pair if requested or
// if enclave generation failed and fallback is allowed
if options.Store == Software || (err != nil && options.StoreFallback) {
if err != nil {
log.Println(err.Error())
log.Println("Fallback to software key pair generation")
}
keyID, err = newKeyPairSoftware(options)
}

return
}

// Generate enclave key pair using platform specific API
func newKeyPairEnclave(options Opts) (keyID string, err error) {
return "", errors.New("Error: enclave key generation not implemented yet")
}

// Generate software key pair using the function corresponding to the key type (ECC or RSA)
func newKeyPairSoftware(options Opts) (keyID string, err error) {
func newKeyPairSoftware(options KeyOpts) (keyID string, err error) {
if options.Type == RSA2048 {
keyID, err = newKeyPairSoftwareRSA(options)
if err != nil && options.TypeFallback {
Expand All @@ -93,26 +92,27 @@ func newKeyPairSoftware(options Opts) (keyID string, err error) {
}

// Generate a random RSA-2048 key pair then return the corresponding ID
func newKeyPairSoftwareRSA(options Opts) (keyID string, err error) {
func newKeyPairSoftwareRSA(options KeyOpts) (keyID string, err error) {
// Generate a random RSA-2048 key pair
var keypair keyPair
keypair.privKey, err = rsa.GenerateKey(rand.Reader, 2048)
keyPairRSA, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Println("Error during key pair generation:", err)
return
}
log.Println("Software RSA-2048 key pair generated successfully")

// Set remaining keyPair fields
keypair.pubKey = &keypair.privKey.PublicKey
keypair.keyType = RSA2048
keypair.keyStore = Software
// Set keyPair struct fields
var keyPair keyPair
keyPair.privKey = keyPairRSA
keyPair.pubKey = &keyPairRSA.PublicKey
keyPair.keyType = RSA2048
keyPair.keyStore = Software

// Append generated keyPair to the map
return storeInKeyPairsMap(options, keypair)
return storeInKeyPairsMap(options, keyPair)
}

// Generate a random ECC-256 key pair then return the corresponding ID
func newKeyPairSoftwareECC(options Opts) (keyID string, err error) {
func newKeyPairSoftwareECC(options KeyOpts) (keyID string, err error) {
return "", errors.New("Error: ECC-256 key generation not implemented yet")
}
51 changes: 31 additions & 20 deletions core/crypto/enclave/keymap.go
Expand Up @@ -21,42 +21,53 @@ func isKeyIDAlreadyExist(keyID string) bool {
return false
}

// Try to store key pair in keys map using potentially specified ID or try generate a new one
func storeInKeyPairsMap(options Opts, keypair keyPair) (keyID string, err error) {
if options.ID != "" {
// Return error if specified ID already exists and fallback isn't allowed
if isKeyIDAlreadyExist(options.ID) && !options.IDFallback {
return "", errors.New("Error: keyID " + options.ID + " not available and fallback is disallowed")
}
keyID = options.ID
}

// Try to generate a shortid <timeout> times before returning error
// Try to generate a shortid <timeout> times before returning error
func getAnAvailableID() (keyID string, err error) {
for try := 0; try < timeout; try++ {
// If ID is available, reserve it then return
if keyID != "" && !isKeyIDAlreadyExist(keyID) {
keyPairs[keyID] = keypair
log.Println("Key pair added to keys map with ID:", keyID)
return
}
keyID, err = shortid.Generate()
if err != nil {
// If ID is available or if an error has occurred, return
if !isKeyIDAlreadyExist(keyID) || err != nil {
return
}
}

return "", errors.New("Error: can't find an available ID in keyPairs map (timeout " + strconv.Itoa(timeout) + ")")
}

// Try to store key pair in keys map using potentially specified ID or try generate a new one
func storeInKeyPairsMap(options KeyOpts, keypair keyPair) (keyID string, err error) {
// Return error if specified ID already exists and fallback isn't allowed
if options.ID != "" && isKeyIDAlreadyExist(options.ID) && !options.IDFallback {
return "", errors.New("Error: keyID " + options.ID + " not available and fallback is disallowed")
} else if options.ID != "" && !isKeyIDAlreadyExist(options.ID) {
// If specified ID is available, use it
keyID = options.ID
} else {
// If no ID is specified or ID isn't available, generate an available random shortid
keyID, err = getAnAvailableID()
}

if err == nil {
keyPairs[keyID] = keypair
log.Println("Key pair added to keys map with ID:", keyID)
}

return
}

// RemoveFromKeyPairsMap removes key pair with keyID from the keys map
func RemoveFromKeyPairsMap(keyID string) error {
func RemoveFromKeyPairsMap(keyID string) (err error) {
// Check if keyID exists in keyPairs map
if !isKeyIDAlreadyExist(keyID) {
return errors.New("Error: keyID doesn't exist")
}

// If the key pair is stored in a platform specific key storage, remove it
if keyPairs[keyID].keyStore == Enclave {
err = removeFromEnclave(keyID)
}
delete(keyPairs, keyID)
log.Println("Key pair with ID", keyID, "has been removed from the keys map")

return nil
return
}
25 changes: 25 additions & 0 deletions core/crypto/enclave/os_android.go
@@ -0,0 +1,25 @@
// +build android

package enclave

import "errors"

// Generate enclave key pair using platform specific API
func newKeyPairEnclave(options KeyOpts) (keyID string, err error) {
return "", errors.New("Error: enclave key generation not implemented yet for Android")
}

// Decrypt ciphertext using specific platform API
func decryptEnclave(keyID string, cipherText string, label []byte) (plainText string, err error) {
return "", errors.New("Error: enclave decryption not implemented yet for Android")
}

// Sign text using platform specific API
func signEnclave(keyID string, text string) (signature []byte, err error) {
return []byte{}, errors.New("Error: enclave signing not implemented yet for Android")
}

// Remove key pair from platform specific key store
func removeFromEnclave(keyID string) error {
return errors.New("Error: enclave signing not implemented yet for Android")
}
71 changes: 71 additions & 0 deletions core/crypto/enclave/os_darwin.go
@@ -0,0 +1,71 @@
// +build darwin

package enclave

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation -framework Security
#import "platform_api/darwin/DarwinInterface.m"
*/
import "C"

import (
"errors"
"log"
"unsafe"
)

// Generate enclave key pair using platform specific API
func newKeyPairEnclave(options KeyOpts) (keyID string, err error) {
// Reserve keyID in keyPairs map
keyID, err = storeInKeyPairsMap(options, keyPair{})
if err != nil {
return
}

// Convert Golang string keyID to a C string then defer freeing it
cString := C.CString(keyID)
defer C.free(unsafe.Pointer(cString))

// Generate a key pair according to the options parameter (within enclave or keychain)
var keyPair keyPair
if (options.Type == ECC256 || options.TypeFallback) && C.generateKeyPairWithinEnclave(cString) == C.bool(true) {
keyPair.keyStore = Enclave
keyPair.keyType = ECC256
log.Println("Key pair generation within the Darwin Secure Enclave succeeded")
} else if C.generateKeyPairWithoutEnclave(cString, C.int(options.Type)) == C.bool(true) {
keyPair.keyStore = Enclave
keyPair.keyType = options.Type
log.Println("Key pair generation within the Darwin keychain succeeded")
} else {
RemoveFromKeyPairsMap(keyID)
return "", errors.New("Error during key generation with Darwin API")
}

keyPairs[keyID] = keyPair
return
}

// Decrypt ciphertext using specific platform API
func decryptEnclave(keyID string, cipherText string, label []byte) (plainText string, err error) {
return "", errors.New("Error: enclave decryption not implemented yet for Darwin")
}

// Sign text using platform specific API
func signEnclave(keyID string, text string) (signature []byte, err error) {
return []byte{}, errors.New("Error: enclave signing not implemented yet for Darwin")
}

// Remove key pair from keychain
func removeFromEnclave(keyID string) error {
// Convert Golang string keyID to a C string then defer freeing it
cString := C.CString(keyID)
defer C.free(unsafe.Pointer(cString))

// Delete key pair from keychain
if C.deleteKeyPairFromKeychain(cString) != C.bool(true) {
return errors.New("Error during keychain deletion")
}

return nil
}

0 comments on commit e0310ef

Please sign in to comment.