libgocryptfs/internal/cryptocore/cryptocore.go

88 lines
2.3 KiB
Go

// Package cryptocore wraps OpenSSL and Go GCM crypto and provides
// a nonce generator.
package cryptocore
import (
"crypto/aes"
"crypto/cipher"
"crypto/sha512"
"fmt"
"github.com/rfjakob/gocryptfs/internal/siv_aead"
"github.com/rfjakob/gocryptfs/internal/stupidgcm"
)
type BackendTypeEnum int
const (
KeyLen = 32 // AES-256
AuthTagLen = 16
_ = iota // Skip zero
BackendOpenSSL BackendTypeEnum = iota
BackendGoGCM BackendTypeEnum = iota
BackendAESSIV BackendTypeEnum = iota
)
type CryptoCore struct {
// AES-256 block cipher. This is used for EME filename encryption.
BlockCipher cipher.Block
// GCM or AES-SIV. This is used for content encryption.
AEADCipher cipher.AEAD
// Which backend is behind AEADCipher?
AEADBackend BackendTypeEnum
// GCM needs unique IVs (nonces)
IVGenerator *nonceGenerator
IVLen int
}
// "New" returns a new CryptoCore object or panics.
//
// Even though the "GCMIV128" feature flag is now mandatory, we must still
// support 96-bit IVs here because they are used for encrypting the master
// key in gocryptfs.conf.
func New(key []byte, backend BackendTypeEnum, IVBitLen int) *CryptoCore {
if len(key) != KeyLen {
panic(fmt.Sprintf("Unsupported key length %d", len(key)))
}
// We want the IV size in bytes
IVLen := IVBitLen / 8
// Name encryption always uses built-in Go AES through BlockCipher.
// Content encryption uses BlockCipher only if useOpenssl=false.
blockCipher, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
var aeadCipher cipher.AEAD
switch backend {
case BackendOpenSSL:
if IVLen != 16 {
panic("stupidgcm only supports 128-bit IVs")
}
aeadCipher = stupidgcm.New(key)
case BackendGoGCM:
aeadCipher, err = goGCMWrapper(blockCipher, IVLen)
case BackendAESSIV:
// AES-SIV uses 1/2 of the key for authentication, 1/2 for
// encryption, so we need a 64-bytes key for AES-256. Derive it from
// the master key by hashing it with SHA-512.
key64 := sha512.Sum512(key)
aeadCipher = siv_aead.New(key64[:])
default:
panic("unknown backend cipher")
}
if err != nil {
panic(err)
}
return &CryptoCore{
BlockCipher: blockCipher,
AEADCipher: aeadCipher,
AEADBackend: backend,
IVGenerator: &nonceGenerator{nonceLen: IVLen},
IVLen: IVLen,
}
}