mirror of
https://github.com/mattermost/mattermost.git
synced 2026-02-18 18:18:23 -05:00
MM-64522: Use PBKDF2 as the new key derivation for remote cluster invitation (#33493)
https://mattermost.atlassian.net/browse/MM-64522 ```release-note NONE ```
This commit is contained in:
parent
14c67d4a60
commit
bc859d7fb0
4 changed files with 79 additions and 9 deletions
|
|
@ -202,7 +202,7 @@ func (a *App) CreateRemoteClusterInvite(remoteId, siteURL, token, password strin
|
|||
RemoteId: remoteId,
|
||||
SiteURL: siteURL,
|
||||
Token: token,
|
||||
Version: 2,
|
||||
Version: 3,
|
||||
}
|
||||
|
||||
if err := invite.IsValid(); err != nil {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ func makeConfirmFrame(rc *model.RemoteCluster, siteURL string) (*model.RemoteClu
|
|||
SiteURL: siteURL,
|
||||
Token: rc.Token,
|
||||
RefreshedToken: rc.RemoteToken,
|
||||
Version: 2,
|
||||
Version: 3,
|
||||
}
|
||||
confirmRaw, err := json.Marshal(confirm)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base32"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
|
@ -17,6 +18,7 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
)
|
||||
|
||||
|
|
@ -401,9 +403,16 @@ func (rci *RemoteClusterInvite) Encrypt(password string) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
key, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var key []byte
|
||||
if rci.Version >= 3 {
|
||||
// Use PBKDF2 for version 3 and above
|
||||
key = pbkdf2.Key([]byte(password), salt, 100000, 32, sha256.New)
|
||||
} else {
|
||||
// Use scrypt for older versions
|
||||
key, err = scrypt.Key([]byte(password), salt, 32768, 8, 1, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key[:])
|
||||
|
|
@ -437,9 +446,28 @@ func (rci *RemoteClusterInvite) Decrypt(encrypted []byte, password string) error
|
|||
salt := encrypted[:16]
|
||||
encrypted = encrypted[16:]
|
||||
|
||||
key, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
// Try PBKDF2 first (for version 3+)
|
||||
if err := rci.tryDecrypt(encrypted, password, salt, true); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fall back to scrypt (for older versions)
|
||||
return rci.tryDecrypt(encrypted, password, salt, false)
|
||||
}
|
||||
|
||||
func (rci *RemoteClusterInvite) tryDecrypt(encrypted []byte, password string, salt []byte, usePBKDF2 bool) error {
|
||||
var key []byte
|
||||
var err error
|
||||
|
||||
if usePBKDF2 {
|
||||
// Use PBKDF2 for version 3 and above
|
||||
key = pbkdf2.Key([]byte(password), salt, 100000, 32, sha256.New)
|
||||
} else {
|
||||
// Use scrypt for older versions
|
||||
key, err = scrypt.Key([]byte(password), salt, 32768, 8, 1, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key[:])
|
||||
|
|
|
|||
|
|
@ -158,13 +158,55 @@ func TestRemoteClusterInviteEncryption(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRemoteClusterInviteBackwardCompatibility(t *testing.T) {
|
||||
// Test that we can decrypt invites created with the old scrypt method
|
||||
oldInvite := RemoteClusterInvite{
|
||||
RemoteId: NewId(),
|
||||
SiteURL: "https://example.com:8065",
|
||||
Token: NewId(),
|
||||
RefreshedToken: NewId(),
|
||||
Version: 2, // Old version using scrypt
|
||||
}
|
||||
|
||||
password := "test password"
|
||||
|
||||
// Encrypt with old method (scrypt)
|
||||
encrypted, err := oldInvite.Encrypt(password)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Decrypt should work with backward compatibility
|
||||
decryptedInvite := RemoteClusterInvite{}
|
||||
err = decryptedInvite.Decrypt(encrypted, password)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, oldInvite, decryptedInvite)
|
||||
|
||||
// Test new version (PBKDF2)
|
||||
newInvite := RemoteClusterInvite{
|
||||
RemoteId: NewId(),
|
||||
SiteURL: "https://example.com:8065",
|
||||
Token: NewId(),
|
||||
RefreshedToken: NewId(),
|
||||
Version: 3, // New version using PBKDF2
|
||||
}
|
||||
|
||||
// Encrypt with new method (PBKDF2)
|
||||
encrypted, err = newInvite.Encrypt(password)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Decrypt should work
|
||||
decryptedInvite = RemoteClusterInvite{}
|
||||
err = decryptedInvite.Decrypt(encrypted, password)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newInvite, decryptedInvite)
|
||||
}
|
||||
|
||||
func makeInvite(url string) RemoteClusterInvite {
|
||||
return RemoteClusterInvite{
|
||||
RemoteId: NewId(),
|
||||
SiteURL: url,
|
||||
Token: NewId(),
|
||||
RefreshedToken: NewId(),
|
||||
Version: 2,
|
||||
Version: 3,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue