From bd786b8ef0bd8a9811ec52d39ae3139ba17a0ad0 Mon Sep 17 00:00:00 2001 From: Unknwon Date: Mon, 13 Feb 2017 14:05:49 -0500 Subject: [PATCH] auth: remove MD5 for secure cookie secret (#4117) Update vendor accordingly --- routers/user/auth.go | 5 +-- vendor/github.com/Unknwon/com/string.go | 54 +++++++++++++++---------- vendor/gopkg.in/macaron.v1/context.go | 21 +++++----- vendor/gopkg.in/macaron.v1/macaron.go | 4 +- vendor/vendor.json | 12 +++--- 5 files changed, 52 insertions(+), 44 deletions(-) diff --git a/routers/user/auth.go b/routers/user/auth.go index 10cee51c9..88ad055f5 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -55,7 +55,7 @@ func AutoSignIn(ctx *context.Context) (bool, error) { return false, nil } - if val, ok := ctx.GetSuperSecureCookie(base.EncodeMD5(u.Rands+u.Passwd), setting.CookieRememberName); !ok || val != u.Name { + if val, ok := ctx.GetSuperSecureCookie(u.Rands+u.Passwd, setting.CookieRememberName); !ok || val != u.Name { return false, nil } @@ -124,8 +124,7 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) { if form.Remember { days := 86400 * setting.LogInRememberDays ctx.SetCookie(setting.CookieUserName, u.Name, days, setting.AppSubUrl) - ctx.SetSuperSecureCookie(base.EncodeMD5(u.Rands+u.Passwd), - setting.CookieRememberName, u.Name, days, setting.AppSubUrl) + ctx.SetSuperSecureCookie(u.Rands+u.Passwd, setting.CookieRememberName, u.Name, days, setting.AppSubUrl) } ctx.Session.Set("uid", u.ID) diff --git a/vendor/github.com/Unknwon/com/string.go b/vendor/github.com/Unknwon/com/string.go index 4c79820f1..7080d174a 100644 --- a/vendor/github.com/Unknwon/com/string.go +++ b/vendor/github.com/Unknwon/com/string.go @@ -19,9 +19,7 @@ import ( "crypto/aes" "crypto/cipher" "crypto/rand" - "encoding/base64" "errors" - "io" r "math/rand" "strconv" "strings" @@ -30,41 +28,53 @@ import ( "unicode/utf8" ) -// AESEncrypt encrypts text and given key with AES. -func AESEncrypt(key, text []byte) ([]byte, error) { +// AESGCMEncrypt encrypts plaintext with the given key using AES in GCM mode. +func AESGCMEncrypt(key, plaintext []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 { + + gcm, err := cipher.NewGCM(block) + if err != nil { return nil, err } - cfb := cipher.NewCFBEncrypter(block, iv) - cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b)) - return ciphertext, nil + + nonce := make([]byte, gcm.NonceSize()) + if _, err := rand.Read(nonce); err != nil { + return nil, err + } + + ciphertext := gcm.Seal(nil, nonce, plaintext, nil) + return append(nonce, ciphertext...), nil } -// AESDecrypt decrypts text and given key with AES. -func AESDecrypt(key, text []byte) ([]byte, error) { +// AESGCMDecrypt decrypts ciphertext with the given key using AES in GCM mode. +func AESGCMDecrypt(key, ciphertext []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)) + + gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } - return data, nil + + size := gcm.NonceSize() + if len(ciphertext)-size <= 0 { + return nil, errors.New("Ciphertext is empty") + } + + nonce := ciphertext[:size] + ciphertext = ciphertext[size:] + + plainText, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, err + } + + return plainText, nil } // IsLetter returns true if the 'l' is an English letter. diff --git a/vendor/gopkg.in/macaron.v1/context.go b/vendor/gopkg.in/macaron.v1/context.go index ef3cb9837..dffc50cf6 100644 --- a/vendor/gopkg.in/macaron.v1/context.go +++ b/vendor/gopkg.in/macaron.v1/context.go @@ -15,7 +15,7 @@ package macaron import ( - "crypto/md5" + "crypto/sha256" "encoding/hex" "html/template" "io" @@ -32,8 +32,8 @@ import ( "time" "github.com/Unknwon/com" - "github.com/go-macaron/inject" + "golang.org/x/crypto/pbkdf2" ) // Locale reprents a localization interface. @@ -419,30 +419,29 @@ func (ctx *Context) GetSecureCookie(key string) (string, bool) { // SetSuperSecureCookie sets given cookie value to response header with secret string. func (ctx *Context) SetSuperSecureCookie(secret, name, value string, others ...interface{}) { - m := md5.Sum([]byte(secret)) - secret = hex.EncodeToString(m[:]) - text, err := com.AESEncrypt([]byte(secret), []byte(value)) + key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New) + text, err := com.AESGCMEncrypt(key, []byte(value)) if err != nil { panic("error encrypting cookie: " + err.Error()) } + ctx.SetCookie(name, hex.EncodeToString(text), others...) } // GetSuperSecureCookie returns given cookie value from request header with secret string. -func (ctx *Context) GetSuperSecureCookie(secret, key string) (string, bool) { - val := ctx.GetCookie(key) +func (ctx *Context) GetSuperSecureCookie(secret, name string) (string, bool) { + val := ctx.GetCookie(name) if val == "" { return "", false } - data, err := hex.DecodeString(val) + text, err := hex.DecodeString(val) if err != nil { return "", false } - m := md5.Sum([]byte(secret)) - secret = hex.EncodeToString(m[:]) - text, err := com.AESDecrypt([]byte(secret), data) + key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New) + text, err = com.AESGCMDecrypt(key, text) return string(text), err == nil } diff --git a/vendor/gopkg.in/macaron.v1/macaron.go b/vendor/gopkg.in/macaron.v1/macaron.go index d30a7f2e1..30ffca1cd 100644 --- a/vendor/gopkg.in/macaron.v1/macaron.go +++ b/vendor/gopkg.in/macaron.v1/macaron.go @@ -32,7 +32,7 @@ import ( "github.com/go-macaron/inject" ) -const _VERSION = "1.2.0.0128" +const _VERSION = "1.2.1.0213" func Version() string { return _VERSION @@ -144,7 +144,7 @@ func New() *Macaron { } // Classic creates a classic Macaron with some basic default middleware: -// mocaron.Logger, mocaron.Recovery and mocaron.Static. +// macaron.Logger, macaron.Recovery and macaron.Static. func Classic() *Macaron { m := New() m.Use(Logger()) diff --git a/vendor/vendor.json b/vendor/vendor.json index cc03ec670..a18dd58bc 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -15,10 +15,10 @@ "revisionTime": "2016-07-15T03:28:08Z" }, { - "checksumSHA1": "ly9VLPE9GKo2U7mnbZyjb2LDQ3w=", + "checksumSHA1": "7HXb3cry6luicWeJM9Uxwzfo9Rs=", "path": "github.com/Unknwon/com", - "revision": "28b053d5a2923b87ce8c5a08f3af779894a72758", - "revisionTime": "2015-10-08T13:54:07Z" + "revision": "0db4a625e949e956314d7d1adea9bf82384cc10c", + "revisionTime": "2017-02-13T07:20:14Z" }, { "checksumSHA1": "gSAaJ38R4iqG2CEsZe/ftOs3V9w=", @@ -543,10 +543,10 @@ "revisionTime": "2016-08-08T14:54:09Z" }, { - "checksumSHA1": "QbG9fWct1WpeoLw+f2ScWxIOuVw=", + "checksumSHA1": "XevKi11X5xpgqjYIahVgsx/8pFk=", "path": "gopkg.in/macaron.v1", - "revision": "2e636df8e98d0382b1bab92f8d82d08c72a72016", - "revisionTime": "2017-01-28T20:05:53Z" + "revision": "a325110f8b392bce3e5cdeb8c44bf98078ada3be", + "revisionTime": "2017-02-13T09:12:08Z" }, { "checksumSHA1": "6QPjE+qflEBHg+JPJd9e4iQuRAk=",