mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 21:41:55 +00:00
85 lines
2.1 KiB
Go
85 lines
2.1 KiB
Go
package secure
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
const pkceCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
|
|
|
|
// RandomBytes returns securely generated random bytes of given length.
|
|
func RandomBytes(length int) ([]byte, error) {
|
|
if length <= 0 {
|
|
return nil, fmt.Errorf("length must be positive")
|
|
}
|
|
b := make([]byte, length)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
// RandomString returns a base64url encoded random string of approximately the requested length.
|
|
func RandomString(length int) (string, error) {
|
|
if length <= 0 {
|
|
return "", fmt.Errorf("length must be positive")
|
|
}
|
|
// Generate ceil(length * 6/8) bytes to have enough entropy for base64 url encoding.
|
|
byteLen := (length*6 + 7) / 8
|
|
bytes, err := RandomBytes(byteLen)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
s := base64.RawURLEncoding.EncodeToString(bytes)
|
|
if len(s) > length {
|
|
return s[:length], nil
|
|
}
|
|
// If encoded string shorter, pad using charset
|
|
if len(s) < length {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(s)
|
|
extraNeeded := length - len(s)
|
|
more, err := randomFromCharset(extraNeeded)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
sb.WriteString(more)
|
|
return sb.String(), nil
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
// PKCECodeVerifier generates a random string compliant with RFC 7636.
|
|
func PKCECodeVerifier(length int) (string, error) {
|
|
if length < 43 {
|
|
length = 43
|
|
}
|
|
if length > 128 {
|
|
length = 128
|
|
}
|
|
return randomFromCharset(length)
|
|
}
|
|
|
|
// randomFromCharset returns a random string of given length using pkceCharset.
|
|
func randomFromCharset(length int) (string, error) {
|
|
if length <= 0 {
|
|
return "", fmt.Errorf("length must be positive")
|
|
}
|
|
bytes, err := RandomBytes(length)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
out := make([]byte, length)
|
|
for i, b := range bytes {
|
|
out[i] = pkceCharset[int(b)%len(pkceCharset)]
|
|
}
|
|
return string(out), nil
|
|
}
|
|
|
|
// Base64URLEncode encodes the input bytes using base64 URL encoding without padding.
|
|
func Base64URLEncode(data []byte) string {
|
|
return base64.RawURLEncoding.EncodeToString(data)
|
|
}
|