github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/attachments/crypt.go (about)

     1  package attachments
     2  
     3  import (
     4  	"crypto/rand"
     5  	"errors"
     6  	"io"
     7  
     8  	"github.com/keybase/client/go/chat/signencrypt"
     9  	"github.com/keybase/client/go/kbcrypto"
    10  	"github.com/keybase/client/go/libkb"
    11  	"github.com/keybase/go-crypto/ed25519"
    12  )
    13  
    14  type Encrypter interface {
    15  	// EncryptedLen returns the number of bytes that the ciphertext of
    16  	// size plaintext bytes will be.
    17  	EncryptedLen(size int) int
    18  
    19  	// Encrypt takes a plaintext reader and returns a ciphertext reader.
    20  	// It generates new keys every time it is called and uses a
    21  	// constant nonce.
    22  	Encrypt(plaintext io.Reader) (ciphertext io.Reader, err error)
    23  
    24  	// EncryptWithNonce takes a plaintext reader and returns a ciphertext reader.
    25  	// It generates new keys every time it is called and uses
    26  	// the provided nonce.
    27  	EncryptWithNonce(plaintext io.Reader, nonce signencrypt.Nonce) (ciphertext io.Reader, err error)
    28  
    29  	// EncryptResume takes a plaintext reader and a set of keys.  It
    30  	// returns a ciphertext reader.  It *does not* generate new keys
    31  	// but uses the parameter keys.  These keys should *only* be used
    32  	// to encrypt the same plaintext as a previous attempt.
    33  	EncryptResume(r io.Reader, nonce signencrypt.Nonce, encKey signencrypt.SecretboxKey, signKey signencrypt.SignKey, verifyKey signencrypt.VerifyKey) (io.Reader, error)
    34  
    35  	// EncryptKey returns the ephemeral key that was used during the
    36  	// last invocation of Encrypt.
    37  	EncryptKey() []byte
    38  
    39  	// VerifyKey returns the public portion of the signing key used during
    40  	// the last invocation of Encrypt.  It can be used for signature
    41  	// verification.
    42  	VerifyKey() []byte
    43  }
    44  
    45  type Decrypter interface {
    46  	// Decrypt takes a ciphertext reader, encryption and verify keys.
    47  	// It returns a plaintext reader.  It uses the constant nonce.
    48  	Decrypt(ciphertext io.Reader, encKey, verifyKey []byte) (plaintext io.Reader)
    49  
    50  	// DecryptWithNonce takes a ciphertext reader, nonce, encryption and verify keys.
    51  	// It returns a plaintext reader.
    52  	DecryptWithNonce(ciphertext io.Reader, nonce signencrypt.Nonce, encKey, verifyKey []byte) (plaintext io.Reader)
    53  }
    54  
    55  // The ASCII bytes "kbchatattachment".
    56  var nonceConst signencrypt.Nonce = &[16]byte{0x6b, 0x62, 0x63, 0x68, 0x61, 0x74, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74}
    57  
    58  type SignEncrypter struct {
    59  	encKey    signencrypt.SecretboxKey
    60  	signKey   signencrypt.SignKey
    61  	verifyKey signencrypt.VerifyKey
    62  }
    63  
    64  func NewSignEncrypter() *SignEncrypter {
    65  	return &SignEncrypter{}
    66  }
    67  
    68  func (s *SignEncrypter) EncryptedLen(size int64) int64 {
    69  	return signencrypt.GetSealedSize(size)
    70  }
    71  
    72  func (s *SignEncrypter) Encrypt(r io.Reader) (io.Reader, error) {
    73  	// It is *very* important that Encrypt calls makeKeys() to make
    74  	// new keys every time it runs.  The keys it uses cannot be reused
    75  	// since we are using a constant nonce.
    76  	if err := s.makeKeys(); err != nil {
    77  		return nil, err
    78  	}
    79  	return signencrypt.NewEncodingReader(s.encKey, s.signKey, kbcrypto.SignaturePrefixChatAttachment, nonceConst, r), nil
    80  }
    81  
    82  func (s *SignEncrypter) EncryptWithNonce(r io.Reader, nonce signencrypt.Nonce) (io.Reader, error) {
    83  	if err := s.makeKeys(); err != nil {
    84  		return nil, err
    85  	}
    86  	return signencrypt.NewEncodingReader(s.encKey, s.signKey, kbcrypto.SignaturePrefixChatAttachment, nonce, r), nil
    87  }
    88  
    89  // EncryptResume is used to create a SignEncrypter to resume an interrupted attachment upload.
    90  // It is *very* important that the keys passed in are not used to encrypt different plaintext
    91  // than their original usage.
    92  func (s *SignEncrypter) EncryptResume(r io.Reader, nonce signencrypt.Nonce, encKey signencrypt.SecretboxKey, signKey signencrypt.SignKey, verifyKey signencrypt.VerifyKey) (io.Reader, error) {
    93  	s.encKey = encKey
    94  	s.signKey = signKey
    95  	s.verifyKey = verifyKey
    96  	return signencrypt.NewEncodingReader(s.encKey, s.signKey, kbcrypto.SignaturePrefixChatAttachment, nonce, r), nil
    97  }
    98  
    99  func (s *SignEncrypter) EncryptKey() []byte {
   100  	return (*s.encKey)[:]
   101  }
   102  
   103  func (s *SignEncrypter) SignKey() []byte {
   104  	return (*s.signKey)[:]
   105  }
   106  
   107  func (s *SignEncrypter) VerifyKey() []byte {
   108  	return (*s.verifyKey)[:]
   109  }
   110  
   111  func (s *SignEncrypter) makeKeys() error {
   112  	var encKey [signencrypt.SecretboxKeySize]byte
   113  	n, err := rand.Read(encKey[:])
   114  	if err != nil {
   115  		return err
   116  	}
   117  	if n != signencrypt.SecretboxKeySize {
   118  		return errors.New("failed to rand.Read the correct number of bytes")
   119  	}
   120  
   121  	sign, err := libkb.GenerateNaclSigningKeyPair()
   122  	if err != nil {
   123  		return err
   124  	}
   125  
   126  	var signKey [ed25519.PrivateKeySize]byte
   127  	copy(signKey[:], (*sign.Private)[:])
   128  	var verifyKey [ed25519.PublicKeySize]byte
   129  	copy(verifyKey[:], sign.Public[:])
   130  
   131  	s.encKey = &encKey
   132  	s.signKey = &signKey
   133  	s.verifyKey = &verifyKey
   134  
   135  	return nil
   136  }
   137  
   138  type SignDecrypter struct{}
   139  
   140  func NewSignDecrypter() *SignDecrypter {
   141  	return &SignDecrypter{}
   142  }
   143  
   144  func (s *SignDecrypter) Decrypt(r io.Reader, encKey, verifyKey []byte) io.Reader {
   145  	var xencKey [signencrypt.SecretboxKeySize]byte
   146  	copy(xencKey[:], encKey)
   147  	var xverifyKey [ed25519.PublicKeySize]byte
   148  	copy(xverifyKey[:], verifyKey)
   149  	return signencrypt.NewDecodingReader(&xencKey, &xverifyKey, kbcrypto.SignaturePrefixChatAttachment, nonceConst, r)
   150  }
   151  
   152  func (s *SignDecrypter) DecryptWithNonce(r io.Reader, nonce signencrypt.Nonce, encKey, verifyKey []byte) (plaintext io.Reader) {
   153  	var xencKey [signencrypt.SecretboxKeySize]byte
   154  	copy(xencKey[:], encKey)
   155  	var xverifyKey [ed25519.PublicKeySize]byte
   156  	copy(xverifyKey[:], verifyKey)
   157  	return signencrypt.NewDecodingReader(&xencKey, &xverifyKey, kbcrypto.SignaturePrefixChatAttachment, nonce, r)
   158  }