mirror of
				https://github.com/zitadel/zitadel.git
				synced 2025-10-31 01:03:55 +00:00 
			
		
		
		
	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:
		| @@ -482,7 +482,8 @@ SystemDefaults: | |||||||
|     Verifiers: # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_VERIFIERS |     Verifiers: # ZITADEL_SYSTEMDEFAULTS_PASSWORDHASHER_VERIFIERS | ||||||
|     #   - "argon2"   # verifier for both argon2i and argon2id. |     #   - "argon2"   # verifier for both argon2i and argon2id. | ||||||
|     #   - "bcrypt" |     #   - "bcrypt" | ||||||
|     #   - "md5" |     #   - "md5"      # md5Crypt with salt and password shuffling. | ||||||
|  |     #   - "md5plain" # md5 digest of a password without salt | ||||||
|     #   - "scrypt" |     #   - "scrypt" | ||||||
|     #   - "pbkdf2"   # verifier for all pbkdf2 hash modes. |     #   - "pbkdf2"   # verifier for all pbkdf2 hash modes. | ||||||
|   SecretHasher: |   SecretHasher: | ||||||
|   | |||||||
| @@ -68,7 +68,8 @@ The following hash algorithms are supported: | |||||||
|  |  | ||||||
| - argon2i / id[^1] | - argon2i / id[^1] | ||||||
| - bcrypt (Default) | - bcrypt (Default) | ||||||
| - md5[^2] | - md5: implementation of md5Crypt with salt and password shuffling [^2] | ||||||
|  | - md5plain: md5 digest of a password without salt [^2] | ||||||
| - scrypt | - scrypt | ||||||
| - pbkdf2 | - pbkdf2 | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @@ -59,7 +59,7 @@ require ( | |||||||
| 	github.com/ttacon/libphonenumber v1.2.1 | 	github.com/ttacon/libphonenumber v1.2.1 | ||||||
| 	github.com/zitadel/logging v0.6.0 | 	github.com/zitadel/logging v0.6.0 | ||||||
| 	github.com/zitadel/oidc/v3 v3.25.0 | 	github.com/zitadel/oidc/v3 v3.25.0 | ||||||
| 	github.com/zitadel/passwap v0.5.0 | 	github.com/zitadel/passwap v0.6.0 | ||||||
| 	github.com/zitadel/saml v0.1.3 | 	github.com/zitadel/saml v0.1.3 | ||||||
| 	github.com/zitadel/schema v1.3.0 | 	github.com/zitadel/schema v1.3.0 | ||||||
| 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 | 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							| @@ -731,8 +731,8 @@ github.com/zitadel/logging v0.6.0 h1:t5Nnt//r+m2ZhhoTmoPX+c96pbMarqJvW1Vq6xFTank | |||||||
| github.com/zitadel/logging v0.6.0/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= | github.com/zitadel/logging v0.6.0/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= | ||||||
| github.com/zitadel/oidc/v3 v3.25.0 h1:DosOUc31IPM9ZtKaT58+0iNicwDFTFk5Ctt7mgYtsA8= | github.com/zitadel/oidc/v3 v3.25.0 h1:DosOUc31IPM9ZtKaT58+0iNicwDFTFk5Ctt7mgYtsA8= | ||||||
| github.com/zitadel/oidc/v3 v3.25.0/go.mod h1:UDwD+PRFbUBzabyPd9JORrakty3/wec7VpKZYi9Ahh0= | github.com/zitadel/oidc/v3 v3.25.0/go.mod h1:UDwD+PRFbUBzabyPd9JORrakty3/wec7VpKZYi9Ahh0= | ||||||
| github.com/zitadel/passwap v0.5.0 h1:kFMoRyo0GnxtOz7j9+r/CsRwSCjHGRaAKoUe69NwPvs= | github.com/zitadel/passwap v0.6.0 h1:m9F3epFC0VkBXu25rihSLGyHvWiNlCzU5kk8RoI+SXQ= | ||||||
| github.com/zitadel/passwap v0.5.0/go.mod h1:uqY7D3jqdTFcKsW0Q3Pcv5qDMmSHpVTzUZewUKC1KZA= | github.com/zitadel/passwap v0.6.0/go.mod h1:kqAiJ4I4eZvm3Y6oAk6hlEqlZZOkjMHraGXF90GG7LI= | ||||||
| github.com/zitadel/saml v0.1.3 h1:LI4DOCVyyU1qKPkzs3vrGcA5J3H4pH3+CL9zr9ShkpM= | github.com/zitadel/saml v0.1.3 h1:LI4DOCVyyU1qKPkzs3vrGcA5J3H4pH3+CL9zr9ShkpM= | ||||||
| github.com/zitadel/saml v0.1.3/go.mod h1:MdkjyU3mwnTuh4lNnhPG+RyZL/VfzD72wUG/eWWBaXc= | github.com/zitadel/saml v0.1.3/go.mod h1:MdkjyU3mwnTuh4lNnhPG+RyZL/VfzD72wUG/eWWBaXc= | ||||||
| github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0= | github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0= | ||||||
|   | |||||||
| @@ -1,7 +1,9 @@ | |||||||
| package crypto | package crypto | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"encoding/hex" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"slices" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/mitchellh/mapstructure" | 	"github.com/mitchellh/mapstructure" | ||||||
| @@ -9,6 +11,7 @@ import ( | |||||||
| 	"github.com/zitadel/passwap/argon2" | 	"github.com/zitadel/passwap/argon2" | ||||||
| 	"github.com/zitadel/passwap/bcrypt" | 	"github.com/zitadel/passwap/bcrypt" | ||||||
| 	"github.com/zitadel/passwap/md5" | 	"github.com/zitadel/passwap/md5" | ||||||
|  | 	"github.com/zitadel/passwap/md5plain" | ||||||
| 	"github.com/zitadel/passwap/pbkdf2" | 	"github.com/zitadel/passwap/pbkdf2" | ||||||
| 	"github.com/zitadel/passwap/scrypt" | 	"github.com/zitadel/passwap/scrypt" | ||||||
| 	"github.com/zitadel/passwap/verifier" | 	"github.com/zitadel/passwap/verifier" | ||||||
| @@ -19,6 +22,7 @@ import ( | |||||||
| type Hasher struct { | type Hasher struct { | ||||||
| 	*passwap.Swapper | 	*passwap.Swapper | ||||||
| 	Prefixes     []string | 	Prefixes     []string | ||||||
|  | 	HexSupported bool | ||||||
| } | } | ||||||
|  |  | ||||||
| func (h *Hasher) EncodingSupported(encodedHash string) bool { | func (h *Hasher) EncodingSupported(encodedHash string) bool { | ||||||
| @@ -27,6 +31,12 @@ func (h *Hasher) EncodingSupported(encodedHash string) bool { | |||||||
| 			return true | 			return true | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if h.HexSupported { | ||||||
|  | 		_, err := hex.DecodeString(encodedHash) | ||||||
|  | 		if err == nil { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	return false | 	return false | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -38,6 +48,7 @@ const ( | |||||||
| 	HashNameArgon2id HashName = "argon2id" // hash only | 	HashNameArgon2id HashName = "argon2id" // hash only | ||||||
| 	HashNameBcrypt   HashName = "bcrypt"   // hash and verify | 	HashNameBcrypt   HashName = "bcrypt"   // hash and verify | ||||||
| 	HashNameMd5      HashName = "md5"      // verify only, as hashing with md5 is insecure and deprecated | 	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 | 	HashNameScrypt   HashName = "scrypt"   // hash and verify | ||||||
| 	HashNamePBKDF2   HashName = "pbkdf2"   // hash and verify | 	HashNamePBKDF2   HashName = "pbkdf2"   // hash and verify | ||||||
| ) | ) | ||||||
| @@ -71,6 +82,7 @@ func (c *HashConfig) NewHasher() (*Hasher, error) { | |||||||
| 	return &Hasher{ | 	return &Hasher{ | ||||||
| 		Swapper:      passwap.NewSwapper(hasher, verifiers...), | 		Swapper:      passwap.NewSwapper(hasher, verifiers...), | ||||||
| 		Prefixes:     append(hPrefixes, vPrefixes...), | 		Prefixes:     append(hPrefixes, vPrefixes...), | ||||||
|  | 		HexSupported: slices.Contains(c.Verifiers, HashNameMd5Plain), | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -95,6 +107,10 @@ var knowVerifiers = map[HashName]prefixVerifier{ | |||||||
| 		prefixes: []string{md5.Prefix}, | 		prefixes: []string{md5.Prefix}, | ||||||
| 		verifier: md5.Verifier, | 		verifier: md5.Verifier, | ||||||
| 	}, | 	}, | ||||||
|  | 	HashNameMd5Plain: { | ||||||
|  | 		prefixes: nil, // hex encoded without identifier or prefix | ||||||
|  | 		verifier: md5plain.Verifier, | ||||||
|  | 	}, | ||||||
| 	HashNameScrypt: { | 	HashNameScrypt: { | ||||||
| 		prefixes: []string{scrypt.Prefix, scrypt.Prefix_Linux}, | 		prefixes: []string{scrypt.Prefix, scrypt.Prefix_Linux}, | ||||||
| 		verifier: scrypt.Verifier, | 		verifier: scrypt.Verifier, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Tim Möhlmann
					Tim Möhlmann