github.com/ZuluSpl0it/Sia@v1.3.7/crypto/encrypt.go (about)

     1  package crypto
     2  
     3  // encrypt.go contains functions for encrypting and decrypting data byte slices
     4  // and readers.
     5  
     6  import (
     7  	"crypto/cipher"
     8  	"encoding/json"
     9  	"errors"
    10  	"io"
    11  
    12  	"github.com/NebulousLabs/fastrand"
    13  
    14  	"golang.org/x/crypto/twofish"
    15  )
    16  
    17  const (
    18  	// TwofishOverhead is the number of bytes added by EncryptBytes
    19  	TwofishOverhead = 28
    20  )
    21  
    22  var (
    23  	// ErrInsufficientLen is an error when supplied ciphertext is not
    24  	// long enough to contain a nonce.
    25  	ErrInsufficientLen = errors.New("supplied ciphertext is not long enough to contain a nonce")
    26  )
    27  
    28  type (
    29  	// Ciphertext is an encrypted []byte.
    30  	Ciphertext []byte
    31  	// TwofishKey is a key used for encrypting and decrypting data.
    32  	TwofishKey [EntropySize]byte
    33  )
    34  
    35  // GenerateTwofishKey produces a key that can be used for encrypting and
    36  // decrypting files.
    37  func GenerateTwofishKey() (key TwofishKey) {
    38  	fastrand.Read(key[:])
    39  	return
    40  }
    41  
    42  // NewCipher creates a new Twofish cipher from the key.
    43  func (key TwofishKey) NewCipher() cipher.Block {
    44  	// NOTE: NewCipher only returns an error if len(key) != 16, 24, or 32.
    45  	cipher, _ := twofish.NewCipher(key[:])
    46  	return cipher
    47  }
    48  
    49  // EncryptBytes encrypts a []byte using the key. EncryptBytes uses GCM and
    50  // prepends the nonce (12 bytes) to the ciphertext.
    51  func (key TwofishKey) EncryptBytes(plaintext []byte) Ciphertext {
    52  	// Create the cipher.
    53  	// NOTE: NewGCM only returns an error if twofishCipher.BlockSize != 16.
    54  	aead, _ := cipher.NewGCM(key.NewCipher())
    55  
    56  	// Create the nonce.
    57  	nonce := fastrand.Bytes(aead.NonceSize())
    58  
    59  	// Encrypt the data. No authenticated data is provided, as EncryptBytes is
    60  	// meant for file encryption.
    61  	return aead.Seal(nonce, nonce, plaintext, nil)
    62  }
    63  
    64  // DecryptBytes decrypts the ciphertext created by EncryptBytes. The nonce is
    65  // expected to be the first 12 bytes of the ciphertext.
    66  func (key TwofishKey) DecryptBytes(ct Ciphertext) ([]byte, error) {
    67  	// Create the cipher.
    68  	// NOTE: NewGCM only returns an error if twofishCipher.BlockSize != 16.
    69  	aead, _ := cipher.NewGCM(key.NewCipher())
    70  
    71  	// Check for a nonce.
    72  	if len(ct) < aead.NonceSize() {
    73  		return nil, ErrInsufficientLen
    74  	}
    75  
    76  	// Decrypt the data.
    77  	nonce := ct[:aead.NonceSize()]
    78  	ciphertext := ct[aead.NonceSize():]
    79  	return aead.Open(nil, nonce, ciphertext, nil)
    80  }
    81  
    82  // DecryptBytesInPlace decrypts the ciphertext created by EncryptBytes. The
    83  // nonce is expected to be the first 12 bytes of the ciphertext.
    84  // DecryptBytesInPlace reuses the memory of ct to be able to operate in-place.
    85  // This means that ct can't be reused after calling DecryptBytesInPlace.
    86  func (key TwofishKey) DecryptBytesInPlace(ct Ciphertext) ([]byte, error) {
    87  	// Create the cipher.
    88  	// NOTE: NewGCM only returns an error if twofishCipher.BlockSize != 16.
    89  	aead, _ := cipher.NewGCM(key.NewCipher())
    90  
    91  	// Check for a nonce.
    92  	if len(ct) < aead.NonceSize() {
    93  		return nil, ErrInsufficientLen
    94  	}
    95  
    96  	// Decrypt the data.
    97  	nonce := ct[:aead.NonceSize()]
    98  	ciphertext := ct[aead.NonceSize():]
    99  	return aead.Open(ciphertext[:0], nonce, ciphertext, nil)
   100  }
   101  
   102  // NewWriter returns a writer that encrypts or decrypts its input stream.
   103  func (key TwofishKey) NewWriter(w io.Writer) io.Writer {
   104  	// OK to use a zero IV if the key is unique for each ciphertext.
   105  	iv := make([]byte, twofish.BlockSize)
   106  	stream := cipher.NewOFB(key.NewCipher(), iv)
   107  
   108  	return &cipher.StreamWriter{S: stream, W: w}
   109  }
   110  
   111  // NewReader returns a reader that encrypts or decrypts its input stream.
   112  func (key TwofishKey) NewReader(r io.Reader) io.Reader {
   113  	// OK to use a zero IV if the key is unique for each ciphertext.
   114  	iv := make([]byte, twofish.BlockSize)
   115  	stream := cipher.NewOFB(key.NewCipher(), iv)
   116  
   117  	return &cipher.StreamReader{S: stream, R: r}
   118  }
   119  
   120  // MarshalJSON returns the JSON encoding of a CipherText
   121  func (c Ciphertext) MarshalJSON() ([]byte, error) {
   122  	return json.Marshal([]byte(c))
   123  }
   124  
   125  // UnmarshalJSON parses the JSON-encoded b and returns an instance of
   126  // CipherText.
   127  func (c *Ciphertext) UnmarshalJSON(b []byte) error {
   128  	var umarB []byte
   129  	err := json.Unmarshal(b, &umarB)
   130  	if err != nil {
   131  		return err
   132  	}
   133  	*c = Ciphertext(umarB)
   134  	return nil
   135  }