| @@ -5,11 +5,15 @@ | |||
| package models | |||
| import ( | |||
| "crypto/aes" | |||
| "crypto/cipher" | |||
| "crypto/md5" | |||
| "crypto/rand" | |||
| "crypto/subtle" | |||
| "encoding/base64" | |||
| "errors" | |||
| "io" | |||
| "github.com/Unknwon/com" | |||
| "github.com/pquerna/otp/totp" | |||
| "code.gitea.io/gitea/modules/base" | |||
| @@ -52,7 +56,7 @@ func (t *TwoFactor) getEncryptionKey() []byte { | |||
| // SetSecret sets the 2FA secret. | |||
| func (t *TwoFactor) SetSecret(secret string) error { | |||
| secretBytes, err := com.AESGCMEncrypt(t.getEncryptionKey(), []byte(secret)) | |||
| secretBytes, err := aesEncrypt(t.getEncryptionKey(), []byte(secret)) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| @@ -66,7 +70,7 @@ func (t *TwoFactor) ValidateTOTP(passcode string) (bool, error) { | |||
| if err != nil { | |||
| return false, err | |||
| } | |||
| secret, err := com.AESGCMDecrypt(t.getEncryptionKey(), decodedStoredSecret) | |||
| secret, err := aesDecrypt(t.getEncryptionKey(), decodedStoredSecret) | |||
| if err != nil { | |||
| return false, err | |||
| } | |||
| @@ -74,6 +78,43 @@ func (t *TwoFactor) ValidateTOTP(passcode string) (bool, error) { | |||
| return totp.Validate(passcode, secretStr), nil | |||
| } | |||
| // aesEncrypt encrypts text and given key with AES. | |||
| func aesEncrypt(key, text []byte) ([]byte, error) { | |||
| block, err := aes.NewCipher(key) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| b := base64.StdEncoding.EncodeToString(text) | |||
| ciphertext := make([]byte, aes.BlockSize+len(b)) | |||
| iv := ciphertext[:aes.BlockSize] | |||
| if _, err := io.ReadFull(rand.Reader, iv); err != nil { | |||
| return nil, err | |||
| } | |||
| cfb := cipher.NewCFBEncrypter(block, iv) | |||
| cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b)) | |||
| return ciphertext, nil | |||
| } | |||
| // aesDecrypt decrypts text and given key with AES. | |||
| func aesDecrypt(key, text []byte) ([]byte, error) { | |||
| block, err := aes.NewCipher(key) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if len(text) < aes.BlockSize { | |||
| return nil, errors.New("ciphertext too short") | |||
| } | |||
| iv := text[:aes.BlockSize] | |||
| text = text[aes.BlockSize:] | |||
| cfb := cipher.NewCFBDecrypter(block, iv) | |||
| cfb.XORKeyStream(text, text) | |||
| data, err := base64.StdEncoding.DecodeString(string(text)) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| return data, nil | |||
| } | |||
| // NewTwoFactor creates a new two-factor authentication token. | |||
| func NewTwoFactor(t *TwoFactor) error { | |||
| err := t.GenerateScratchToken() | |||