gitlab.com/SiaPrime/SiaPrime@v1.4.1/crypto/twofish.go (about)

     1  package crypto
     2  
     3  import (
     4  	"crypto/cipher"
     5  	"fmt"
     6  
     7  	"gitlab.com/NebulousLabs/errors"
     8  	"gitlab.com/NebulousLabs/fastrand"
     9  	"golang.org/x/crypto/twofish"
    10  )
    11  
    12  const (
    13  	// twofishOverhead is the number of bytes added by EncryptBytes.
    14  	twofishOverhead = 28
    15  )
    16  
    17  var (
    18  	// ErrInsufficientLen is an error when supplied ciphertext is not
    19  	// long enough to contain a nonce.
    20  	ErrInsufficientLen = errors.New("supplied ciphertext is not long enough to contain a nonce")
    21  )
    22  
    23  type (
    24  	// TwofishKey is a key used for encrypting and decrypting data.
    25  	TwofishKey [EntropySize]byte
    26  )
    27  
    28  // generateTwofishKey produces a TwofishKey that can be used for encrypting and
    29  // decrypting data using Twofish-GCM.
    30  func generateTwofishKey() (key TwofishKey) {
    31  	fastrand.Read(key[:])
    32  	return
    33  }
    34  
    35  // newCipher creates a new Twofish cipher from the key.
    36  func (key TwofishKey) newCipher() cipher.Block {
    37  	cipher, err := twofish.NewCipher(key[:])
    38  	if err != nil {
    39  		panic("NewCipher only returns an error if len(key) != 16, 24, or 32.")
    40  	}
    41  	return cipher
    42  }
    43  
    44  // newTwofishKey creates a new TwofishKey from a given entropy.
    45  func newTwofishKey(entropy []byte) (key TwofishKey, err error) {
    46  	// check key length
    47  	if len(entropy) != len(key) {
    48  		err = fmt.Errorf("twofish key should have size %v but was %v",
    49  			EntropySize, len(entropy))
    50  		return
    51  	}
    52  	// create key
    53  	copy(key[:], entropy)
    54  	return
    55  }
    56  
    57  // DecryptBytes decrypts a ciphertext created by EncryptPiece. The nonce is
    58  // expected to be the first 12 bytes of the ciphertext.
    59  func (key TwofishKey) DecryptBytes(ct Ciphertext) ([]byte, error) {
    60  	// Create the cipher.
    61  	aead, err := cipher.NewGCM(key.newCipher())
    62  	if err != nil {
    63  		return nil, errors.AddContext(err, "NewGCM should only return an error if twofishCipher.BlockSize != 16")
    64  	}
    65  	return DecryptWithNonce(ct, aead)
    66  }
    67  
    68  // DecryptBytesInPlace decrypts the ciphertext created by EncryptBytes. The
    69  // nonce is expected to be the first 12 bytes of the ciphertext.
    70  // DecryptBytesInPlace reuses the memory of ct to be able to operate in-place.
    71  // This means that ct can't be reused after calling DecryptBytesInPlace.
    72  func (key TwofishKey) DecryptBytesInPlace(ct Ciphertext, blockIndex uint64) ([]byte, error) {
    73  	if blockIndex != 0 {
    74  		return nil, errors.New("twofish doesn't support a blockIndex != 0")
    75  	}
    76  	// Create the cipher.
    77  	aead, err := cipher.NewGCM(key.newCipher())
    78  	if err != nil {
    79  		return nil, errors.AddContext(err, "NewGCM should only return an error if twofishCipher.BlockSize != 16")
    80  	}
    81  
    82  	// Check for a nonce.
    83  	if len(ct) < aead.NonceSize() {
    84  		return nil, ErrInsufficientLen
    85  	}
    86  
    87  	// Decrypt the data.
    88  	nonce := ct[:aead.NonceSize()]
    89  	ciphertext := ct[aead.NonceSize():]
    90  	return aead.Open(ciphertext[:0], nonce, ciphertext, nil)
    91  }
    92  
    93  // Derive derives a child key for a given combination of chunk and piece index.
    94  func (key TwofishKey) Derive(chunkIndex, pieceIndex uint64) CipherKey {
    95  	entropy := HashAll(key, chunkIndex, pieceIndex)
    96  	ck, err := NewSiaKey(TypeTwofish, entropy[:])
    97  	if err != nil {
    98  		panic("this should not be possible when deriving from a valid key")
    99  	}
   100  	return ck
   101  }
   102  
   103  // EncryptBytes encrypts arbitrary data using the TwofishKey, prepending a 12
   104  // byte nonce to the ciphertext in the process.  GCM and prepends the nonce (12
   105  // bytes) to the ciphertext.
   106  func (key TwofishKey) EncryptBytes(piece []byte) Ciphertext {
   107  	// Create the cipher.
   108  	aead, err := cipher.NewGCM(key.newCipher())
   109  	if err != nil {
   110  		panic("NewGCM only returns an error if twofishCipher.BlockSize != 16")
   111  	}
   112  	return EncryptWithNonce(piece, aead)
   113  }
   114  
   115  // Key returns the twofish key.
   116  func (key TwofishKey) Key() []byte {
   117  	return key[:]
   118  }
   119  
   120  // Type returns the type of the twofish key.
   121  func (TwofishKey) Type() CipherType {
   122  	return TypeTwofish
   123  }