Skip to content

Commit

Permalink
Add comment to cassette header (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
seborama authored Aug 16, 2022
1 parent 5a7addf commit 6ce205e
Show file tree
Hide file tree
Showing 7 changed files with 22 additions and 17 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,11 @@ Refer to the tests for examples (search for `WithTrackRecordingMutators` and `Wi

## Cassette encryption

Cassettes can be encrypted with the Go-supported AES-CGM cipher.
Cassettes can be encrypted with the Go-supported AES-GCM cipher.

You will need to provide a secret key of either 16 or 32 bytes to a "`Crypter`" that will take care of encrypting and decrypting the cassette contents transparently.

The "nonce" is stored with the cassette, in its header. The default strategy to generate a nonce is a 12-byte random generator.
The "nonce" is stored with the cassette, in its header. The default strategy to generate a nonce is a 12-byte random generator. This is only safe if the same key is reused at most 2³² times (which for a **govcr** cassette feels somewhat infinite).

It is possible to provide a custom nonce generator, albeit currently this is somewhat limited because the current nonce is not provided. This can make it difficult to implement a counter, for example.

Expand Down
6 changes: 3 additions & 3 deletions cassette/cassette_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func Test_cassette_Encryption(t *testing.T) {

// STEP 1: create encrypted cassette.
key := []byte("12345678901234567890123456789012")
c, err := encryption.NewAESCGM(key, nil)
c, err := encryption.NewAESGCMWithRandomNonceGenerator(key)
require.NoError(t, err)

k7 := cassette.NewCassette(cassetteName, cassette.WithCassetteCrypter(c))
Expand All @@ -149,7 +149,7 @@ func Test_cassette_Encryption(t *testing.T) {
data, err := os.ReadFile(cassetteName) // nolint:gosec
require.NoError(t, err)

const encryptedCassetteHeader = "$ENC$"
const encryptedCassetteHeader = "$ENC$" // AES-GCM encryption marker

require.True(t, bytes.HasPrefix(data, []byte(encryptedCassetteHeader)))

Expand Down Expand Up @@ -184,7 +184,7 @@ func Test_cassette_CanEncryptPlainCassette(t *testing.T) {

// STEP 1b: add track to cassette, this time encrypt the cassette.
key := []byte("12345678901234567890123456789012")
c, err := encryption.NewAESCGM(key, nil)
c, err := encryption.NewAESGCMWithRandomNonceGenerator(key)
require.NoError(t, err)

k7 = cassette.LoadCassette(cassetteName, cassette.WithCassetteCrypter(c))
Expand Down
2 changes: 1 addition & 1 deletion cmd/govcr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func decryptCassette(cassetteFile, keyFile string) (string, error) {
return "", errors.Wrap(err, "key file")
}

crypter, err := encryption.NewAESCGM(key, nil)
crypter, err := encryption.NewAESGCMWithRandomNonceGenerator(key)
if err != nil {
return "", errors.Wrap(err, "cryptographer")
}
Expand Down
13 changes: 9 additions & 4 deletions encryption/aesgcm.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@ import (
cryptoerr "github.com/seborama/govcr/v8/encryption/errors"
)

// NewAESCGM creates a new Cryptor initialised with an AES-CGM cipher from the
// NewAESGCMWithRandomNonceGenerator creates a new Cryptor initialised with an
// AES-GCM cipher from the supplied key and the default nonce generator.
func NewAESGCMWithRandomNonceGenerator(key []byte) (*Crypter, error) {
return NewAESGCM(key, &RandomNonceGenerator{})
}

// NewAESGCM creates a new Cryptor initialised with an AES-GCM cipher from the
// supplied key.
// The key is sensitive, never share it openly.
//
// When decoded the key should be 16 bytes (AES-128) or 32 (AES-256).
//
// If you want to convert a passphrase to a key, use a suitable
// package like bcrypt or scrypt.
// TODO: as nonceGenerator is not required, make it optional with a functional opt.
// TODO: add a nonceGenerator validator i.e. call it 1000 times, ensures no dupes.
func NewAESCGM(key []byte, nonceGenerator NonceGenerator) (*Crypter, error) {
func NewAESGCM(key []byte, nonceGenerator NonceGenerator) (*Crypter, error) {
if len(key) != 16 && len(key) != 32 {
return nil, cryptoerr.NewErrCrypto("key size is not 16 or 32 bytes")
}
Expand All @@ -33,7 +38,7 @@ func NewAESCGM(key []byte, nonceGenerator NonceGenerator) (*Crypter, error) {
}

if nonceGenerator == nil {
nonceGenerator = &DefaultNonceGenerator{}
nonceGenerator = &RandomNonceGenerator{}
}

return &Crypter{
Expand Down
6 changes: 3 additions & 3 deletions encryption/aesgcm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ import (
func TestCryptor(t *testing.T) {
key := []byte("this is a test key______________")

aescgm, err := encryption.NewAESCGM(key, encryption.DefaultNonceGenerator{})
aesgcm, err := encryption.NewAESGCMWithRandomNonceGenerator(key)
require.NoError(t, err)

inputData := []byte("My little secret!")

ciphertext, nonce, err := aescgm.Encrypt(inputData)
ciphertext, nonce, err := aesgcm.Encrypt(inputData)
require.NoError(t, err)

plaintext, err := aescgm.Decrypt(ciphertext, nonce)
plaintext, err := aesgcm.Decrypt(ciphertext, nonce)
require.NoError(t, err)
assert.Equal(t, inputData, plaintext)
}
4 changes: 2 additions & 2 deletions encryption/nonce.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (
"io"
)

type DefaultNonceGenerator struct{}
type RandomNonceGenerator struct{}

// Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
func (ng DefaultNonceGenerator) Generate() ([]byte, error) {
func (ng RandomNonceGenerator) Generate() ([]byte, error) {
nonce := make([]byte, 12)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, err
Expand Down
4 changes: 2 additions & 2 deletions vcrsettings.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func WithCassetteCrypto(keyFile string) CassetteOption {
panic(fmt.Sprintf("%+v", err))
}

crypter, err := encryption.NewAESCGM(key, nil)
crypter, err := encryption.NewAESGCMWithRandomNonceGenerator(key)
if err != nil {
panic(fmt.Sprintf("%+v", err))
}
Expand All @@ -55,7 +55,7 @@ func WithCassetteCryptoCustomNonce(keyFile string, nonceGenerator encryption.Non
panic(fmt.Sprintf("%+v", err))
}

crypter, err := encryption.NewAESCGM(key, nonceGenerator)
crypter, err := encryption.NewAESGCM(key, nonceGenerator)
if err != nil {
panic(fmt.Sprintf("%+v", err))
}
Expand Down

0 comments on commit 6ce205e

Please sign in to comment.