2016-09-26 23:06:40 +02:00
|
|
|
// Package siv_aead wraps the functions provided by siv
|
|
|
|
// in a crypto.AEAD interface.
|
|
|
|
package siv_aead
|
|
|
|
|
|
|
|
import (
|
2016-10-02 06:14:18 +02:00
|
|
|
"crypto/cipher"
|
2016-12-10 11:50:16 +01:00
|
|
|
"log"
|
2016-10-02 06:14:18 +02:00
|
|
|
|
2016-09-26 23:06:40 +02:00
|
|
|
"github.com/jacobsa/crypto/siv"
|
|
|
|
)
|
|
|
|
|
|
|
|
type sivAead struct {
|
|
|
|
key []byte
|
|
|
|
}
|
|
|
|
|
2016-10-02 06:14:18 +02:00
|
|
|
var _ cipher.AEAD = &sivAead{}
|
|
|
|
|
2017-03-05 21:59:55 +01:00
|
|
|
const (
|
2017-04-29 14:50:58 +02:00
|
|
|
// KeyLen is the required key length. The SIV algorithm supports other lengths,
|
|
|
|
// but we only support 64.
|
2017-03-05 21:59:55 +01:00
|
|
|
KeyLen = 64
|
|
|
|
)
|
|
|
|
|
2016-10-02 06:14:18 +02:00
|
|
|
// New returns a new cipher.AEAD implementation.
|
|
|
|
func New(key []byte) cipher.AEAD {
|
2017-03-05 21:59:55 +01:00
|
|
|
if len(key) != KeyLen {
|
2017-04-29 14:50:58 +02:00
|
|
|
// SIV supports 32, 48 or 64-byte keys, but in gocryptfs we
|
2017-03-05 21:59:55 +01:00
|
|
|
// exclusively use 64.
|
|
|
|
log.Panicf("Key must be %d byte long (you passed %d)", KeyLen, len(key))
|
|
|
|
}
|
|
|
|
return new2(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same as "New" without the 64-byte restriction.
|
2018-02-18 16:01:46 +01:00
|
|
|
func new2(keyIn []byte) cipher.AEAD {
|
|
|
|
// Create a private copy so the caller can zero the one he owns
|
|
|
|
key := append([]byte{}, keyIn...)
|
2016-09-26 23:06:40 +02:00
|
|
|
return &sivAead{
|
|
|
|
key: key,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *sivAead) NonceSize() int {
|
|
|
|
// SIV supports any nonce size, but in gocryptfs we exclusively use 16.
|
|
|
|
return 16
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *sivAead) Overhead() int {
|
2016-10-03 23:58:19 +02:00
|
|
|
return 16
|
2016-09-26 23:06:40 +02:00
|
|
|
}
|
|
|
|
|
2017-09-17 11:42:46 +02:00
|
|
|
// Seal encrypts "in" using "nonce" and "authData" and appends the result to "dst"
|
2016-09-26 23:06:40 +02:00
|
|
|
func (s *sivAead) Seal(dst, nonce, plaintext, authData []byte) []byte {
|
|
|
|
if len(nonce) != 16 {
|
|
|
|
// SIV supports any nonce size, but in gocryptfs we exclusively use 16.
|
2016-12-10 11:50:16 +01:00
|
|
|
log.Panic("nonce must be 16 bytes long")
|
2016-09-26 23:06:40 +02:00
|
|
|
}
|
2018-02-18 16:01:46 +01:00
|
|
|
if len(s.key) == 0 {
|
|
|
|
log.Panic("Key has been wiped?")
|
|
|
|
}
|
2016-09-26 23:06:40 +02:00
|
|
|
// https://github.com/jacobsa/crypto/blob/master/siv/encrypt.go#L48:
|
|
|
|
// As per RFC 5297 section 3, you may use this function for nonce-based
|
|
|
|
// authenticated encryption by passing a nonce as the last associated
|
|
|
|
// data element.
|
|
|
|
associated := [][]byte{authData, nonce}
|
|
|
|
out, err := siv.Encrypt(dst, s.key, plaintext, associated)
|
|
|
|
if err != nil {
|
2016-12-10 11:50:16 +01:00
|
|
|
log.Panic(err)
|
2016-09-26 23:06:40 +02:00
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2017-09-17 11:42:46 +02:00
|
|
|
// Open decrypts "in" using "nonce" and "authData" and appends the result to "dst"
|
2016-09-26 23:06:40 +02:00
|
|
|
func (s *sivAead) Open(dst, nonce, ciphertext, authData []byte) ([]byte, error) {
|
|
|
|
if len(nonce) != 16 {
|
|
|
|
// SIV supports any nonce size, but in gocryptfs we exclusively use 16.
|
2016-12-10 11:50:16 +01:00
|
|
|
log.Panic("nonce must be 16 bytes long")
|
2016-09-26 23:06:40 +02:00
|
|
|
}
|
2018-02-18 16:01:46 +01:00
|
|
|
if len(s.key) == 0 {
|
|
|
|
log.Panic("Key has been wiped?")
|
|
|
|
}
|
2016-09-26 23:06:40 +02:00
|
|
|
associated := [][]byte{authData, nonce}
|
|
|
|
dec, err := siv.Decrypt(s.key, ciphertext, associated)
|
|
|
|
return append(dst, dec...), err
|
|
|
|
}
|
2018-02-18 16:01:46 +01:00
|
|
|
|
|
|
|
// Wipe tries to wipe the AES key from memory by overwriting it with zeros
|
|
|
|
// and setting the reference to nil.
|
|
|
|
//
|
|
|
|
// This is not bulletproof due to possible GC copies, but
|
|
|
|
// still raises to bar for extracting the key.
|
|
|
|
func (s *sivAead) Wipe() {
|
|
|
|
for i := range s.key {
|
|
|
|
s.key[i] = 0
|
|
|
|
}
|
|
|
|
s.key = nil
|
|
|
|
}
|