github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/saltpack.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 libkb 5 6 import ( 7 "bytes" 8 "fmt" 9 10 "github.com/keybase/client/go/kbcrypto" 11 keybase1 "github.com/keybase/client/go/protocol/keybase1" 12 "github.com/keybase/saltpack" 13 "golang.org/x/crypto/ed25519" 14 "golang.org/x/crypto/nacl/box" 15 ) 16 17 // Wrap types from naclwrap.go in saltpack interfaces. 18 19 type naclBoxPublicKey NaclDHKeyPublic 20 21 var _ saltpack.BoxPublicKey = naclBoxPublicKey{} 22 23 func (b naclBoxPublicKey) ToKID() []byte { 24 return b[:] 25 } 26 27 func (b naclBoxPublicKey) ToRawBoxKeyPointer() *saltpack.RawBoxKey { 28 return (*saltpack.RawBoxKey)(&b) 29 } 30 31 func (b naclBoxPublicKey) CreateEphemeralKey() (saltpack.BoxSecretKey, error) { 32 kp, err := GenerateNaclDHKeyPair() 33 if err != nil { 34 return nil, err 35 } 36 37 return naclBoxSecretKey(kp), nil 38 } 39 40 func (b naclBoxPublicKey) HideIdentity() bool { 41 return false 42 } 43 44 type hiddenNaclBoxPublicKey NaclDHKeyPublic 45 46 func (b hiddenNaclBoxPublicKey) ToKID() []byte { 47 return b[:] 48 } 49 50 func (b hiddenNaclBoxPublicKey) ToRawBoxKeyPointer() *saltpack.RawBoxKey { 51 return (*saltpack.RawBoxKey)(&b) 52 } 53 54 func (b hiddenNaclBoxPublicKey) CreateEphemeralKey() (saltpack.BoxSecretKey, error) { 55 kp, err := GenerateNaclDHKeyPair() 56 if err != nil { 57 return nil, err 58 } 59 60 return naclBoxSecretKey(kp), nil 61 } 62 63 func (b hiddenNaclBoxPublicKey) HideIdentity() bool { 64 return true 65 } 66 67 type naclBoxPrecomputedSharedKey [32]byte 68 69 var _ saltpack.BoxPrecomputedSharedKey = naclBoxPrecomputedSharedKey{} 70 71 func (k naclBoxPrecomputedSharedKey) Unbox(nonce saltpack.Nonce, msg []byte) ( 72 []byte, error) { 73 ret, ok := box.OpenAfterPrecomputation( 74 []byte{}, msg, (*[24]byte)(&nonce), (*[32]byte)(&k)) 75 if !ok { 76 return nil, DecryptionError{} 77 } 78 return ret, nil 79 } 80 81 func (k naclBoxPrecomputedSharedKey) Box(nonce saltpack.Nonce, msg []byte) []byte { 82 ret := box.SealAfterPrecomputation([]byte{}, msg, (*[24]byte)(&nonce), (*[32]byte)(&k)) 83 return ret 84 } 85 86 type naclBoxSecretKey NaclDHKeyPair 87 88 var _ saltpack.BoxSecretKey = naclBoxSecretKey{} 89 90 func (n naclBoxSecretKey) Box( 91 receiver saltpack.BoxPublicKey, nonce saltpack.Nonce, msg []byte) []byte { 92 ret := box.Seal([]byte{}, msg, (*[24]byte)(&nonce), 93 (*[32]byte)(receiver.ToRawBoxKeyPointer()), 94 (*[32]byte)(n.Private)) 95 return ret 96 } 97 98 func (n naclBoxSecretKey) Unbox( 99 sender saltpack.BoxPublicKey, nonce saltpack.Nonce, msg []byte) ( 100 []byte, error) { 101 ret, ok := box.Open([]byte{}, msg, (*[24]byte)(&nonce), 102 (*[32]byte)(sender.ToRawBoxKeyPointer()), 103 (*[32]byte)(n.Private)) 104 if !ok { 105 return nil, DecryptionError{} 106 } 107 return ret, nil 108 } 109 110 func (n naclBoxSecretKey) GetPublicKey() saltpack.BoxPublicKey { 111 return naclBoxPublicKey(n.Public) 112 } 113 114 func (n naclBoxSecretKey) Precompute( 115 sender saltpack.BoxPublicKey) saltpack.BoxPrecomputedSharedKey { 116 var res naclBoxPrecomputedSharedKey 117 box.Precompute((*[32]byte)(&res), 118 (*[32]byte)(sender.ToRawBoxKeyPointer()), 119 (*[32]byte)(n.Private)) 120 return res 121 } 122 123 // A secret key also functions as a keyring with a single key. 124 type naclKeyring naclBoxSecretKey 125 126 var _ saltpack.Keyring = naclKeyring{} 127 128 func (n naclKeyring) LookupBoxSecretKey( 129 kids [][]byte) (int, saltpack.BoxSecretKey) { 130 sk := (naclBoxSecretKey)(n) 131 pkKid := sk.GetPublicKey().ToKID() 132 for i, kid := range kids { 133 if bytes.Equal(pkKid, kid) { 134 return i, sk 135 } 136 } 137 138 return -1, nil 139 } 140 141 func (n naclKeyring) LookupBoxPublicKey(kid []byte) saltpack.BoxPublicKey { 142 var pk naclBoxPublicKey 143 if len(kid) != len(pk) { 144 return nil 145 } 146 copy(pk[:], kid) 147 return pk 148 } 149 150 func (n naclKeyring) GetAllBoxSecretKeys() []saltpack.BoxSecretKey { 151 return []saltpack.BoxSecretKey{naclBoxSecretKey(n)} 152 } 153 154 func (n naclKeyring) ImportBoxEphemeralKey(kid []byte) saltpack.BoxPublicKey { 155 return n.LookupBoxPublicKey(kid) 156 } 157 158 func (n naclKeyring) CreateEphemeralKey() (saltpack.BoxSecretKey, error) { 159 kp, err := GenerateNaclDHKeyPair() 160 if err != nil { 161 return nil, err 162 } 163 164 return naclBoxSecretKey(kp), nil 165 } 166 167 func (n naclKeyring) LookupSigningPublicKey(kid []byte) saltpack.SigningPublicKey { 168 if len(kid) != ed25519.PublicKeySize { 169 return nil 170 } 171 keyBytes := [ed25519.PublicKeySize]byte{} 172 copy(keyBytes[:], kid) 173 return saltSignerPublic{kbcrypto.NaclSigningKeyPublic(keyBytes)} 174 } 175 176 // An empty keyring just for generating ephemeral keys. 177 type emptyKeyring struct{} 178 179 var _ saltpack.Keyring = emptyKeyring{} 180 181 func (e emptyKeyring) LookupBoxSecretKey(kids [][]byte) (int, saltpack.BoxSecretKey) { 182 panic("unimplemented") 183 } 184 185 func (e emptyKeyring) LookupBoxPublicKey(kid []byte) saltpack.BoxPublicKey { 186 panic("unimplemented") 187 } 188 189 func (e emptyKeyring) GetAllBoxSecretKeys() []saltpack.BoxSecretKey { 190 panic("unimplemented") 191 } 192 193 func (e emptyKeyring) ImportBoxEphemeralKey(kid []byte) saltpack.BoxPublicKey { 194 panic("unimplemented") 195 } 196 197 func (e emptyKeyring) CreateEphemeralKey() (saltpack.BoxSecretKey, error) { 198 kp, err := GenerateNaclDHKeyPair() 199 if err != nil { 200 return nil, err 201 } 202 203 return naclBoxSecretKey(kp), nil 204 } 205 206 func BoxPublicKeyToKeybaseKID(k saltpack.BoxPublicKey) (ret keybase1.KID) { 207 if k == nil { 208 return ret 209 } 210 p := k.ToKID() 211 return keybase1.KIDFromRawKey(p, byte(kbcrypto.KIDNaclDH)) 212 } 213 214 func checkSaltpackBrand(b string) error { 215 // Everything is awesome! 216 return nil 217 } 218 219 func SaltpackVersionFromArg(saltpackVersionArg int) (saltpack.Version, error) { 220 if saltpackVersionArg == 0 { 221 return CurrentSaltpackVersion(), nil 222 } 223 224 // The arg specifies the major version we want, and the minor version is 225 // assumed to be the latest available. Make a map to accomplish that. 226 majorVersionMap := map[int]saltpack.Version{} 227 for _, v := range saltpack.KnownVersions() { 228 latestPair, found := majorVersionMap[v.Major] 229 if !found || (v.Minor > latestPair.Minor) { 230 majorVersionMap[v.Major] = v 231 } 232 } 233 234 ret, found := majorVersionMap[saltpackVersionArg] 235 if !found { 236 return saltpack.Version{}, fmt.Errorf("failed to find saltpack major version %d", saltpackVersionArg) 237 } 238 return ret, nil 239 }