feat(crypto): support md5 plain for imported password hashes (#8189)

# Which Problems Are Solved

Allow verification of imported passwords hashed with plain md5, without
salt. These are password digests typically created by one of:

- `printf "password" | md5sum` on most linux systems.
- PHP's `md5("password")`
- Python3's `hashlib.md5(b"password").hexdigest()`

# How the Problems Are Solved

- Upgrade passwap to
[v0.6.0](https://github.com/zitadel/passwap/releases/tag/v0.6.0)
- Add md5plain as a new verfier option in `defaults.yaml`

# Additional Changes

- Updated documentation to explain difference between `md5` (crypt) and
`md5plain` verifiers.

# Additional Context

- Requested by customer for import case
This commit is contained in:
Tim Möhlmann
2024-06-25 11:10:49 +03:00
committed by GitHub
parent bb609b642c
commit dc170dc46e
5 changed files with 28 additions and 10 deletions

View File

@@ -1,7 +1,9 @@
package crypto
import (
"encoding/hex"
"fmt"
"slices"
"strings"
"github.com/mitchellh/mapstructure"
@@ -9,6 +11,7 @@ import (
"github.com/zitadel/passwap/argon2"
"github.com/zitadel/passwap/bcrypt"
"github.com/zitadel/passwap/md5"
"github.com/zitadel/passwap/md5plain"
"github.com/zitadel/passwap/pbkdf2"
"github.com/zitadel/passwap/scrypt"
"github.com/zitadel/passwap/verifier"
@@ -18,7 +21,8 @@ import (
type Hasher struct {
*passwap.Swapper
Prefixes []string
Prefixes []string
HexSupported bool
}
func (h *Hasher) EncodingSupported(encodedHash string) bool {
@@ -27,6 +31,12 @@ func (h *Hasher) EncodingSupported(encodedHash string) bool {
return true
}
}
if h.HexSupported {
_, err := hex.DecodeString(encodedHash)
if err == nil {
return true
}
}
return false
}
@@ -38,6 +48,7 @@ const (
HashNameArgon2id HashName = "argon2id" // hash only
HashNameBcrypt HashName = "bcrypt" // hash and verify
HashNameMd5 HashName = "md5" // verify only, as hashing with md5 is insecure and deprecated
HashNameMd5Plain HashName = "md5plain" // verify only, as hashing with md5 is insecure and deprecated
HashNameScrypt HashName = "scrypt" // hash and verify
HashNamePBKDF2 HashName = "pbkdf2" // hash and verify
)
@@ -69,8 +80,9 @@ func (c *HashConfig) NewHasher() (*Hasher, error) {
return nil, zerrors.ThrowInvalidArgument(err, "CRYPT-Que4r", "password hash config invalid")
}
return &Hasher{
Swapper: passwap.NewSwapper(hasher, verifiers...),
Prefixes: append(hPrefixes, vPrefixes...),
Swapper: passwap.NewSwapper(hasher, verifiers...),
Prefixes: append(hPrefixes, vPrefixes...),
HexSupported: slices.Contains(c.Verifiers, HashNameMd5Plain),
}, nil
}
@@ -95,6 +107,10 @@ var knowVerifiers = map[HashName]prefixVerifier{
prefixes: []string{md5.Prefix},
verifier: md5.Verifier,
},
HashNameMd5Plain: {
prefixes: nil, // hex encoded without identifier or prefix
verifier: md5plain.Verifier,
},
HashNameScrypt: {
prefixes: []string{scrypt.Prefix, scrypt.Prefix_Linux},
verifier: scrypt.Verifier,