1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package libkb
5
6import (
7	"errors"
8	"io"
9
10	"github.com/keybase/saltpack"
11)
12
13type SaltpackEncryptArg struct {
14	Source             io.Reader
15	Sink               io.WriteCloser
16	Receivers          []NaclDHKeyPublic
17	Sender             NaclDHKeyPair
18	SenderSigning      NaclSigningKeyPair
19	Binary             bool
20	EncryptionOnlyMode bool
21	SymmetricReceivers []saltpack.ReceiverSymmetricKey
22	SaltpackVersion    saltpack.Version
23
24	VisibleRecipientsForTesting bool
25}
26
27// SaltpackEncrypt reads from the given source, encrypts it for the given
28// receivers from the given sender, and writes it to sink.  If
29// Binary is false, the data written to sink will be armored.
30func SaltpackEncrypt(m MetaContext, arg *SaltpackEncryptArg) error {
31	var receiverBoxKeys []saltpack.BoxPublicKey
32	for _, k := range arg.Receivers {
33		// Since signcryption became the default, we never use visible
34		// recipients in encryption mode, except in tests.
35		if arg.VisibleRecipientsForTesting {
36			receiverBoxKeys = append(receiverBoxKeys, naclBoxPublicKey(k))
37		} else {
38			receiverBoxKeys = append(receiverBoxKeys, hiddenNaclBoxPublicKey(k))
39		}
40	}
41
42	var bsk saltpack.BoxSecretKey
43	if !arg.Sender.IsNil() {
44		bsk = naclBoxSecretKey(arg.Sender)
45	}
46
47	// If the version is unspecified, default to the current version.
48	saltpackVersion := arg.SaltpackVersion
49	if saltpackVersion == (saltpack.Version{}) {
50		saltpackVersion = saltpack.CurrentVersion()
51	}
52
53	var plainsink io.WriteCloser
54	var err error
55	if !arg.EncryptionOnlyMode {
56		if arg.SaltpackVersion.Major == 1 {
57			return errors.New("specifying saltpack version 1 requires repudiable authentication")
58		}
59		var signer saltpack.SigningSecretKey
60		if !arg.SenderSigning.IsNil() {
61			signer = saltSigner{arg.SenderSigning}
62		}
63		if arg.Binary {
64			plainsink, err = saltpack.NewSigncryptSealStream(arg.Sink, emptyKeyring{}, signer, receiverBoxKeys, arg.SymmetricReceivers)
65		} else {
66			plainsink, err = saltpack.NewSigncryptArmor62SealStream(arg.Sink, emptyKeyring{}, signer, receiverBoxKeys, arg.SymmetricReceivers, KeybaseSaltpackBrand)
67		}
68	} else {
69		if arg.Binary {
70			plainsink, err = saltpack.NewEncryptStream(saltpackVersion, arg.Sink, bsk, receiverBoxKeys)
71		} else {
72			plainsink, err = saltpack.NewEncryptArmor62Stream(saltpackVersion, arg.Sink, bsk, receiverBoxKeys, KeybaseSaltpackBrand)
73		}
74	}
75	if err != nil {
76		return err
77	}
78
79	n, err := io.Copy(plainsink, arg.Source)
80	if err != nil {
81		return err
82	}
83
84	m.Debug("Encrypt: wrote %d bytes", n)
85
86	if err := plainsink.Close(); err != nil {
87		return err
88	}
89	return arg.Sink.Close()
90}
91