mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender.git
synced 2025-08-10 13:43:49 +02:00
feat:#10 added new minimal backend
This commit is contained in:
62
datamanager/backend/tools/security/crypto.go
Normal file
62
datamanager/backend/tools/security/crypto.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// S256Challenge creates base64 encoded sha256 challenge string derived from code.
|
||||
// The padding of the result base64 string is stripped per [RFC 7636].
|
||||
//
|
||||
// [RFC 7636]: https://datatracker.ietf.org/doc/html/rfc7636#section-4.2
|
||||
func S256Challenge(code string) string {
|
||||
h := sha256.New()
|
||||
h.Write([]byte(code))
|
||||
return strings.TrimRight(base64.URLEncoding.EncodeToString(h.Sum(nil)), "=")
|
||||
}
|
||||
|
||||
// MD5 creates md5 hash from the provided plain text.
|
||||
func MD5(text string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(text))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
// SHA256 creates sha256 hash as defined in FIPS 180-4 from the provided text.
|
||||
func SHA256(text string) string {
|
||||
h := sha256.New()
|
||||
h.Write([]byte(text))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
// SHA512 creates sha512 hash as defined in FIPS 180-4 from the provided text.
|
||||
func SHA512(text string) string {
|
||||
h := sha512.New()
|
||||
h.Write([]byte(text))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
// HS256 creates a HMAC hash with sha256 digest algorithm.
|
||||
func HS256(text string, secret string) string {
|
||||
h := hmac.New(sha256.New, []byte(secret))
|
||||
h.Write([]byte(text))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
// HS512 creates a HMAC hash with sha512 digest algorithm.
|
||||
func HS512(text string, secret string) string {
|
||||
h := hmac.New(sha512.New, []byte(secret))
|
||||
h.Write([]byte(text))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
// Equal compares two hash strings for equality without leaking timing information.
|
||||
func Equal(hash1 string, hash2 string) bool {
|
||||
return subtle.ConstantTimeCompare([]byte(hash1), []byte(hash2)) == 1
|
||||
}
|
58
datamanager/backend/tools/security/encrypt.go
Normal file
58
datamanager/backend/tools/security/encrypt.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
crand "crypto/rand"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Encrypt encrypts data with key (must be valid 32 char aes key).
|
||||
func Encrypt(data []byte, key string) (string, error) {
|
||||
block, err := aes.NewCipher([]byte(key))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
|
||||
// populates the nonce with a cryptographically secure random sequence
|
||||
if _, err := io.ReadFull(crand.Reader, nonce); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cipherByte := gcm.Seal(nonce, nonce, data, nil)
|
||||
|
||||
result := base64.StdEncoding.EncodeToString(cipherByte)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Decrypt decrypts encrypted text with key (must be valid 32 chars aes key).
|
||||
func Decrypt(cipherText string, key string) ([]byte, error) {
|
||||
block, err := aes.NewCipher([]byte(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonceSize := gcm.NonceSize()
|
||||
|
||||
cipherByte, err := base64.StdEncoding.DecodeString(cipherText)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce, cipherByteClean := cipherByte[:nonceSize], cipherByte[nonceSize:]
|
||||
return gcm.Open(nil, nonce, cipherByteClean, nil)
|
||||
}
|
66
datamanager/backend/tools/security/jwt.go
Normal file
66
datamanager/backend/tools/security/jwt.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
)
|
||||
|
||||
// ParseUnverifiedJWT parses JWT and returns its claims
|
||||
// but DOES NOT verify the signature.
|
||||
//
|
||||
// It verifies only the exp, iat and nbf claims.
|
||||
func ParseUnverifiedJWT(token string) (jwt.MapClaims, error) {
|
||||
claims := jwt.MapClaims{}
|
||||
|
||||
parser := &jwt.Parser{}
|
||||
_, _, err := parser.ParseUnverified(token, claims)
|
||||
|
||||
if err == nil {
|
||||
err = claims.Valid()
|
||||
}
|
||||
|
||||
return claims, err
|
||||
}
|
||||
|
||||
// ParseJWT verifies and parses JWT and returns its claims.
|
||||
func ParseJWT(token string, verificationKey string) (jwt.MapClaims, error) {
|
||||
parser := jwt.NewParser(jwt.WithValidMethods([]string{"HS256"}))
|
||||
|
||||
parsedToken, err := parser.Parse(token, func(t *jwt.Token) (any, error) {
|
||||
return []byte(verificationKey), nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if claims, ok := parsedToken.Claims.(jwt.MapClaims); ok && parsedToken.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("Unable to parse token.")
|
||||
}
|
||||
|
||||
// NewJWT generates and returns new HS256 signed JWT.
|
||||
func NewJWT(payload jwt.MapClaims, signingKey string, secondsDuration int64) (string, error) {
|
||||
seconds := time.Duration(secondsDuration) * time.Second
|
||||
|
||||
claims := jwt.MapClaims{
|
||||
"exp": time.Now().Add(seconds).Unix(),
|
||||
}
|
||||
|
||||
for k, v := range payload {
|
||||
claims[k] = v
|
||||
}
|
||||
|
||||
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(signingKey))
|
||||
}
|
||||
|
||||
// Deprecated:
|
||||
// Consider replacing with NewJWT().
|
||||
//
|
||||
// NewToken is a legacy alias for NewJWT that generates a HS256 signed JWT.
|
||||
func NewToken(payload jwt.MapClaims, signingKey string, secondsDuration int64) (string, error) {
|
||||
return NewJWT(payload, signingKey, secondsDuration)
|
||||
}
|
64
datamanager/backend/tools/security/random.go
Normal file
64
datamanager/backend/tools/security/random.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
cryptoRand "crypto/rand"
|
||||
"math/big"
|
||||
mathRand "math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
const defaultRandomAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
func init() {
|
||||
mathRand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// RandomString generates a cryptographically random string with the specified length.
|
||||
//
|
||||
// The generated string matches [A-Za-z0-9]+ and it's transparent to URL-encoding.
|
||||
func RandomString(length int) string {
|
||||
return RandomStringWithAlphabet(length, defaultRandomAlphabet)
|
||||
}
|
||||
|
||||
// RandomStringWithAlphabet generates a cryptographically random string
|
||||
// with the specified length and characters set.
|
||||
//
|
||||
// It panics if for some reason rand.Int returns a non-nil error.
|
||||
func RandomStringWithAlphabet(length int, alphabet string) string {
|
||||
b := make([]byte, length)
|
||||
max := big.NewInt(int64(len(alphabet)))
|
||||
|
||||
for i := range b {
|
||||
n, err := cryptoRand.Int(cryptoRand.Reader, max)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b[i] = alphabet[n.Int64()]
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// PseudorandomString generates a pseudorandom string with the specified length.
|
||||
//
|
||||
// The generated string matches [A-Za-z0-9]+ and it's transparent to URL-encoding.
|
||||
//
|
||||
// For a cryptographically random string (but a little bit slower) use RandomString instead.
|
||||
func PseudorandomString(length int) string {
|
||||
return PseudorandomStringWithAlphabet(length, defaultRandomAlphabet)
|
||||
}
|
||||
|
||||
// PseudorandomStringWithAlphabet generates a pseudorandom string
|
||||
// with the specified length and characters set.
|
||||
//
|
||||
// For a cryptographically random (but a little bit slower) use RandomStringWithAlphabet instead.
|
||||
func PseudorandomStringWithAlphabet(length int, alphabet string) string {
|
||||
b := make([]byte, length)
|
||||
max := len(alphabet)
|
||||
|
||||
for i := range b {
|
||||
b[i] = alphabet[mathRand.Intn(max)]
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
Reference in New Issue
Block a user