github.com/pavlo67/common@v0.5.3/common/auth/auth_ecdsa/ecdsa.go (about)

     1  package auth_ecdsa
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/rand"
     7  	r "math/rand"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/btcsuite/btcutil/base58"
    12  	"github.com/pkg/errors"
    13  
    14  	"github.com/pavlo67/common/common/auth"
    15  	"github.com/pavlo67/common/common/encrlib"
    16  )
    17  
    18  // const Cryptype encrlib.Cryptype = "ecdsa"
    19  
    20  const Proto = "ecdsa"
    21  
    22  var _ auth.Operator = &authECDSA{}
    23  
    24  var errIPToCheckSignature = errors.New("wrong IP to check signature")
    25  var errWrongSignature = errors.New("wrong signature")
    26  var errWrongNumber = errors.New("wrong user's number")
    27  var errEmptyPublicKeyAddress = errors.New("empty public key address")
    28  var errEmptyPrivateKeyGenerated = errors.New("empty private key generated")
    29  
    30  //var cnt uint32
    31  //type Session struct {
    32  //	IP        string
    33  //	StartedAt time.Time
    34  //}
    35  
    36  type authECDSA struct {
    37  	//sessions map[uint64]Session
    38  	//mutex    *sync.Mutex
    39  	//maxSessionDuration time.Duration
    40  	//numbersLimit       int
    41  }
    42  
    43  func New() (auth.Operator, error) {
    44  	r.Seed(time.Now().UnixNano())
    45  
    46  	is := &authECDSA{
    47  		//sessions: map[uint64]Session{},
    48  		//mutex:    &sync.Mutex{},
    49  		//maxSessionDuration: maxSessionDuration,
    50  		//numbersLimit:       numbersLimit,
    51  	}
    52  
    53  	return is, nil
    54  }
    55  
    56  // 	SetCreds creates either session-generated key or new "BTC identity" and returns it
    57  func (is *authECDSA) SetCreds(actor auth.Actor, toSet auth.Creds) (*auth.Creds, error) {
    58  
    59  	//toSet := auth.CredsType(toSet[auth.CredsToSet])
    60  	//
    61  	//if toSet == auth.CredsKeyToSignature {
    62  	//	now := time.Now()
    63  	//
    64  	//	is.mutex.Lock() // Lock() -----------------------------------------------------
    65  	//
    66  	//	if is.numbersLimit > 0 && len(is.sessions) >= is.numbersLimit {
    67  	//		for n, s := range is.sessions {
    68  	//			if now.Sub(s.StartedAt) >= is.maxSessionDuration {
    69  	//				delete(is.sessions, n)
    70  	//			}
    71  	//		}
    72  	//	}
    73  	//
    74  	//	cnt++
    75  	//	numberToSend := uint64(cnt)<<32 + uint64(r.Uint32())
    76  	//
    77  	//	is.sessions[numberToSend] = Session{
    78  	//		IP:        creds[auth.CredsIP], // TODO??? check if IP isn't empty
    79  	//		StartedAt: now,
    80  	//	}
    81  	//
    82  	//	is.mutex.Unlock() // Unlock() -------------------------------------------------
    83  	//
    84  	//	return &auth.Creds{auth.CredsKeyToSignature: strconv.FormatUint(numberToSend, 10)}, nil
    85  	//}
    86  
    87  	// TODO: modify acceptableIDs if it's necessary
    88  
    89  	privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    90  	if err != nil {
    91  		return nil, err
    92  	} else if privKey == nil {
    93  		return nil, errEmptyPrivateKeyGenerated
    94  	}
    95  
    96  	privKeyBytes, err := encrlib.ECDSASerialize(*privKey)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	publKeyBase58 := base58.Encode(encrlib.ECDSAPublicKey(*privKey))
   102  	//nickname := publKeyBase58
   103  	//if toSet.StringDefault(auth.CredsNickname, "") != "" {
   104  	//	nickname = toSet[auth.CredsNickname]
   105  	//}
   106  
   107  	credsNew := &auth.Creds{
   108  		auth.CredsNickname:          publKeyBase58, //  nickname,
   109  		auth.CredsPrivateKey:        string(privKeyBytes),
   110  		auth.CredsPublicKeyBase58:   publKeyBase58,
   111  		auth.CredsPublicKeyEncoding: Proto,
   112  	}
   113  
   114  	return credsNew, nil
   115  }
   116  
   117  const onAuthorize = "on authECDSA.Authenticate(): "
   118  
   119  func (is *authECDSA) Authenticate(toAuth auth.Creds) (*auth.Actor, error) {
   120  	if toAuth[auth.CredsPublicKeyEncoding] != Proto {
   121  		return nil, errors.Wrap(auth.ErrEncryptionType, onAuthorize)
   122  	}
   123  
   124  	keyToSignature := strings.TrimSpace(toAuth[auth.CredsIP])
   125  	if keyToSignature == "" {
   126  		return nil, errors.Wrapf(errIPToCheckSignature, "toAuth: %#v", toAuth)
   127  	}
   128  
   129  	publKeyBase58 := toAuth[auth.CredsPublicKeyBase58]
   130  	if len(publKeyBase58) < 1 {
   131  		return nil, errEmptyPublicKeyAddress
   132  	}
   133  	publKey := base58.Decode(publKeyBase58)
   134  
   135  	//numberToSend, err := strconv.ParseUint(keyToSignature, 10, 64)
   136  	//if err != nil {
   137  	//	return nil, errors.Wrap(auth.ErrSignaturedKey, "not a number!")
   138  	//}
   139  	//is.mutex.Lock() // Lock() -----------------------------------------------------
   140  	//
   141  	//session, ok := is.sessions[numberToSend]
   142  	//if !ok {
   143  	//	return nil, errors.Wrap(auth.ErrSignaturedKey, "no appropriate session")
   144  	//	is.mutex.Unlock() // Unlock() ---------------------------------------------
   145  	//}
   146  	//delete(is.sessions, numberToSend)
   147  	//
   148  	//is.mutex.Unlock() // Unlock() -------------------------------------------------
   149  	//
   150  	//if time.Now().Sub(session.StartedAt) > is.maxSessionDuration {
   151  	//	return nil, errors.Wrap(auth.ErrAuthSession, "session is expired")
   152  	//}
   153  	//
   154  	//if session.IP != toAuth[auth.CredsIP] {
   155  	//	return nil, auth.ErrIP
   156  	//}
   157  
   158  	signature := []byte(toAuth[auth.CredsSignature])
   159  	if !encrlib.ECDSAVerify(keyToSignature, publKey, signature) {
   160  		return nil, errWrongSignature
   161  	}
   162  
   163  	var nickname = publKeyBase58
   164  	//if nicknameReceived := toAuth[auth.CredsNickname]; strings.TrimSpace(nicknameReceived) != "" {
   165  	//	nickname = nicknameReceived
   166  	//}
   167  
   168  	return &auth.Actor{
   169  		Identity: &auth.Identity{
   170  			ID:       auth.ID(Proto + "://" + publKeyBase58),
   171  			Nickname: nickname,
   172  		},
   173  	}, nil
   174  }