"crypto/md5"
"crypto/sha256"
"crypto/subtle"
+ "encoding/base32"
"encoding/base64"
"fmt"
// GenerateScratchToken recreates the scratch token the user is using.
func (t *TwoFactor) GenerateScratchToken() (string, error) {
- token, err := util.RandomString(8)
+ tokenBytes, err := util.CryptoRandomBytes(6)
if err != nil {
return "", err
}
- t.ScratchSalt, _ = util.RandomString(10)
+ // these chars are specially chosen, avoid ambiguous chars like `0`, `O`, `1`, `I`.
+ const base32Chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
+ token := base32.NewEncoding(base32Chars).WithPadding(base32.NoPadding).EncodeToString(tokenBytes)
+ t.ScratchSalt, _ = util.CryptoRandomString(10)
t.ScratchHash = HashToken(token, t.ScratchSalt)
return token, nil
}
for _, tfa := range tfas {
// generate salt
- salt, err := util.RandomString(10)
+ salt, err := util.CryptoRandomString(10)
if err != nil {
return err
}
for _, token := range tokens {
// generate salt
- salt, err := util.RandomString(10)
+ salt, err := util.CryptoRandomString(10)
if err != nil {
return err
}
// NewAccessToken creates new access token.
func NewAccessToken(t *AccessToken) error {
- salt, err := util.RandomString(10)
+ salt, err := util.CryptoRandomString(10)
if err != nil {
return err
}
// GetUserSalt returns a random user salt token.
func GetUserSalt() (string, error) {
- rBytes, err := util.RandomBytes(SaltByteLength)
+ rBytes, err := util.CryptoRandomBytes(SaltByteLength)
if err != nil {
return "", err
}
// NewSecretKey generate a new value intended to be used by SECRET_KEY.
func NewSecretKey() (string, error) {
- secretKey, err := util.RandomString(64)
+ secretKey, err := util.CryptoRandomString(64)
if err != nil {
return "", err
}
// NewWithLength creates a new secret for a given length
func NewWithLength(length int64) (string, error) {
- return util.RandomString(length)
+ return util.CryptoRandomString(length)
}
// AesEncrypt encrypts text and given key with AES.
return dict, nil
}
-// RandomInt returns a random integer between 0 and limit, inclusive
-func RandomInt(limit int64) (int64, error) {
+// CryptoRandomInt returns a crypto random integer between 0 and limit, inclusive
+func CryptoRandomInt(limit int64) (int64, error) {
rInt, err := rand.Int(rand.Reader, big.NewInt(limit))
if err != nil {
return 0, err
return rInt.Int64(), nil
}
-const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+const alphanumericalChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
-// RandomString generates a random alphanumerical string
-func RandomString(length int64) (string, error) {
- bytes := make([]byte, length)
- limit := int64(len(letters))
- for i := range bytes {
- num, err := RandomInt(limit)
+// CryptoRandomString generates a crypto random alphanumerical string, each byte is generated by [0,61] range
+func CryptoRandomString(length int64) (string, error) {
+ buf := make([]byte, length)
+ limit := int64(len(alphanumericalChars))
+ for i := range buf {
+ num, err := CryptoRandomInt(limit)
if err != nil {
return "", err
}
- bytes[i] = letters[num]
+ buf[i] = alphanumericalChars[num]
}
- return string(bytes), nil
+ return string(buf), nil
}
-// RandomBytes generates `length` bytes
-// This differs from RandomString, as RandomString is limits each byte to have
-// a maximum value of 63 instead of 255(max byte size)
-func RandomBytes(length int64) ([]byte, error) {
- bytes := make([]byte, length)
- _, err := rand.Read(bytes)
- return bytes, err
+// CryptoRandomBytes generates `length` crypto bytes
+// This differs from CryptoRandomString, as each byte in CryptoRandomString is generated by [0,61] range
+// This function generates totally random bytes, each byte is generated by [0,255] range
+func CryptoRandomBytes(length int64) ([]byte, error) {
+ buf := make([]byte, length)
+ _, err := rand.Read(buf)
+ return buf, err
}
}
func Test_RandomInt(t *testing.T) {
- int, err := RandomInt(255)
+ int, err := CryptoRandomInt(255)
assert.True(t, int >= 0)
assert.True(t, int <= 255)
assert.NoError(t, err)
}
func Test_RandomString(t *testing.T) {
- str1, err := RandomString(32)
+ str1, err := CryptoRandomString(32)
assert.NoError(t, err)
matches, err := regexp.MatchString(`^[a-zA-Z0-9]{32}$`, str1)
assert.NoError(t, err)
assert.True(t, matches)
- str2, err := RandomString(32)
+ str2, err := CryptoRandomString(32)
assert.NoError(t, err)
matches, err = regexp.MatchString(`^[a-zA-Z0-9]{32}$`, str1)
assert.NoError(t, err)
assert.NotEqual(t, str1, str2)
- str3, err := RandomString(256)
+ str3, err := CryptoRandomString(256)
assert.NoError(t, err)
matches, err = regexp.MatchString(`^[a-zA-Z0-9]{256}$`, str3)
assert.NoError(t, err)
assert.True(t, matches)
- str4, err := RandomString(256)
+ str4, err := CryptoRandomString(256)
assert.NoError(t, err)
matches, err = regexp.MatchString(`^[a-zA-Z0-9]{256}$`, str4)
assert.NoError(t, err)
}
func Test_RandomBytes(t *testing.T) {
- bytes1, err := RandomBytes(32)
+ bytes1, err := CryptoRandomBytes(32)
assert.NoError(t, err)
- bytes2, err := RandomBytes(32)
+ bytes2, err := CryptoRandomBytes(32)
assert.NoError(t, err)
assert.NotEqual(t, bytes1, bytes2)
- bytes3, err := RandomBytes(256)
+ bytes3, err := CryptoRandomBytes(256)
assert.NoError(t, err)
- bytes4, err := RandomBytes(256)
+ bytes4, err := CryptoRandomBytes(256)
assert.NoError(t, err)
assert.NotEqual(t, bytes3, bytes4)
if length < 256 {
length = 256
}
- password, err := util.RandomString(int64(length))
+ password, err := util.CryptoRandomString(int64(length))
if err != nil {
ctx.RenderWithErr(err.Error(), tplSignUpOID, form)
return
return
}
- remoteSuffix, err := util.RandomString(10)
+ remoteSuffix, err := util.CryptoRandomString(10)
if err != nil {
ctx.ServerError("RandomString", err)
return