github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/saltpack_encrypt.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package engine 5 6 import ( 7 "fmt" 8 "io" 9 10 "github.com/keybase/client/go/libkb" 11 keybase1 "github.com/keybase/client/go/protocol/keybase1" 12 "github.com/keybase/saltpack" 13 ) 14 15 type SaltpackEncryptArg struct { 16 Opts keybase1.SaltpackEncryptOptions 17 Source io.Reader 18 Sink io.WriteCloser 19 } 20 21 // SaltpackEncrypt encrypts data read from a source into a sink 22 // for a set of users. It will track them if necessary. 23 type SaltpackEncrypt struct { 24 arg *SaltpackEncryptArg 25 me keybase1.UID 26 27 newKeyfinderHook (func(arg libkb.SaltpackRecipientKeyfinderArg) libkb.SaltpackRecipientKeyfinderEngineInterface) 28 29 // keep track if an SBS recipient was used so callers can tell the user 30 UsedSBS bool 31 SBSAssertion string 32 33 // Legacy encryption-only messages include a lot more information about 34 // receivers, and it's nice to keep the helpful errors working while those 35 // messages are still around. 36 visibleRecipientsForTesting bool 37 } 38 39 // NewSaltpackEncrypt creates a SaltpackEncrypt engine. 40 func NewSaltpackEncrypt(arg *SaltpackEncryptArg, newKeyfinderHook func(arg libkb.SaltpackRecipientKeyfinderArg) libkb.SaltpackRecipientKeyfinderEngineInterface) *SaltpackEncrypt { 41 return &SaltpackEncrypt{ 42 arg: arg, 43 newKeyfinderHook: newKeyfinderHook, 44 } 45 } 46 47 // Name is the unique engine name. 48 func (e *SaltpackEncrypt) Name() string { 49 return "SaltpackEncrypt" 50 } 51 52 // Prereqs returns the engine prereqs. 53 func (e *SaltpackEncrypt) Prereqs() Prereqs { 54 return Prereqs{} 55 } 56 57 // RequiredUIs returns the required UIs. 58 func (e *SaltpackEncrypt) RequiredUIs() []libkb.UIKind { 59 return []libkb.UIKind{ 60 libkb.SecretUIKind, 61 } 62 } 63 64 // SubConsumers returns the other UI consumers for this engine. 65 func (e *SaltpackEncrypt) SubConsumers() []libkb.UIConsumer { 66 // Note that potentially KeyfinderHook might return a different UIConsumer depending on its arguments, 67 // which might make this call problematic, but all the hooks currently in use are not doing that. 68 return []libkb.UIConsumer{ 69 e.newKeyfinderHook(libkb.SaltpackRecipientKeyfinderArg{}), 70 } 71 } 72 73 func (e *SaltpackEncrypt) loadMe(m libkb.MetaContext) error { 74 loggedIn, uid, err := isLoggedInWithUIDAndError(m) 75 if err != nil && !e.arg.Opts.NoSelfEncrypt { 76 return err 77 } 78 if !loggedIn { 79 return nil 80 } 81 e.me = uid 82 return nil 83 } 84 85 // Run starts the engine. 86 func (e *SaltpackEncrypt) Run(m libkb.MetaContext) (err error) { 87 defer m.Trace("SaltpackEncrypt::Run", &err)() 88 89 if err = e.loadMe(m); err != nil { 90 return err 91 } 92 93 if !(e.arg.Opts.UseEntityKeys || e.arg.Opts.UseDeviceKeys || e.arg.Opts.UsePaperKeys || e.arg.Opts.UseKBFSKeysOnlyForTesting) { 94 return fmt.Errorf("no key type for encryption was specified") 95 } 96 97 kfarg := libkb.SaltpackRecipientKeyfinderArg{ 98 Recipients: e.arg.Opts.Recipients, 99 TeamRecipients: e.arg.Opts.TeamRecipients, 100 NoSelfEncrypt: e.arg.Opts.NoSelfEncrypt, 101 UseEntityKeys: e.arg.Opts.UseEntityKeys, 102 UsePaperKeys: e.arg.Opts.UsePaperKeys, 103 UseDeviceKeys: e.arg.Opts.UseDeviceKeys, 104 UseRepudiableAuth: e.arg.Opts.AuthenticityType == keybase1.AuthenticityType_REPUDIABLE, 105 NoForcePoll: e.arg.Opts.NoForcePoll, 106 } 107 108 kf := e.newKeyfinderHook(kfarg) 109 if err := RunEngine2(m, kf); err != nil { 110 return err 111 } 112 113 var receivers []libkb.NaclDHKeyPublic 114 for _, KID := range kf.GetPublicKIDs() { 115 gk, err := libkb.ImportKeypairFromKID(KID) 116 if err != nil { 117 return err 118 } 119 kp, ok := gk.(libkb.NaclDHKeyPair) 120 if !ok { 121 return libkb.KeyCannotEncryptError{} 122 } 123 receivers = append(receivers, kp.Public) 124 } 125 126 var symmetricReceivers []saltpack.ReceiverSymmetricKey 127 for _, key := range kf.GetSymmetricKeys() { 128 symmetricReceivers = append(symmetricReceivers, saltpack.ReceiverSymmetricKey{ 129 Key: saltpack.SymmetricKey(key.Key), 130 Identifier: key.Identifier, 131 }) 132 } 133 134 e.UsedSBS, e.SBSAssertion = kf.UsedUnresolvedSBSAssertion() 135 136 if e.UsedSBS { 137 actx := m.G().MakeAssertionContext(m) 138 expr, err := libkb.AssertionParse(actx, e.SBSAssertion) 139 if err == nil { 140 social, err := expr.ToSocialAssertion() 141 if err == nil && social.Service == "email" { 142 // email assertions are pretty ugly, so just return 143 // the "User" part for easier handling upstream. 144 e.SBSAssertion = social.User 145 } 146 } 147 } 148 149 // This flag determines whether saltpack is used in signcryption (false) 150 // vs encryption (true) format. 151 encryptionOnlyMode := false 152 153 var senderDH libkb.NaclDHKeyPair 154 if e.arg.Opts.AuthenticityType == keybase1.AuthenticityType_REPUDIABLE && !e.me.IsNil() { 155 encryptionOnlyMode = true 156 dhKey, err := m.G().ActiveDevice.EncryptionKeyWithUID(e.me) 157 if err != nil { 158 return err 159 } 160 dhKeypair, ok := dhKey.(libkb.NaclDHKeyPair) 161 if !ok || dhKeypair.Private == nil { 162 return libkb.KeyCannotEncryptError{} 163 } 164 senderDH = dhKeypair 165 } 166 167 var senderSigning libkb.NaclSigningKeyPair 168 if e.arg.Opts.AuthenticityType == keybase1.AuthenticityType_SIGNED && !e.me.IsNil() { 169 signingKey, err := m.G().ActiveDevice.SigningKeyWithUID(e.me) 170 if err != nil { 171 return err 172 } 173 signingKeypair, ok := signingKey.(libkb.NaclSigningKeyPair) 174 if !ok || signingKeypair.Private == nil { 175 // Perhaps a KeyCannotEncrypt error, although less accurate, would be more intuitive for the user. 176 return libkb.KeyCannotSignError{} 177 } 178 senderSigning = signingKeypair 179 } 180 181 if e.arg.Opts.AuthenticityType != keybase1.AuthenticityType_ANONYMOUS && e.me.IsNil() { 182 return libkb.NewLoginRequiredError("authenticating a message requires login. Either login or use --auth-type=anonymous") 183 } 184 185 saltpackVersion, err := libkb.SaltpackVersionFromArg(e.arg.Opts.SaltpackVersion) 186 if err != nil { 187 return err 188 } 189 190 encarg := libkb.SaltpackEncryptArg{ 191 Source: e.arg.Source, 192 Sink: e.arg.Sink, 193 Receivers: receivers, 194 Sender: senderDH, 195 SenderSigning: senderSigning, 196 Binary: e.arg.Opts.Binary, 197 EncryptionOnlyMode: encryptionOnlyMode, 198 SymmetricReceivers: symmetricReceivers, 199 SaltpackVersion: saltpackVersion, 200 201 VisibleRecipientsForTesting: e.visibleRecipientsForTesting, 202 } 203 return libkb.SaltpackEncrypt(m, &encarg) 204 }