2016-07-06 21:51:25 +02:00
|
|
|
// Package cryptocore wraps OpenSSL and Go GCM crypto and provides
|
|
|
|
// a nonce generator.
|
2016-02-06 19:20:54 +01:00
|
|
|
package cryptocore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/aes"
|
2016-02-06 20:23:36 +01:00
|
|
|
"crypto/cipher"
|
2016-10-04 00:12:29 +02:00
|
|
|
"crypto/sha512"
|
2016-02-06 19:20:54 +01:00
|
|
|
"fmt"
|
2016-12-10 11:50:16 +01:00
|
|
|
"log"
|
2016-05-04 19:09:14 +02:00
|
|
|
|
2017-03-05 13:58:24 +01:00
|
|
|
"github.com/rfjakob/eme"
|
|
|
|
|
2016-09-26 23:25:13 +02:00
|
|
|
"github.com/rfjakob/gocryptfs/internal/siv_aead"
|
2016-05-04 19:09:14 +02:00
|
|
|
"github.com/rfjakob/gocryptfs/internal/stupidgcm"
|
2016-02-06 19:20:54 +01:00
|
|
|
)
|
|
|
|
|
2017-04-29 14:50:58 +02:00
|
|
|
// AEADTypeEnum indicates the type of AEAD backend in use.
|
2017-03-05 17:08:16 +01:00
|
|
|
type AEADTypeEnum int
|
2016-09-20 21:58:04 +02:00
|
|
|
|
2016-02-06 19:20:54 +01:00
|
|
|
const (
|
2016-10-02 06:14:18 +02:00
|
|
|
// KeyLen is the cipher key length in bytes. 32 for AES-256.
|
|
|
|
KeyLen = 32
|
|
|
|
// AuthTagLen is the length of a GCM auth tag in bytes.
|
2016-02-06 20:23:36 +01:00
|
|
|
AuthTagLen = 16
|
2016-09-20 21:58:04 +02:00
|
|
|
|
2016-10-02 06:14:18 +02:00
|
|
|
_ = iota // Skip zero
|
|
|
|
// BackendOpenSSL specifies the OpenSSL backend.
|
2017-03-05 17:08:16 +01:00
|
|
|
BackendOpenSSL AEADTypeEnum = iota
|
2016-10-02 06:14:18 +02:00
|
|
|
// BackendGoGCM specifies the Go based GCM backend.
|
2017-03-05 17:08:16 +01:00
|
|
|
BackendGoGCM AEADTypeEnum = iota
|
2016-10-02 06:14:18 +02:00
|
|
|
// BackendAESSIV specifies an AESSIV backend.
|
2017-03-05 17:08:16 +01:00
|
|
|
BackendAESSIV AEADTypeEnum = iota
|
2016-02-06 19:20:54 +01:00
|
|
|
)
|
|
|
|
|
2016-10-02 06:14:18 +02:00
|
|
|
// CryptoCore is the low level crypto implementation.
|
2016-02-06 19:20:54 +01:00
|
|
|
type CryptoCore struct {
|
2017-03-05 13:58:24 +01:00
|
|
|
// EME is used for filename encryption.
|
|
|
|
EMECipher *eme.EMECipher
|
2016-09-26 23:25:13 +02:00
|
|
|
// GCM or AES-SIV. This is used for content encryption.
|
2016-09-20 21:58:04 +02:00
|
|
|
AEADCipher cipher.AEAD
|
2016-09-20 22:59:10 +02:00
|
|
|
// Which backend is behind AEADCipher?
|
2017-03-05 17:08:16 +01:00
|
|
|
AEADBackend AEADTypeEnum
|
2016-09-20 21:58:04 +02:00
|
|
|
// GCM needs unique IVs (nonces)
|
|
|
|
IVGenerator *nonceGenerator
|
2016-02-06 20:23:36 +01:00
|
|
|
IVLen int
|
2016-02-06 19:20:54 +01:00
|
|
|
}
|
|
|
|
|
2016-10-02 06:14:18 +02:00
|
|
|
// New returns a new CryptoCore object or panics.
|
2016-07-31 13:36:38 +02:00
|
|
|
//
|
|
|
|
// Even though the "GCMIV128" feature flag is now mandatory, we must still
|
2017-03-05 18:03:03 +01:00
|
|
|
// support 96-bit IVs here because they were used for encrypting the master
|
|
|
|
// key in gocryptfs.conf up to gocryptfs v1.2. v1.3 switched to 128 bits.
|
2017-04-08 02:09:28 +02:00
|
|
|
func New(key []byte, aeadType AEADTypeEnum, IVBitLen int, useHKDF bool, forceDecode bool) *CryptoCore {
|
2016-02-06 19:20:54 +01:00
|
|
|
if len(key) != KeyLen {
|
2016-12-10 11:50:16 +01:00
|
|
|
log.Panic(fmt.Sprintf("Unsupported key length %d", len(key)))
|
2016-02-06 19:20:54 +01:00
|
|
|
}
|
|
|
|
// We want the IV size in bytes
|
2016-09-20 21:58:04 +02:00
|
|
|
IVLen := IVBitLen / 8
|
2016-02-06 19:20:54 +01:00
|
|
|
|
2017-03-05 21:59:55 +01:00
|
|
|
// Initialize EME for filename encryption.
|
|
|
|
var emeCipher *eme.EMECipher
|
|
|
|
{
|
|
|
|
emeKey := key
|
|
|
|
if useHKDF {
|
|
|
|
info := "EME filename encryption"
|
|
|
|
emeKey = hkdfDerive(key, info, KeyLen)
|
|
|
|
}
|
|
|
|
emeBlockCipher, err := aes.NewCipher(emeKey)
|
|
|
|
if err != nil {
|
|
|
|
log.Panic(err)
|
|
|
|
}
|
|
|
|
emeCipher = eme.New(emeBlockCipher)
|
2016-02-06 19:20:54 +01:00
|
|
|
}
|
|
|
|
|
2017-03-05 21:59:55 +01:00
|
|
|
// Initilize an AEAD cipher for file content encryption.
|
2016-10-04 00:15:27 +02:00
|
|
|
var aeadCipher cipher.AEAD
|
2017-03-05 21:59:55 +01:00
|
|
|
if aeadType == BackendOpenSSL || aeadType == BackendGoGCM {
|
|
|
|
gcmKey := key
|
|
|
|
if useHKDF {
|
|
|
|
info := "AES-GCM file content encryption"
|
|
|
|
gcmKey = hkdfDerive(key, info, KeyLen)
|
2016-09-20 21:58:04 +02:00
|
|
|
}
|
2017-03-05 21:59:55 +01:00
|
|
|
switch aeadType {
|
|
|
|
case BackendOpenSSL:
|
|
|
|
if IVLen != 16 {
|
|
|
|
log.Panic("stupidgcm only supports 128-bit IVs")
|
|
|
|
}
|
2017-04-08 02:09:28 +02:00
|
|
|
aeadCipher = stupidgcm.New(gcmKey, forceDecode)
|
2017-03-05 21:59:55 +01:00
|
|
|
case BackendGoGCM:
|
|
|
|
goGcmBlockCipher, err := aes.NewCipher(gcmKey)
|
|
|
|
if err != nil {
|
|
|
|
log.Panic(err)
|
|
|
|
}
|
|
|
|
aeadCipher, err = cipher.NewGCMWithNonceSize(goGcmBlockCipher, IVLen)
|
|
|
|
if err != nil {
|
|
|
|
log.Panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if aeadType == BackendAESSIV {
|
2016-10-09 17:05:12 +02:00
|
|
|
if IVLen != 16 {
|
|
|
|
// SIV supports any nonce size, but we only use 16.
|
2016-12-10 11:50:16 +01:00
|
|
|
log.Panic("AES-SIV must use 16-byte nonces")
|
2016-10-09 17:05:12 +02:00
|
|
|
}
|
2017-03-05 21:59:55 +01:00
|
|
|
var key64 []byte
|
|
|
|
if useHKDF {
|
|
|
|
info := "AES-SIV file content encryption"
|
|
|
|
key64 = hkdfDerive(key, info, siv_aead.KeyLen)
|
|
|
|
} else {
|
|
|
|
// 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.
|
|
|
|
s := sha512.Sum512(key)
|
|
|
|
key64 = s[:]
|
|
|
|
}
|
|
|
|
aeadCipher = siv_aead.New(key64)
|
|
|
|
} else {
|
2016-12-10 11:50:16 +01:00
|
|
|
log.Panic("unknown backend cipher")
|
2016-09-20 21:58:04 +02:00
|
|
|
}
|
2016-02-06 19:20:54 +01:00
|
|
|
|
|
|
|
return &CryptoCore{
|
2017-03-05 13:58:24 +01:00
|
|
|
EMECipher: emeCipher,
|
2016-10-04 00:15:27 +02:00
|
|
|
AEADCipher: aeadCipher,
|
2017-03-05 17:08:16 +01:00
|
|
|
AEADBackend: aeadType,
|
2016-09-20 21:58:04 +02:00
|
|
|
IVGenerator: &nonceGenerator{nonceLen: IVLen},
|
2016-02-06 20:23:36 +01:00
|
|
|
IVLen: IVLen,
|
2016-02-06 19:20:54 +01:00
|
|
|
}
|
|
|
|
}
|