mirror of
https://github.com/octoleo/restic.git
synced 2024-11-26 14:56:29 +00:00
crypto: Match signature of Encrypt() to Decrypt()
This commit is contained in:
parent
7e6acfe44d
commit
f8e1043ad3
@ -205,29 +205,33 @@ func (k *EncryptionKey) UnmarshalJSON(data []byte) error {
|
||||
}
|
||||
|
||||
// Encrypt encrypts and signs data. Stored in ciphertext is IV || Ciphertext ||
|
||||
// MAC. Encrypt returns the ciphertext's length.
|
||||
func Encrypt(ks *Key, ciphertext, plaintext []byte) (int, error) {
|
||||
if cap(ciphertext) < len(plaintext)+ivSize+macSize {
|
||||
return 0, ErrBufferTooSmall
|
||||
// MAC. Encrypt returns the new ciphertext slice, which is extended when
|
||||
// necessary. ciphertext and plaintext may point to the same slice.
|
||||
func Encrypt(ks *Key, ciphertext, plaintext []byte) ([]byte, error) {
|
||||
// extend ciphertext slice if necessary
|
||||
if cap(ciphertext) < len(plaintext)+Extension {
|
||||
ext := len(plaintext) + Extension - cap(ciphertext)
|
||||
n := len(ciphertext)
|
||||
ciphertext = append(ciphertext, make([]byte, ext)...)
|
||||
ciphertext = ciphertext[:n]
|
||||
}
|
||||
|
||||
iv := newIV()
|
||||
copy(ciphertext, iv[:])
|
||||
|
||||
c, err := aes.NewCipher(ks.Encrypt[:])
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unable to create cipher: %v", err))
|
||||
}
|
||||
|
||||
e := cipher.NewCTR(c, ciphertext[:ivSize])
|
||||
e := cipher.NewCTR(c, iv[:])
|
||||
|
||||
e.XORKeyStream(ciphertext[ivSize:cap(ciphertext)], plaintext)
|
||||
copy(ciphertext, iv[:])
|
||||
ciphertext = ciphertext[:ivSize+len(plaintext)]
|
||||
|
||||
mac := poly1305_sign(ciphertext[ivSize:], ciphertext[:ivSize], &ks.Sign)
|
||||
ciphertext = append(ciphertext, mac...)
|
||||
|
||||
return len(ciphertext), nil
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
// Decrypt verifies and decrypts the ciphertext. Ciphertext must be in the form
|
||||
|
@ -98,6 +98,7 @@ func should_panic(f func()) (did_panic bool) {
|
||||
}
|
||||
|
||||
func TestCrypto(t *testing.T) {
|
||||
msg := make([]byte, 0, 8*1024*1024) // use 8MiB for now
|
||||
for _, tv := range test_values {
|
||||
// test encryption
|
||||
k := &Key{
|
||||
@ -105,12 +106,10 @@ func TestCrypto(t *testing.T) {
|
||||
Sign: tv.skey,
|
||||
}
|
||||
|
||||
msg := make([]byte, 0, 8*1024*1024) // use 8MiB for now
|
||||
n, err := Encrypt(k, msg, tv.plaintext)
|
||||
msg, err := Encrypt(k, msg, tv.plaintext)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
msg = msg[:n]
|
||||
|
||||
// decrypt message
|
||||
_, err = Decrypt(k, []byte{}, msg)
|
||||
|
@ -29,11 +29,10 @@ func TestEncryptDecrypt(t *testing.T) {
|
||||
_, err := io.ReadFull(RandomReader(42, size), data)
|
||||
OK(t, err)
|
||||
|
||||
ciphertext := restic.GetChunkBuf("TestEncryptDecrypt")
|
||||
n, err := crypto.Encrypt(k, ciphertext, data)
|
||||
ciphertext, err := crypto.Encrypt(k, restic.GetChunkBuf("TestEncryptDecrypt"), data)
|
||||
OK(t, err)
|
||||
|
||||
plaintext, err := crypto.Decrypt(k, nil, ciphertext[:n])
|
||||
plaintext, err := crypto.Decrypt(k, nil, ciphertext)
|
||||
OK(t, err)
|
||||
|
||||
restic.FreeChunkBuf("TestEncryptDecrypt", ciphertext)
|
||||
@ -54,10 +53,40 @@ func TestSmallBuffer(t *testing.T) {
|
||||
OK(t, err)
|
||||
|
||||
ciphertext := make([]byte, size/2)
|
||||
_, err = crypto.Encrypt(k, ciphertext, data)
|
||||
ciphertext, err = crypto.Encrypt(k, ciphertext, data)
|
||||
// this must throw an error, since the target slice is too small
|
||||
Assert(t, err != nil && err == crypto.ErrBufferTooSmall,
|
||||
"expected restic.ErrBufferTooSmall, got %#v", err)
|
||||
Assert(t, cap(ciphertext) > size/2,
|
||||
"expected extended slice, but capacity is only %d bytes",
|
||||
cap(ciphertext))
|
||||
|
||||
// check for the correct plaintext
|
||||
plaintext, err := crypto.Decrypt(k, nil, ciphertext)
|
||||
OK(t, err)
|
||||
Assert(t, bytes.Equal(plaintext, data),
|
||||
"wrong plaintext returned")
|
||||
}
|
||||
|
||||
func TestSameBuffer(t *testing.T) {
|
||||
k := crypto.NewKey()
|
||||
|
||||
size := 600
|
||||
data := make([]byte, size)
|
||||
f, err := os.Open("/dev/urandom")
|
||||
OK(t, err)
|
||||
|
||||
_, err = io.ReadFull(f, data)
|
||||
OK(t, err)
|
||||
|
||||
ciphertext := make([]byte, size)
|
||||
copy(ciphertext, data)
|
||||
|
||||
ciphertext, err = crypto.Encrypt(k, ciphertext, ciphertext)
|
||||
OK(t, err)
|
||||
|
||||
ciphertext, err = crypto.Decrypt(k, ciphertext, ciphertext)
|
||||
OK(t, err)
|
||||
Assert(t, bytes.Equal(ciphertext, data),
|
||||
"wrong plaintext returned")
|
||||
}
|
||||
|
||||
func TestLargeEncrypt(t *testing.T) {
|
||||
@ -75,11 +104,10 @@ func TestLargeEncrypt(t *testing.T) {
|
||||
_, err = io.ReadFull(f, data)
|
||||
OK(t, err)
|
||||
|
||||
ciphertext := make([]byte, size+crypto.Extension)
|
||||
n, err := crypto.Encrypt(k, ciphertext, data)
|
||||
ciphertext, err := crypto.Encrypt(k, make([]byte, size+crypto.Extension), data)
|
||||
OK(t, err)
|
||||
|
||||
plaintext, err := crypto.Decrypt(k, []byte{}, ciphertext[:n])
|
||||
plaintext, err := crypto.Decrypt(k, []byte{}, ciphertext)
|
||||
OK(t, err)
|
||||
|
||||
Equals(t, plaintext, data)
|
||||
@ -183,14 +211,14 @@ func BenchmarkDecrypt(b *testing.B) {
|
||||
plaintext := restic.GetChunkBuf("BenchmarkDecrypt")
|
||||
defer restic.FreeChunkBuf("BenchmarkDecrypt", plaintext)
|
||||
|
||||
n, err := crypto.Encrypt(k, ciphertext, data)
|
||||
ciphertext, err := crypto.Encrypt(k, ciphertext, data)
|
||||
OK(b, err)
|
||||
|
||||
b.ResetTimer()
|
||||
b.SetBytes(int64(size))
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
plaintext, err = crypto.Decrypt(k, plaintext, ciphertext[:n])
|
||||
plaintext, err = crypto.Decrypt(k, plaintext, ciphertext)
|
||||
OK(b, err)
|
||||
}
|
||||
}
|
||||
@ -245,11 +273,11 @@ func TestDecryptStreamReader(t *testing.T) {
|
||||
ciphertext := make([]byte, size+crypto.Extension)
|
||||
|
||||
// encrypt with default function
|
||||
n, err := crypto.Encrypt(k, ciphertext, data)
|
||||
ciphertext, err = crypto.Encrypt(k, ciphertext, data)
|
||||
OK(t, err)
|
||||
Assert(t, n == len(data)+crypto.Extension,
|
||||
Assert(t, len(ciphertext) == len(data)+crypto.Extension,
|
||||
"wrong number of bytes returned after encryption: expected %d, got %d",
|
||||
len(data)+crypto.Extension, n)
|
||||
len(data)+crypto.Extension, len(ciphertext))
|
||||
|
||||
rd, err := crypto.DecryptFrom(k, bytes.NewReader(ciphertext))
|
||||
OK(t, err)
|
||||
|
9
key.go
9
key.go
@ -196,9 +196,7 @@ func AddKey(s Server, password string, template *Key) (*Key, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newkey.Data = GetChunkBuf("key")
|
||||
n, err = crypto.Encrypt(newkey.user, newkey.Data, buf)
|
||||
newkey.Data = newkey.Data[:n]
|
||||
newkey.Data, err = crypto.Encrypt(newkey.user, GetChunkBuf("key"), buf)
|
||||
|
||||
// dump as json
|
||||
buf, err = json.Marshal(newkey)
|
||||
@ -234,8 +232,9 @@ func AddKey(s Server, password string, template *Key) (*Key, error) {
|
||||
}
|
||||
|
||||
// Encrypt encrypts and signs data with the master key. Stored in ciphertext is
|
||||
// IV || Ciphertext || MAC. Returns the ciphertext length.
|
||||
func (k *Key) Encrypt(ciphertext, plaintext []byte) (int, error) {
|
||||
// IV || Ciphertext || MAC. Returns the ciphertext, which is extended if
|
||||
// necessary.
|
||||
func (k *Key) Encrypt(ciphertext, plaintext []byte) ([]byte, error) {
|
||||
return crypto.Encrypt(k.master, ciphertext, plaintext)
|
||||
}
|
||||
|
||||
|
@ -172,13 +172,11 @@ func (s Server) Save(t backend.Type, data []byte, id backend.ID) (Blob, error) {
|
||||
}
|
||||
|
||||
// encrypt blob
|
||||
n, err := s.Encrypt(ciphertext, data)
|
||||
ciphertext, err := s.Encrypt(ciphertext, data)
|
||||
if err != nil {
|
||||
return Blob{}, err
|
||||
}
|
||||
|
||||
ciphertext = ciphertext[:n]
|
||||
|
||||
// compute ciphertext hash
|
||||
sid := backend.Hash(ciphertext)
|
||||
|
||||
@ -309,9 +307,9 @@ func (s Server) Decrypt(ciphertext []byte) ([]byte, error) {
|
||||
return s.key.Decrypt([]byte{}, ciphertext)
|
||||
}
|
||||
|
||||
func (s Server) Encrypt(ciphertext, plaintext []byte) (int, error) {
|
||||
func (s Server) Encrypt(ciphertext, plaintext []byte) ([]byte, error) {
|
||||
if s.key == nil {
|
||||
return 0, errors.New("key for server not set")
|
||||
return nil, errors.New("key for server not set")
|
||||
}
|
||||
|
||||
return s.key.Encrypt(ciphertext, plaintext)
|
||||
|
Loading…
Reference in New Issue
Block a user