diff --git a/crypto.go b/crypto.go index 6cd50557b..741ae9598 100644 --- a/crypto.go +++ b/crypto.go @@ -15,13 +15,18 @@ import ( ) const ( - AESKeySize = 32 // for AES256 - MACKeySize = 16 + 16 // for Poly1305-AES128 - ivSize = aes.BlockSize + AESKeySize = 32 // for AES256 + MACKeySizeK = 16 // for AES-128 + MACKeySizeR = 16 // for Poly1305 + MACKeySize = MACKeySizeK + MACKeySizeR // for Poly1305-AES128 + ivSize = aes.BlockSize ) type AESKey [32]byte -type MACKey [32]byte +type MACKey struct { + K [16]byte // for AES128 + R [16]byte // for Poly1305 +} type IV [ivSize]byte // mask for key, (cf. http://cr.yp.to/mac/poly1305-20050329.pdf) @@ -53,14 +58,14 @@ func poly1305_sign(msg []byte, nonce []byte, key *MACKey) []byte { maskKey(key) // fill in nonce, encrypted with AES and key[:16] - cipher, err := aes.NewCipher(key[:16]) + cipher, err := aes.NewCipher(key.K[:]) if err != nil { panic(err) } cipher.Encrypt(k[16:], nonce[:]) // copy r - copy(k[:16], key[16:]) + copy(k[:16], key.R[:]) // save mac in out var out [16]byte @@ -75,10 +80,20 @@ func maskKey(k *MACKey) { return } for i := 0; i < poly1305.TagSize; i++ { - k[i+16] = k[i+16] & poly1305KeyMask[i] + k.R[i] = k.R[i] & poly1305KeyMask[i] } } +// construct mac key from slice (k||r), with masking +func macKeyFromSlice(data []byte) *MACKey { + mk := &MACKey{} + copy(mk.K[:], data[:16]) + copy(mk.R[:], data[16:32]) + maskKey(mk) + + return mk +} + // key: k||r func poly1305_verify(msg []byte, nonce []byte, key *MACKey, mac []byte) bool { // prepare key for low-level poly1305.Sum(): r||n @@ -88,14 +103,14 @@ func poly1305_verify(msg []byte, nonce []byte, key *MACKey, mac []byte) bool { maskKey(key) // fill in nonce, encrypted with AES and key[:16] - cipher, err := aes.NewCipher(key[:16]) + cipher, err := aes.NewCipher(key.K[:]) if err != nil { panic(err) } cipher.Encrypt(k[16:], nonce[:]) // copy r - copy(k[:16], key[16:]) + copy(k[:16], key.R[:]) // copy mac to array var m [16]byte @@ -113,15 +128,19 @@ func generateRandomAESKey() (k *AESKey) { return } -// returns [32]byte == k||r +// returns a new mac key. k.R is already masked func generateRandomMACKey() (k *MACKey) { k = &MACKey{} - n, err := rand.Read(k[:]) - if n != MACKeySize || err != nil { - panic("unable to read enough random bytes for mac key") + n, err := rand.Read(k.K[:]) + if n != MACKeySizeK || err != nil { + panic("unable to read enough random bytes for mac encryption key") } - // mask r in second half + n, err = rand.Read(k.R[:]) + if n != MACKeySizeR || err != nil { + panic("unable to read enough random bytes for mac signing key") + } + // mask r maskKey(k) return @@ -161,7 +180,7 @@ func Encrypt(ks *keys, ciphertext, plaintext []byte) (int, error) { return len(ciphertext), nil } -// Decrypt verifes and decrypts the ciphertext. Ciphertext must be in the form +// Decrypt verifies and decrypts the ciphertext. Ciphertext must be in the form // IV || Ciphertext || MAC. func Decrypt(ks *keys, plaintext, ciphertext []byte) ([]byte, error) { // check for plausible length @@ -216,17 +235,13 @@ func kdf(k *Key, password string) (*keys, error) { return nil, fmt.Errorf("invalid numbers of bytes expanded from scrypt(): %d", len(scryptKeys)) } + // first 32 byte of scrypt output is the encryption key ek := &AESKey{} copy(ek[:], scryptKeys[:AESKeySize]) - mk := &MACKey{} - copy(mk[:], scryptKeys[AESKeySize:]) - - ks := &keys{ - Encrypt: ek, - Sign: mk, - } - return ks, nil + // next 32 byte of scrypt output is the mac key, in the form k||r + mk := macKeyFromSlice(scryptKeys[AESKeySize:]) + return &keys{Encrypt: ek, Sign: mk}, nil } type encryptWriter struct { diff --git a/crypto_int_test.go b/crypto_int_test.go index 2da59ee19..88befb887 100644 --- a/crypto_int_test.go +++ b/crypto_int_test.go @@ -46,8 +46,8 @@ var poly1305_tests = []struct { func TestPoly1305(t *testing.T) { for _, test := range poly1305_tests { key := &MACKey{} - copy(key[:16], test.k) - copy(key[16:], test.r) + copy(key.K[:], test.k) + copy(key.R[:], test.r) mac := poly1305_sign(test.msg, test.nonce, key) if !bytes.Equal(mac, test.mac) { @@ -70,8 +70,10 @@ var test_values = []struct { { ekey: AESKey([...]byte{0x30, 0x3e, 0x86, 0x87, 0xb1, 0xd7, 0xdb, 0x18, 0x42, 0x1b, 0xdc, 0x6b, 0xb8, 0x58, 0x8c, 0xca, 0xda, 0xc4, 0xd5, 0x9e, 0xe8, 0x7b, 0x8f, 0xf7, 0x0c, 0x44, 0xe6, 0x35, 0x79, 0x0c, 0xaf, 0xef}), - skey: MACKey([...]byte{0xef, 0x4d, 0x88, 0x24, 0xcb, 0x80, 0xb2, 0xbc, 0xc5, 0xfb, 0xff, 0x8a, 0x9b, 0x12, 0xa4, 0x2c, - 0xcc, 0x8d, 0x4b, 0x94, 0x8e, 0xe0, 0xeb, 0xfe, 0x1d, 0x41, 0x5d, 0xe9, 0x21, 0xd1, 0x03, 0x53}), + skey: MACKey{ + K: [...]byte{0xef, 0x4d, 0x88, 0x24, 0xcb, 0x80, 0xb2, 0xbc, 0xc5, 0xfb, 0xff, 0x8a, 0x9b, 0x12, 0xa4, 0x2c}, + R: [...]byte{0xcc, 0x8d, 0x4b, 0x94, 0x8e, 0xe0, 0xeb, 0xfe, 0x1d, 0x41, 0x5d, 0xe9, 0x21, 0xd1, 0x03, 0x53}, + }, ciphertext: decode_hex("69fb41c62d12def4593bd71757138606338f621aeaeb39da0fe4f99233f8037a54ea63338a813bcf3f75d8c3cc75dddf8750"), plaintext: []byte("Dies ist ein Test!"), }, diff --git a/key.go b/key.go index 3e9d10c67..5f88a5eca 100644 --- a/key.go +++ b/key.go @@ -60,7 +60,9 @@ type Key struct { id backend.ID } -// keys is a JSON structure that holds signing and encryption keys. +// MasterKeys holds signing and encryption keys for a repository. It is stored +// encrypted and signed as a JSON data structure in the Data field of the Key +// structure. type keys struct { Sign *MACKey Encrypt *AESKey