github.com/iDigitalFlame/xmt@v0.5.4/data/crypto.go (about)

     1  // Copyright (C) 2020 - 2023 iDigitalFlame
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  //
    16  
    17  package data
    18  
    19  import (
    20  	"crypto/elliptic"
    21  	"crypto/rand"
    22  	"io"
    23  
    24  	"github.com/iDigitalFlame/xmt/util/xerr"
    25  )
    26  
    27  const (
    28  	sharedKeySize  = 65
    29  	publicKeySize  = 133
    30  	privateKeySize = 66
    31  )
    32  
    33  var keyCurve = elliptic.P521()
    34  
    35  // KeyPair is a ECDH key pair that can be used to generate and manage Public,
    36  // Private and shared keys. The data from this struct can be written and read
    37  // from disk or network.
    38  //
    39  // The empty value can be filled using the 'Fill*' functions.
    40  //
    41  // If not changed via the 'keyCurve' const, this function uses NIST P-521 (FIPS
    42  // 186-3, section D.2.5), known as secp521r1.
    43  //
    44  // Initial ideas and concepts from: https://github.com/wsddn/go-ecdh
    45  type KeyPair struct {
    46  	Public  PublicKey
    47  	Private PrivateKey
    48  	share   SharedKeys
    49  }
    50  
    51  // PublicKey represents a ECDH PublicKey in raw binary format. This alias can be
    52  // used to parse or output to a string value.
    53  type PublicKey [publicKeySize]byte
    54  
    55  // PrivateKey represents a ECDH PrivateKey in raw binary format. This alias can
    56  // be used to parse or output to a string value.
    57  type PrivateKey [privateKeySize]byte
    58  
    59  // SharedKeys represents a ECDH SharedKey in raw binary format. This alias is just
    60  // used to differentate the shared key from other binary structures.
    61  type SharedKeys [sharedKeySize]byte
    62  
    63  // Fill will populate this KeyPair with a randomally generated Public and Private
    64  // key values.
    65  //
    66  // Before returning, this function will zero out the shared secret.
    67  func (k *KeyPair) Fill() {
    68  	// We can ignore the error, since it's only for the read operation.
    69  	var (
    70  		p, x, y, _ = elliptic.GenerateKey(keyCurve, rand.Reader)
    71  		s          = elliptic.Marshal(keyCurve, x, y)
    72  	)
    73  	copy(k.Public[:], s)
    74  	copy(k.Private[:], p)
    75  	p, x, y, s = nil, nil, nil, nil
    76  	for i := range k.share {
    77  		k.share[i] = 0
    78  	}
    79  }
    80  
    81  // Empty returns true if the PublicKey is empty (all zeros).
    82  func (k *KeyPair) Empty() bool {
    83  	return k.Public.Empty()
    84  }
    85  
    86  // Sync attempts to generate the Shared key using the current KeyPair's Public
    87  // and Private key values.
    88  //
    89  // This function returns an error if a Shared key could not be generated.
    90  func (k *KeyPair) Sync() error {
    91  	return k.fillShared(k.Public, k.Private)
    92  }
    93  
    94  // Empty returns true if this PublicKey is empty (all zeros).
    95  func (p PublicKey) Empty() bool {
    96  	for i := range p {
    97  		if p[i] > 0 {
    98  			return false
    99  		}
   100  	}
   101  	return true
   102  }
   103  
   104  // Hash returns the FNV-32 hash of this PublicKey in a uint32 format.
   105  func (p PublicKey) Hash() uint32 {
   106  	h := uint32(2166136261)
   107  	for i := range p {
   108  		h *= 16777619
   109  		h ^= uint32(p[i])
   110  	}
   111  	return h
   112  }
   113  
   114  // IsSynced returns false if the Shared key is empty (all zeros).
   115  func (k *KeyPair) IsSynced() bool {
   116  	for i := range k.share {
   117  		if k.share[i] > 0 {
   118  			return true
   119  		}
   120  	}
   121  	return false
   122  }
   123  
   124  // Shared returns a copy of the current Shared key contained in this KeyPair.
   125  //
   126  // If 'IsSynced' returns false, the output will be a zero filled array.
   127  func (k KeyPair) Shared() SharedKeys {
   128  	return k.share
   129  }
   130  
   131  // Read will read in the PublicKey ONLY from the supplied 'io.Reader' and fill
   132  // the current KeyPair's PublicKey with the resulting data.
   133  //
   134  // Any errors or invalid byte lengths read will return an error.
   135  func (k *KeyPair) Read(r io.Reader) error {
   136  	switch n, err := r.Read(k.Public[:]); {
   137  	case err != nil:
   138  		return err
   139  	case n != publicKeySize:
   140  		return io.ErrUnexpectedEOF
   141  	}
   142  	return nil
   143  }
   144  
   145  // Write will write out the PublicKey ONLY to the supplied 'io.Writer'.
   146  //
   147  // Any errors or invalid byte lengths written will return an error.
   148  func (k *KeyPair) Write(w io.Writer) error {
   149  	switch n, err := w.Write(k.Public[:]); {
   150  	case err != nil:
   151  		return err
   152  	case n != publicKeySize:
   153  		return io.ErrShortWrite
   154  	}
   155  	return nil
   156  }
   157  
   158  // Marshal will write out the Public, Private and Shared key data to the supplied
   159  // 'io.Writer'.
   160  //
   161  // Any errors or invalid byte lengths written will return an error.
   162  func (k *KeyPair) Marshal(w io.Writer) error {
   163  	switch n, err := w.Write(k.Public[:]); {
   164  	case err != nil:
   165  		return err
   166  	case n != publicKeySize:
   167  		return io.ErrShortWrite
   168  	}
   169  	switch n, err := w.Write(k.Private[:]); {
   170  	case err != nil:
   171  		return err
   172  	case n != privateKeySize:
   173  		return io.ErrShortWrite
   174  	}
   175  	switch n, err := w.Write(k.share[:]); {
   176  	case err != nil:
   177  		return err
   178  	case n != sharedKeySize:
   179  		return io.ErrShortWrite
   180  	}
   181  	return nil
   182  }
   183  
   184  // Unmarshal will read in the Public, Private and Shared key data from the supplied
   185  // 'io.Reader' and fill all the current KeyPair data with the resulting data.
   186  //
   187  // Any errors or invalid byte lengths read will return an error.
   188  func (k *KeyPair) Unmarshal(r io.Reader) error {
   189  	switch n, err := r.Read(k.Public[:]); {
   190  	case err != nil:
   191  		return err
   192  	case n != publicKeySize:
   193  		return io.ErrUnexpectedEOF
   194  	}
   195  	switch n, err := r.Read(k.Private[:]); {
   196  	case err != nil:
   197  		return err
   198  	case n != privateKeySize:
   199  		return io.ErrUnexpectedEOF
   200  	}
   201  	switch n, err := r.Read(k.share[:]); {
   202  	case err != nil:
   203  		return err
   204  	case n != sharedKeySize:
   205  		return io.ErrUnexpectedEOF
   206  	}
   207  	return nil
   208  }
   209  
   210  // FillPublic will generate the Shared key using the KeyPair's PrivateKey and
   211  // the supplied PublicKey.
   212  //
   213  // If successful, the PublicKey data will be copied over the current KeyPair's
   214  // PublicKey for successive calls to 'Sync'.
   215  //
   216  // This function returns an error if a Shared key could not be generated.
   217  func (k *KeyPair) FillPublic(p PublicKey) error {
   218  	if err := k.fillShared(p, k.Private); err != nil {
   219  		return err
   220  	}
   221  	copy(k.Public[:], p[:])
   222  	return nil
   223  }
   224  
   225  // FillPrivate will generate the Shared key using the KeyPair's PublicKey and
   226  // the supplied PrivateKey.
   227  //
   228  // If successful, the PrivateKey data will be copied over the current KeyPair's
   229  // PrivateKey for successive calls to 'Sync'.
   230  //
   231  // This function returns an error if a Shared key could not be generated.
   232  func (k *KeyPair) FillPrivate(p PrivateKey) error {
   233  	if err := k.fillShared(k.Public, p); err != nil {
   234  		return err
   235  	}
   236  	copy(k.Private[:], p[:])
   237  	return nil
   238  }
   239  func (k *KeyPair) fillShared(n PublicKey, m PrivateKey) error {
   240  	x, y := elliptic.Unmarshal(keyCurve, n[:])
   241  	if x == nil || y == nil {
   242  		return xerr.Sub("cannot parse curve PublicKey", 0x77)
   243  	}
   244  	v, _ := keyCurve.ScalarMult(x, y, m[:])
   245  	if x, y = nil, nil; v == nil {
   246  		return xerr.Sub("cannot multiply PrivateKey with PublicKey", 0x78)
   247  	}
   248  	copy(k.share[:], v.Bytes())
   249  	x = nil
   250  	return nil
   251  }