github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/sign.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  	"crypto/sha256"
     9  	"hash"
    10  	"io"
    11  
    12  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    13  	"github.com/keybase/go-crypto/openpgp"
    14  	"github.com/keybase/go-crypto/openpgp/armor"
    15  	"github.com/keybase/go-crypto/openpgp/packet"
    16  )
    17  
    18  // SimpleSign signs the given data stream, outputs an armored string which is
    19  // the attached signature of the input data
    20  func SimpleSign(payload []byte, key PGPKeyBundle) (out string, id keybase1.SigIDBase, err error) {
    21  	var outb bytes.Buffer
    22  	var in io.WriteCloser
    23  	var h HashSummer
    24  	if !key.HasSecretKey() {
    25  		err = NoSecretKeyError{}
    26  		return
    27  	}
    28  	if in, h, err = ArmoredAttachedSign(NopWriteCloser{&outb}, *key.Entity, nil, nil); err != nil {
    29  		return
    30  	}
    31  	if _, err = in.Write(payload); err != nil {
    32  		return
    33  	}
    34  	if err = in.Close(); err != nil {
    35  		return
    36  	}
    37  	out = outb.String()
    38  	if id, err = keybase1.SigIDBaseFromSlice(h()); err != nil {
    39  		return
    40  	}
    41  	return
    42  }
    43  
    44  type HashingWriteCloser struct {
    45  	targ   io.WriteCloser
    46  	hasher hash.Hash
    47  }
    48  
    49  func (h HashingWriteCloser) Write(buf []byte) (int, error) {
    50  	n, err := h.targ.Write(buf)
    51  	if err == nil {
    52  		_, err = h.hasher.Write(buf)
    53  	}
    54  	return n, err
    55  }
    56  
    57  func (h HashingWriteCloser) Close() error {
    58  	err := h.targ.Close()
    59  	return err
    60  }
    61  
    62  type HashSummer func() []byte
    63  
    64  func ArmoredAttachedSign(out io.WriteCloser, signed openpgp.Entity, hints *openpgp.FileHints, config *packet.Config) (in io.WriteCloser, h HashSummer, err error) {
    65  
    66  	var aout io.WriteCloser
    67  
    68  	aout, err = armor.Encode(out, "PGP MESSAGE", PGPArmorHeaders)
    69  	if err != nil {
    70  		return
    71  	}
    72  
    73  	hwc := HashingWriteCloser{aout, sha256.New()}
    74  	in, err = openpgp.AttachedSign(hwc, signed, hints, config)
    75  	h = func() []byte { return hwc.hasher.Sum(nil) }
    76  
    77  	return in, h, err
    78  }
    79  
    80  func AttachedSignWrapper(out io.WriteCloser, key PGPKeyBundle, armored bool) (
    81  	in io.WriteCloser, err error) {
    82  
    83  	if armored {
    84  		in, _, err = ArmoredAttachedSign(out, *key.Entity, nil, nil)
    85  	} else {
    86  		in, err = openpgp.AttachedSign(out, *key.Entity, nil, nil)
    87  	}
    88  	return
    89  }
    90  
    91  // NopWriteCloser is like an io.NopCloser, but for an io.Writer.
    92  // TODO: we have two of these in OpenPGP packages alone. This probably needs
    93  // to be promoted somewhere more common.
    94  //
    95  // From here:
    96  //
    97  //	https://code.google.com/p/go/source/browse/openpgp/write.go?repo=crypto&r=1e7a3e301825bf9cb32e0535f3761d62d2d369d1#364
    98  type NopWriteCloser struct {
    99  	W io.Writer
   100  }
   101  
   102  func (c NopWriteCloser) Write(data []byte) (n int, err error) {
   103  	return c.W.Write(data)
   104  }
   105  
   106  func (c NopWriteCloser) Close() error {
   107  	return nil
   108  }