2023-01-15 16:14:19 +01:00
|
|
|
// SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
|
2022-10-26 14:05:25 +02:00
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
|
|
|
package mail
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/rand"
|
|
|
|
"encoding/binary"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Range of characters for the secure string generation
|
2024-10-07 15:03:07 +02:00
|
|
|
const cr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-"
|
2022-10-26 14:05:25 +02:00
|
|
|
|
|
|
|
// Bitmask sizes for the string generators (based on 93 chars total)
|
2024-10-06 17:00:49 +02:00
|
|
|
//
|
|
|
|
// These constants define bitmask-related values used for efficient random string generation.
|
2024-10-07 15:03:07 +02:00
|
|
|
// The bitmask operates over 66 possible characters, and the constants help determine the
|
2024-10-06 17:00:49 +02:00
|
|
|
// number of bits and indices used in the process.
|
2022-10-26 14:05:25 +02:00
|
|
|
const (
|
2024-10-07 15:03:07 +02:00
|
|
|
// letterIdxBits: Number of bits needed to represent a letter index. We have 64 possible characters
|
|
|
|
// which fit into 6 bits.
|
|
|
|
letterIdxBits = 6
|
2024-10-06 17:00:49 +02:00
|
|
|
// letterIdxMask: Bitmask to extract letter indices (all 1-bits for letterIdxBits).
|
|
|
|
letterIdxMask = 1<<letterIdxBits - 1
|
|
|
|
// letterIdxMax: The maximum number of letter indices that fit in 63 bits.
|
|
|
|
letterIdxMax = 63 / letterIdxBits
|
2022-10-26 14:05:25 +02:00
|
|
|
)
|
|
|
|
|
2024-10-06 17:00:49 +02:00
|
|
|
// randomStringSecure returns a random string of the specified length.
|
|
|
|
//
|
|
|
|
// This function generates a cryptographically secure random string of the given length using
|
|
|
|
// the crypto/rand package. It ensures that the randomness is secure and suitable for
|
|
|
|
// cryptographic purposes. The function reads random bytes, converts them to indices within
|
|
|
|
// a character range, and builds the string. If an error occurs while reading from the random
|
|
|
|
// pool, it returns the error.
|
|
|
|
//
|
|
|
|
// Parameters:
|
|
|
|
// - length: The length of the random string to be generated.
|
|
|
|
//
|
|
|
|
// Returns:
|
|
|
|
// - A randomly generated string.
|
|
|
|
// - An error if the random generation fails.
|
2024-02-27 11:30:09 +01:00
|
|
|
func randomStringSecure(length int) (string, error) {
|
|
|
|
randString := strings.Builder{}
|
|
|
|
randString.Grow(length)
|
|
|
|
charRangeLength := len(cr)
|
2022-10-26 14:05:25 +02:00
|
|
|
|
2024-02-27 11:30:09 +01:00
|
|
|
randPool := make([]byte, 8)
|
|
|
|
_, err := rand.Read(randPool)
|
2022-10-26 14:05:25 +02:00
|
|
|
if err != nil {
|
2024-02-27 11:30:09 +01:00
|
|
|
return randString.String(), err
|
2022-10-26 14:05:25 +02:00
|
|
|
}
|
2024-02-27 11:30:09 +01:00
|
|
|
for idx, char, rest := length-1, binary.BigEndian.Uint64(randPool), letterIdxMax; idx >= 0; {
|
|
|
|
if rest == 0 {
|
|
|
|
_, err = rand.Read(randPool)
|
2022-10-26 14:05:25 +02:00
|
|
|
if err != nil {
|
2024-02-27 11:30:09 +01:00
|
|
|
return randString.String(), err
|
2022-10-26 14:05:25 +02:00
|
|
|
}
|
2024-02-27 11:30:09 +01:00
|
|
|
char, rest = binary.BigEndian.Uint64(randPool), letterIdxMax
|
2022-10-26 14:05:25 +02:00
|
|
|
}
|
2024-02-27 11:43:05 +01:00
|
|
|
if i := int(char & letterIdxMask); i < charRangeLength {
|
|
|
|
randString.WriteByte(cr[i])
|
2024-02-27 11:30:09 +01:00
|
|
|
idx--
|
2022-10-26 14:05:25 +02:00
|
|
|
}
|
2024-02-27 11:30:09 +01:00
|
|
|
char >>= letterIdxBits
|
|
|
|
rest--
|
2022-10-26 14:05:25 +02:00
|
|
|
}
|
|
|
|
|
2024-02-27 11:30:09 +01:00
|
|
|
return randString.String(), nil
|
2022-10-26 14:05:25 +02:00
|
|
|
}
|