mirror of https://github.com/restic/restic.git
Refactor JSON data structure for master keys
This commit is contained in:
parent
3e246170de
commit
47d71d23d2
61
crypto.go
61
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 {
|
||||
|
|
|
@ -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
4
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
|
||||
|
|
Loading…
Reference in New Issue