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 }