2
2
mirror of https://github.com/octoleo/restic.git synced 2024-05-28 22:50:48 +00:00

Refactor JSON data structure for master keys

This commit is contained in:
Alexander Neumann 2015-03-22 19:09:30 +01:00
parent 3e246170de
commit 47d71d23d2
3 changed files with 47 additions and 28 deletions

View File

@ -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 {

View File

@ -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!"),
},

4
key.go
View File

@ -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