github.com/go-chef/chef@v0.30.1/authentication.go (about)

     1  package chef
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/rand"
     6  	"crypto/rsa"
     7  	"crypto/sha1"
     8  	"crypto/sha256"
     9  	"encoding/base64"
    10  	"errors"
    11  	"io"
    12  	"math/big"
    13  )
    14  
    15  // GenerateDigestSignature will generate a signature of the given data protocol 1.3
    16  func GenerateDigestSignature(priv *rsa.PrivateKey, string_to_sign string) (sig []byte, err error) {
    17  	hashed := sha256.Sum256([]byte(string_to_sign))
    18  	sig, err = rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hashed[:])
    19  	if err != nil {
    20  		return nil, err
    21  	}
    22  	return sig, nil
    23  }
    24  
    25  // GenerateSignature will generate a signature ( sign ) the given data
    26  func GenerateSignature(priv *rsa.PrivateKey, data string) (enc []byte, err error) {
    27  	sig, err := privateEncrypt(priv, []byte(data))
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  
    32  	return sig, nil
    33  }
    34  
    35  // privateEncrypt implements OpenSSL's RSA_private_encrypt function
    36  func privateEncrypt(key *rsa.PrivateKey, data []byte) (enc []byte, err error) {
    37  	k := (key.N.BitLen() + 7) / 8
    38  	tLen := len(data)
    39  
    40  	// rfc2313, section 8:
    41  	// The length of the data D shall not be more than k-11 octets
    42  	if tLen > k-11 {
    43  		err = errors.New("Data too long")
    44  		return
    45  	}
    46  	em := make([]byte, k)
    47  	em[1] = 1
    48  	for i := 2; i < k-tLen-1; i++ {
    49  		em[i] = 0xff
    50  	}
    51  	copy(em[k-tLen:k], data)
    52  	c := new(big.Int).SetBytes(em)
    53  	if c.Cmp(key.N) > 0 {
    54  		err = nil
    55  		return
    56  	}
    57  	var m *big.Int
    58  	var ir *big.Int
    59  	if key.Precomputed.Dp == nil {
    60  		m = new(big.Int).Exp(c, key.D, key.N)
    61  	} else {
    62  		// We have the precalculated values needed for the CRT.
    63  		m = new(big.Int).Exp(c, key.Precomputed.Dp, key.Primes[0])
    64  		m2 := new(big.Int).Exp(c, key.Precomputed.Dq, key.Primes[1])
    65  		m.Sub(m, m2)
    66  		if m.Sign() < 0 {
    67  			m.Add(m, key.Primes[0])
    68  		}
    69  		m.Mul(m, key.Precomputed.Qinv)
    70  		m.Mod(m, key.Primes[0])
    71  		m.Mul(m, key.Primes[1])
    72  		m.Add(m, m2)
    73  
    74  		for i, values := range key.Precomputed.CRTValues {
    75  			prime := key.Primes[2+i]
    76  			m2.Exp(c, values.Exp, prime)
    77  			m2.Sub(m2, m)
    78  			m2.Mul(m2, values.Coeff)
    79  			m2.Mod(m2, prime)
    80  			if m2.Sign() < 0 {
    81  				m2.Add(m2, prime)
    82  			}
    83  			m2.Mul(m2, values.R)
    84  			m.Add(m, m2)
    85  		}
    86  	}
    87  
    88  	if ir != nil {
    89  		// Unblind.
    90  		m.Mul(m, ir)
    91  		m.Mod(m, key.N)
    92  	}
    93  	enc = m.Bytes()
    94  	return
    95  }
    96  
    97  // HashStr returns the base64 encoded SHA1 sum of the toHash string
    98  func HashStr(toHash string) string {
    99  	h := sha1.New()
   100  	io.WriteString(h, toHash)
   101  	hashed := base64.StdEncoding.EncodeToString(h.Sum(nil))
   102  	return hashed
   103  }
   104  
   105  // HashStr256 returns the base64 encoded SHA256 sum of the toHash string
   106  func HashStr256(toHash string) string {
   107  	sum := sha256.Sum256([]byte(toHash))
   108  	sumslice := sum[:]
   109  	hashed := base64.StdEncoding.EncodeToString(sumslice)
   110  	return hashed
   111  }
   112  
   113  // Base64BlockEncode takes a byte slice and breaks it up into a
   114  // slice of base64 encoded strings
   115  func Base64BlockEncode(content []byte, limit int) []string {
   116  	resultString := base64.StdEncoding.EncodeToString(content)
   117  	var resultSlice []string
   118  
   119  	index := 0
   120  
   121  	var maxLengthPerSlice int
   122  
   123  	// No limit
   124  	if limit == 0 {
   125  		maxLengthPerSlice = len(resultString)
   126  	} else {
   127  		maxLengthPerSlice = limit
   128  	}
   129  
   130  	// Iterate through the encoded string storing
   131  	// a max of <limit> per slice item
   132  	for i := 0; i < len(resultString)/maxLengthPerSlice; i++ {
   133  		resultSlice = append(resultSlice, resultString[index:index+maxLengthPerSlice])
   134  		index += maxLengthPerSlice
   135  	}
   136  
   137  	// Add remaining chunk to the end of the slice
   138  	if len(resultString)%maxLengthPerSlice != 0 {
   139  		resultSlice = append(resultSlice, resultString[index:])
   140  	}
   141  
   142  	return resultSlice
   143  }