mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
watchtower/blob/justice_kit: use randomized 192-bit nonce
This commit modifies the blob encryption scheme to use chacha20-poly1305 with a randomized 192-bit nonce. The previous approach used a deterministic nonce scheme, which is being replaced to simplify the requirements of a correct implementation. As a result, each payload gains an addtional 24-bytes prepended to the ciphertext.
This commit is contained in:
parent
2dd399ca52
commit
c5eba3b608
@ -2,6 +2,7 @@ package blob
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -22,8 +23,8 @@ const (
|
|||||||
// MaxVersion is the maximumm blob version supported by this package.
|
// MaxVersion is the maximumm blob version supported by this package.
|
||||||
MaxVersion = 0
|
MaxVersion = 0
|
||||||
|
|
||||||
// NonceSize is the length of a chacha20poly1305 nonce, 12 bytes.
|
// NonceSize is the length of a chacha20poly1305 nonce, 24 bytes.
|
||||||
NonceSize = chacha20poly1305.NonceSize
|
NonceSize = chacha20poly1305.NonceSizeX
|
||||||
|
|
||||||
// KeySize is the length of a chacha20poly1305 key, 32 bytes.
|
// KeySize is the length of a chacha20poly1305 key, 32 bytes.
|
||||||
KeySize = chacha20poly1305.KeySize
|
KeySize = chacha20poly1305.KeySize
|
||||||
@ -49,10 +50,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Size returns the size of the encoded-and-encrypted blob in bytes.
|
// Size returns the size of the encoded-and-encrypted blob in bytes.
|
||||||
// enciphered plaintext: n bytes
|
// nonce: 24 bytes
|
||||||
// MAC: 16 bytes
|
// enciphered plaintext: n bytes
|
||||||
|
// MAC: 16 bytes
|
||||||
func Size(ver uint16) int {
|
func Size(ver uint16) int {
|
||||||
return PlaintextSize(ver) + CiphertextExpansion
|
return NonceSize + PlaintextSize(ver) + CiphertextExpansion
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlaintextSize returns the size of the encoded-but-unencrypted blob in bytes.
|
// PlaintextSize returns the size of the encoded-but-unencrypted blob in bytes.
|
||||||
@ -79,11 +81,6 @@ var (
|
|||||||
"ciphertext is too small for chacha20poly1305",
|
"ciphertext is too small for chacha20poly1305",
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNonceSize signals that the provided nonce is improperly sized.
|
|
||||||
ErrNonceSize = fmt.Errorf(
|
|
||||||
"chacha20poly1305 nonce must be %d bytes", NonceSize,
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrKeySize signals that the provided key is improperly sized.
|
// ErrKeySize signals that the provided key is improperly sized.
|
||||||
ErrKeySize = fmt.Errorf(
|
ErrKeySize = fmt.Errorf(
|
||||||
"chacha20poly1305 key size must be %d bytes", KeySize,
|
"chacha20poly1305 key size must be %d bytes", KeySize,
|
||||||
@ -232,15 +229,9 @@ func (b *JusticeKit) CommitToRemoteWitnessStack() ([][]byte, error) {
|
|||||||
//
|
//
|
||||||
// NOTE: It is the caller's responsibility to ensure that this method is only
|
// NOTE: It is the caller's responsibility to ensure that this method is only
|
||||||
// called once for a given (nonce, key) pair.
|
// called once for a given (nonce, key) pair.
|
||||||
func (b *JusticeKit) Encrypt(nonce, key []byte, version uint16) ([]byte, error) {
|
func (b *JusticeKit) Encrypt(key []byte, version uint16) ([]byte, error) {
|
||||||
switch {
|
|
||||||
|
|
||||||
// Fail if the nonce is not 12-bytes.
|
|
||||||
case len(nonce) != NonceSize:
|
|
||||||
return nil, ErrNonceSize
|
|
||||||
|
|
||||||
// Fail if the nonce is not 32-bytes.
|
// Fail if the nonce is not 32-bytes.
|
||||||
case len(key) != KeySize:
|
if len(key) != KeySize {
|
||||||
return nil, ErrKeySize
|
return nil, ErrKeySize
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,19 +244,25 @@ func (b *JusticeKit) Encrypt(nonce, key []byte, version uint16) ([]byte, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new chacha20poly1305 cipher, using a 32-byte key.
|
// Create a new chacha20poly1305 cipher, using a 32-byte key.
|
||||||
cipher, err := chacha20poly1305.New(key)
|
cipher, err := chacha20poly1305.NewX(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the ciphertext, which will contain the encrypted plaintext
|
// Allocate the ciphertext, which will contain the nonce, encrypted
|
||||||
// and MAC.
|
// plaintext and MAC.
|
||||||
plaintext := ptxtBuf.Bytes()
|
plaintext := ptxtBuf.Bytes()
|
||||||
ciphertext := make([]byte, len(plaintext)+CiphertextExpansion)
|
ciphertext := make([]byte, Size(version))
|
||||||
|
|
||||||
|
// Generate a random 24-byte nonce in the ciphertext's prefix.
|
||||||
|
nonce := ciphertext[:NonceSize]
|
||||||
|
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Finally, encrypt the plaintext using the given nonce, storing the
|
// Finally, encrypt the plaintext using the given nonce, storing the
|
||||||
// result in the ciphertext buffer.
|
// result in the ciphertext buffer.
|
||||||
cipher.Seal(ciphertext[:0], nonce, plaintext, nil)
|
cipher.Seal(ciphertext[NonceSize:NonceSize], nonce, plaintext, nil)
|
||||||
|
|
||||||
return ciphertext, nil
|
return ciphertext, nil
|
||||||
}
|
}
|
||||||
@ -273,24 +270,21 @@ func (b *JusticeKit) Encrypt(nonce, key []byte, version uint16) ([]byte, error)
|
|||||||
// Decrypt unenciphers a blob of justice by decrypting the ciphertext using
|
// Decrypt unenciphers a blob of justice by decrypting the ciphertext using
|
||||||
// chacha20poly1305 with the chosen (nonce, key) pair. The internal plaintext is
|
// chacha20poly1305 with the chosen (nonce, key) pair. The internal plaintext is
|
||||||
// then deserialized using the given encoding version.
|
// then deserialized using the given encoding version.
|
||||||
func Decrypt(nonce, key, ciphertext []byte, version uint16) (*JusticeKit, error) {
|
func Decrypt(key, ciphertext []byte, version uint16) (*JusticeKit, error) {
|
||||||
switch {
|
switch {
|
||||||
|
|
||||||
// Fail if the blob's overall length is less than the expansion factor.
|
// Fail if the blob's overall length is less than required for the nonce
|
||||||
case len(ciphertext) < CiphertextExpansion:
|
// and expansion factor.
|
||||||
|
case len(ciphertext) < NonceSize+CiphertextExpansion:
|
||||||
return nil, ErrCiphertextTooSmall
|
return nil, ErrCiphertextTooSmall
|
||||||
|
|
||||||
// Fail if the nonce is not 12-bytes.
|
|
||||||
case len(nonce) != NonceSize:
|
|
||||||
return nil, ErrNonceSize
|
|
||||||
|
|
||||||
// Fail if the key is not 32-bytes.
|
// Fail if the key is not 32-bytes.
|
||||||
case len(key) != KeySize:
|
case len(key) != KeySize:
|
||||||
return nil, ErrKeySize
|
return nil, ErrKeySize
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new chacha20poly1305 cipher, using a 32-byte key.
|
// Create a new chacha20poly1305 cipher, using a 32-byte key.
|
||||||
cipher, err := chacha20poly1305.New(key)
|
cipher, err := chacha20poly1305.NewX(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -302,7 +296,8 @@ func Decrypt(nonce, key, ciphertext []byte, version uint16) (*JusticeKit, error)
|
|||||||
|
|
||||||
// Decrypt the ciphertext, placing the resulting plaintext in our
|
// Decrypt the ciphertext, placing the resulting plaintext in our
|
||||||
// plaintext buffer.
|
// plaintext buffer.
|
||||||
_, err = cipher.Open(plaintext[:0], nonce, ciphertext, nil)
|
nonce := ciphertext[:NonceSize]
|
||||||
|
_, err = cipher.Open(plaintext[:0], nonce, ciphertext[NonceSize:], nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user