github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/kbfscrypto/signature.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package kbfscrypto 6 7 import ( 8 "bytes" 9 "encoding" 10 "encoding/hex" 11 "encoding/json" 12 "fmt" 13 14 "github.com/keybase/client/go/kbcrypto" 15 "github.com/keybase/client/go/libkb" 16 "github.com/keybase/client/go/protocol/keybase1" 17 "github.com/pkg/errors" 18 19 "golang.org/x/net/context" 20 ) 21 22 // SigVer denotes a signature version. 23 type SigVer int 24 25 const ( 26 // SigED25519 is the signature type for ED25519 27 SigED25519 = SigVer(iota + 1) 28 // SigED25519ForKBFS is the signature type for ED25519 with a KBFS prefix. 29 SigED25519ForKBFS 30 ) 31 32 // IsNil returns true if this SigVer is nil. 33 func (v SigVer) IsNil() bool { 34 return int(v) == 0 35 } 36 37 // SignatureInfo contains all the info needed to verify a signature 38 // for a message. 39 type SignatureInfo struct { 40 // Exported only for serialization purposes. 41 Version SigVer `codec:"v"` 42 Signature []byte `codec:"s"` 43 VerifyingKey VerifyingKey `codec:"k"` 44 } 45 46 // IsNil returns true if this SignatureInfo is nil. 47 func (s SignatureInfo) IsNil() bool { 48 return s.Version.IsNil() && len(s.Signature) == 0 && s.VerifyingKey.IsNil() 49 } 50 51 // Equals returns true if this SignatureInfo matches the given one. 52 func (s SignatureInfo) Equals(other SignatureInfo) bool { 53 if s.Version != other.Version { 54 return false 55 } 56 if !bytes.Equal(s.Signature, other.Signature) { 57 return false 58 } 59 if s.VerifyingKey != other.VerifyingKey { 60 return false 61 } 62 63 return true 64 } 65 66 // DeepCopy makes a complete copy of this SignatureInfo. 67 func (s SignatureInfo) DeepCopy() SignatureInfo { 68 signature := make([]byte, len(s.Signature)) 69 copy(signature, s.Signature) 70 return SignatureInfo{s.Version, signature, s.VerifyingKey} 71 } 72 73 // String implements the fmt.Stringer interface for SignatureInfo. 74 func (s SignatureInfo) String() string { 75 return fmt.Sprintf("SignatureInfo{Version: %d, Signature: %s, "+ 76 "VerifyingKey: %s}", s.Version, hex.EncodeToString(s.Signature), 77 &s.VerifyingKey) 78 } 79 80 // SigningKey is a key pair for signing. 81 type SigningKey struct { 82 kp libkb.NaclSigningKeyPair 83 } 84 85 // NewSigningKey returns a SigningKey using the given key pair. 86 func NewSigningKey(kp libkb.NaclSigningKeyPair) SigningKey { 87 return SigningKey{kp} 88 } 89 90 // Sign signs the given data and returns a SignatureInfo. 91 func (k SigningKey) Sign(data []byte) SignatureInfo { 92 sig := k.kp.Private.Sign(data) 93 return SignatureInfo{ 94 Version: SigED25519, 95 Signature: sig[:], 96 VerifyingKey: k.GetVerifyingKey(), 97 } 98 } 99 100 // SignForKBFS signs the given data with the KBFS prefix and returns a SignatureInfo. 101 func (k SigningKey) SignForKBFS(data []byte) (SignatureInfo, error) { 102 sigInfo, err := k.kp.SignV2(data, kbcrypto.SignaturePrefixKBFS) 103 if err != nil { 104 return SignatureInfo{}, errors.WithStack(err) 105 } 106 return SignatureInfo{ 107 Version: SigVer(sigInfo.Version), 108 Signature: sigInfo.Sig[:], 109 VerifyingKey: k.GetVerifyingKey(), 110 }, nil 111 } 112 113 // SignToString signs the given data and returns a string. 114 func (k SigningKey) SignToString(data []byte) (sig string, err error) { 115 sig, _, err = k.kp.SignToString(data) 116 if err != nil { 117 return "", errors.WithStack(err) 118 } 119 return sig, nil 120 } 121 122 // GetVerifyingKey returns the public key half of this signing key. 123 func (k SigningKey) GetVerifyingKey() VerifyingKey { 124 return MakeVerifyingKey(k.kp.Public.GetKID()) 125 } 126 127 // A VerifyingKey is a public key that can be used to verify a 128 // signature created by the corresponding private signing key. In 129 // particular, VerifyingKeys are used to authenticate home and public 130 // TLFs. (See 4.2, 4.3.) 131 // 132 // These are also sometimes known as sibkeys. 133 // 134 // Copies of VerifyingKey objects are deep copies. 135 type VerifyingKey struct { 136 // Even though we currently use NaclSignatures, we use a KID 137 // here (which encodes the key type) as we may end up storing 138 // other kinds of signatures. 139 kidContainer 140 } 141 142 var _ encoding.BinaryMarshaler = VerifyingKey{} 143 var _ encoding.BinaryUnmarshaler = (*VerifyingKey)(nil) 144 145 var _ json.Marshaler = VerifyingKey{} 146 var _ json.Unmarshaler = (*VerifyingKey)(nil) 147 148 // MakeVerifyingKey returns a VerifyingKey containing the given KID. 149 func MakeVerifyingKey(kid keybase1.KID) VerifyingKey { 150 return VerifyingKey{kidContainer{kid}} 151 } 152 153 // IsNil returns true if the VerifyingKey is nil. 154 func (k VerifyingKey) IsNil() bool { 155 return k.kid.IsNil() 156 } 157 158 // Verify verifies the given message against the given SignatureInfo, 159 // and returns nil if it verifies successfully, or an error otherwise. 160 func Verify(msg []byte, sigInfo SignatureInfo) error { 161 if sigInfo.Version < SigED25519 || sigInfo.Version > SigED25519ForKBFS { 162 return errors.WithStack(UnknownSigVer{sigInfo.Version}) 163 } 164 165 publicKey := kbcrypto.KIDToNaclSigningKeyPublic( 166 sigInfo.VerifyingKey.KID().ToBytes()) 167 if publicKey == nil { 168 return errors.WithStack(libkb.KeyCannotVerifyError{}) 169 } 170 171 var naclSignature kbcrypto.NaclSignature 172 if len(sigInfo.Signature) != len(naclSignature) { 173 return errors.WithStack(kbcrypto.VerificationError{}) 174 } 175 copy(naclSignature[:], sigInfo.Signature) 176 177 if sigInfo.Version == SigED25519ForKBFS { 178 msg = kbcrypto.SignaturePrefixKBFS.Prefix(msg) 179 } 180 181 if !publicKey.Verify(msg, naclSignature) { 182 return errors.WithStack(kbcrypto.VerificationError{}) 183 } 184 185 return nil 186 } 187 188 // A Signer is something that can sign using an internal private key. 189 type Signer interface { 190 // Sign signs msg with some internal private key. 191 Sign(ctx context.Context, msg []byte) (sigInfo SignatureInfo, err error) 192 // SignForKBFS signs msg with some internal private key on behalf of KBFS. 193 SignForKBFS(ctx context.Context, msg []byte) (sigInfo SignatureInfo, err error) 194 // SignToString signs msg with some internal private key and 195 // outputs the full serialized NaclSigInfo. 196 SignToString(ctx context.Context, msg []byte) (signature string, err error) 197 } 198 199 // SigningKeySigner is a Signer wrapper around a SigningKey. 200 type SigningKeySigner struct { 201 Key SigningKey 202 } 203 204 // Sign implements Signer for SigningKeySigner. 205 func (s SigningKeySigner) Sign( 206 ctx context.Context, data []byte) (SignatureInfo, error) { 207 return s.Key.Sign(data), nil 208 } 209 210 // SignForKBFS implements Signer for SigningKeySigner. 211 func (s SigningKeySigner) SignForKBFS( 212 ctx context.Context, data []byte) (SignatureInfo, error) { 213 return s.Key.SignForKBFS(data) 214 } 215 216 // SignToString implements Signer for SigningKeySigner. 217 func (s SigningKeySigner) SignToString( 218 ctx context.Context, data []byte) (sig string, err error) { 219 return s.Key.SignToString(data) 220 }