Skip to content

Fix CRAM-MD5 authentication with non-ASCII secrets - #109

Open
afurm wants to merge 1 commit into
ruby:masterfrom
afurm:fix-cram-md5-non-ascii-secret
Open

afurm wants to merge 1 commit into
ruby:masterfrom
afurm:fix-cram-md5-non-ascii-secret

Conversation

@afurm

@afurm afurm commented Oct 22, 2026

Copy link
Copy Markdown
Member

authtype: :cram_md5 fails as soon as the password has a non-ASCII character:

Net::SMTP.start("mail.example.com", 587, user: "me", password: "pässwörd", authtype: :cram_md5) { }
# => Encoding::CompatibilityError: incompatible character encodings: UTF-8 and BINARY (ASCII-8BIT)

cram_secret XORs the secret character by character and then appends the binary challenge and digest to it, so a UTF-8 secret with multibyte characters can't be combined with them. It also compares secret.size (characters) with the 64-byte HMAC block size, so a secret of 33 to 64 characters that is longer than 64 bytes wasn't hashed first as RFC 2104 requires.

This converts the secret to bytes before building the pads and checks bytesize, so the response is the plain HMAC-MD5 from RFC 2195. ASCII secrets give the same result as before.

I added a test with the RFC 2195 example and compared non-ASCII and long secrets against OpenSSL::HMAC. The new test fails on master with the error above, and bundle exec rake test passes.

cram_secret mixed the UTF-8 secret with the binary challenge and digest,
which raised Encoding::CompatibilityError, and it compared the character
count (not the byte count) against the 64 byte HMAC block size.

Work on the secret's bytes so the response matches HMAC-MD5 per RFC 2195.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant