< draft-newman-auth-scram-00.txt   draft-newman-auth-scram-01.txt >
Network Working Group C. Newman Network Working Group C. Newman
Internet Draft: SCRAM-SHA1 SASL Mechanism Innosoft Internet Draft: SCRAM-MD5 SASL Mechanism Innosoft
Document: draft-newman-auth-scram-00.txt September 1997 Document: draft-newman-auth-scram-01.txt October 1997
Expires in six months Expires in six months
Salted Challenge Response Authentication Mechanism (SCRAM) Salted Challenge Response Authentication Mechanism (SCRAM)
Status of this memo Status of this memo
This document is an Internet-Draft. Internet-Drafts are working This document is an Internet-Draft. Internet-Drafts are working
documents of the Internet Engineering Task Force (IETF), its areas, documents of the Internet Engineering Task Force (IETF), its areas,
and its working groups. Note that other groups may also distribute and its working groups. Note that other groups may also distribute
working documents as Internet-Drafts. working documents as Internet-Drafts.
skipping to change at page 1, line 31 skipping to change at page 1, line 31
progress." progress."
To view the entire list of current Internet-Drafts, please check To view the entire list of current Internet-Drafts, please check
the "1id-abstracts.txt" listing contained in the Internet-Drafts the "1id-abstracts.txt" listing contained in the Internet-Drafts
Shadow Directories on ftp.is.co.za (Africa), ftp.nordu.net Shadow Directories on ftp.is.co.za (Africa), ftp.nordu.net
(Europe), munnari.oz.au (Pacific Rim), ds.internic.net (US East (Europe), munnari.oz.au (Pacific Rim), ds.internic.net (US East
Coast), or ftp.isi.edu (US West Coast). Coast), or ftp.isi.edu (US West Coast).
Abstract Abstract
SCRAM is a simple passphrase-based authentication mechanism which SCRAM is a simple passphrase-based authentication mechanism
uses only a publicly available cryptographic hash function to suitable for a wide variety of usage scenarios. It combines the
provide authentication for protocols. It is designed to replace best properties of CRAM-MD5 [CRAM-MD5] and OTP [OTP] without a
plaintext password mechanisms without significant additional significant increase in complexity.
complexity, loss of performance or plaintext equivalent verifiers.
CRAM-MD5 [CRAM-MD5], a similar mechanism, has the drawback that the This document defines the SCRAM-MD5 SASL mechanism [SASL] using the
password verifier stored on the server can be used to impersonate MD5 [MD5] and HMAC-MD5 [HMAC] algorithms. It is suitable for use
the user. Current plaintext password mechanisms do not have this directly with protocols such as IMAP [IMAP4] and POP [POP3].
drawback and it is a serious issue for servers which allow remote
login or sites which distribute the authentication database to
multiple servers via an insecure protocol. SCRAM-SHA1 corrects
this drawback with minimal additional complexity.
This document defines the SCRAM-SHA1 SASL mechanism [SASL] using 0. Changes from Previous Version
the SHA1 [SHA1] and HMAC-SHA1 [HMAC] algorithms.
0. Open Issues (1) MD5 is used instead of SHA1 as it permits backwards-
compatibility with CRAM-MD5 verifiers on the server and it is a
more commonly available hash function. This should not effect
SCRAM's security significantly.
(1) Although this mechanism has no new concepts, it has not had (2) The server-proof is now independent of the client-verifier.
extensive review. Advice on the completeness of the security This allows a remote authentication service to efficiently restrict
considerations is appreciated. the services an application server may offer to clients.
(2) The TWEKE proposal (appendix B) is more secure and more (3) The salt is included in the client-key which means that a
complex. Is it an acceptable or desirable tradeoff? Perhaps SCRAM compromised verifier and client-server exchange only gains access
could get 40% penetration into the plaintext market and TWEKE could to services which use the same salt.
get 30%, would it be worthwhile to do TWEKE instead of SCRAM in
this case? What if there's a bigger difference?
1. Conventions Used in this Document (4) The service identifier is simplified and separated from the
extension data which now has defined syntax.
(5) The client-nonce may be omitted for one-way authentication.
(6) Examples and sample source code has been added.
1. How to Read This Document
This document has information for several different audiences.
Section 2 describes the highlights of SCRAM. Sections 3-6 are
intended for implementors. Section 7 is intended for system
administrators. Sections 7-10 are intended for security
evaluation.
The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
in this document are to be interpreted as defined in "Key words for in this document are to be interpreted as defined in "Key words for
use in RFCs to Indicate Requirement Levels" [KEYWORDS]. use in RFCs to Indicate Requirement Levels" [KEYWORDS].
2. Client Implementation of SCRAM-SHA1 2. SCRAM Highlights
SCRAM is a simple passphrase-based mechanism, which does not
require complicated public key technology. It can be implemented
in a few pages of source code.
SCRAM is not plaintext equivalent, so it improves network security
over plaintext mechanisms without sacrificing security of the
authentication database.
SCRAM includes a salt to prevent global dictionary attacks on the
server's authentication database.
SCRAM supports proxy authentication by including an authorization
identity (user to login as) separate from the authentication
identity (server authentication database entry to use).
SCRAM supports optional mutual authentication.
SCRAM supports limited server trust. This means a centralized
authentication server can restrict the services offered by
application servers.
SCRAM-MD5 is backwards-compatible with existing CRAM-MD5 verifiers
stored in server authentication databases.
3. Client Implementation of SCRAM-MD5
This section includes a step-by-step guide for client implementors. This section includes a step-by-step guide for client implementors.
Although section 7 contains the formal definition of the syntax and Although section 6 contains the formal definition of the syntax and
is the authoritative reference in case of errors here, this section is the authoritative reference in case of errors here, this section
should be sufficient to build a correct implementation. should be sufficient to build a correct implementation.
When used with SASL the mechanism name is "SCRAM-SHA1". The When used with SASL the mechanism name is "SCRAM-MD5". The
mechanism does not provide a security layer. mechanism does not provide a security layer.
The client begins by sending a message to the server containing The client begins by sending a message to the server containing the
three pieces of information: following three pieces of information. The entire message MUST NOT
exceed 1000 characters.
(1) An authorization identity. When the empty string is used, this (1) An authorization identity. When the empty string is used, this
defaults to the authentication identity. This is used by system defaults to the authentication identity. This is used by system
administrators or proxy servers to login with a different user administrators or proxy servers to login with a different user
identity. This field may be up to 255 octets and is terminated by identity. This field may be up to 255 octets and is terminated by
a NUL (0) octet. US-ASCII printable characters are preferred, a NUL (0) octet. US-ASCII printable characters are preferred,
although UTF-8 [UTF-8] printable characters are permitted to although UTF-8 [UTF-8] printable characters are permitted to
support international names. Use of character sets other than support international names. Use of character sets other than
US-ASCII and UTF-8 is forbidden. US-ASCII and UTF-8 is forbidden.
(2) An authentication identity. The identity whose passphrase will (2) An authentication identity. The identity whose passphrase will
be used. This field may be up to 255 octets and is terminated by a be used. This field may be up to 255 octets and is terminated by a
NUL (0) octet. US-ASCII printable characters are preferred, NUL (0) octet. US-ASCII printable characters are preferred,
although UTF-8 [UTF-8] printable characters are permitted to although UTF-8 [UTF-8] printable characters are permitted to
support international names. Use of character sets other than support international names. Use of character sets other than
US-ASCII and UTF-8 is forbidden. US-ASCII and UTF-8 is forbidden.
(3) A "client nonce" of 8 to 256 octets. It is important that this (3) An optional "client nonce." If this is omitted, it indicates a
be globally unique and somewhat random. It can be generated by desire for client-only authentication. When present, it is
appending the system clock to a random number (advice for important that this be globally unique. One common technique for
generating good random numbers can be found in [RANDOM]) and the generating globally unique identifiers combines a process
client's IP address or domain name. identifier with the system clock, a sequence number, a random
number and the client's domain name. The random number is
important as clocks are often synchronized using insecure
protocols. Advice for generating strong random numbers can be
found in [RANDOM].
The server responds by sending a message containing three pieces of The server responds by sending a message containing three pieces of
information: information. The entire message MUST NOT exceed 1000 characters.
(4) An 8-octet salt value, specific to the authentication identity. (4) An 8-octet salt value, specific to the authentication identity.
(5) A server id consisting of the service name of the protocol's (5) A service id consisting of the service name of the protocol's
SASL profile followed by a "." followed by the domain name of the SASL profile followed by an "@" followed by the domain name of the
server followed by an "@" and optional extension data terminated by server and terminated by NUL. The client SHOULD verify this is
NUL. This will not be longer than 512 octets. The client SHOULD correct.
verify this is correct.
(6) A "server nonce" of 8 to 32 octets. (6) A string containing extension data, terminated by NUL. A
client which supports TLS [TLS] or stronger SASL mechanisms can
check this to protect against an active downgrade attack. A server
which supports TLS or stronger SASL mechanisms SHOULD advertise
them here.
(7) A "server nonce".
The client then does the following: The client then does the following:
(A) Create a buffer containing the user's passphrase. The client (A) Create a buffer containing the user's passphrase. The client
MUST support passphrases of at least 64 octets. US-ASCII MUST support passphrases of at least 64 octets. US-ASCII
characters are preferred, although UTF-8 characters are permitted. characters are preferred, although UTF-8 characters are permitted.
Character sets other than UTF-8 MUST NOT be used. Character sets other than UTF-8 MUST NOT be used.
(B) Apply the SHA1 function to (A), producing a 20 octet result. (B) Apply the HMAC-MD5 function with (A) as the key and the 8-octet
Once this is done, (A) SHOULD be erased from memory. salt as the data, producing a 16-octet result. Once this is done,
(A) SHOULD be erased from memory.
(C) Apply the HMAC-SHA1 function with the result of (B) as the key (C) Apply the MD5 function to the result of (B). This produces a
and the 8-octet salt (4) value as the data. This produces a 20 16-octet result.
octet result.
(D) Create a buffer containing the server's response (4)-(6), (D) Apply the MD5 function to the result of (C). This produces a
16-octet result.
(E) Create a buffer containing the server's response (4)-(7),
immediately followed by the initial client message (1)-(3). immediately followed by the initial client message (1)-(3).
(E) Apply the HMAC-SHA1 function with the result of (C) as the key (F) Apply the HMAC-MD5 function with the result of (D) as the key
and the buffer from (D) as the data. This produces a 20-octet and the buffer from (E) as the data. This produces a 16-octet
result. result.
(F) Create a 20-octet buffer containing the exclusive-or of (B) and (G) Create a 16-octet buffer containing the exclusive-or of (C) and
(E). (F).
The client then sends a message to the server containing the The client then sends a message to the server containing the
following: following:
(7) The 20-octet result of step (F). (8) The 16-octet result of step (G).
If authentication is successful, then the server responds with the If no client challenge was suppled in step 3, the one-way
following: authentication is now complete.
(8) A 20-octet mutual authentication verifier. (9) A 16-octet server authentication verifier.
The client SHOULD verify this with the following procedure: The client SHOULD verify this with the following procedure:
(G) Create a buffer containing the initial client message (1)-(3) (H) Apply the HMAC-MD5 function with the result of (B) as the key
immediately followed by the initial server response (4)-(6). and the 8-octet salt as the data. This produces a 16-octet result.
(H) Apply the HMAC-SHA1 function with the result of (C) as the key (I) Create a buffer containing the initial client message (1)-(3)
and the buffer from (G) as the data. immediately followed by the initial server response (4)-(7).
(I) If the result of (H) matches (8), the server is authenticated. (J) Apply the HMAC-MD5 function with the result of (H) as the key
and the buffer from (I) as the data.
A secured client MAY store the result of (B) to re-authenticate. (K) If the result of (J) matches (9), the server is authenticated.
Permanent storage of (B) by the client is discouraged although it
is preferable to storing the actual passphrase.
3. Server Implementation of SCRAM-SHA1. A secured client MAY store the result of (B) to re-authenticate to
services using the same salt, or the intermediate HMAC state from
(B) to re-authenticate to any service. Clients SHOULD NOT store
the passphrase itself.
4. Server Implementation of SCRAM-MD5.
The section includes a step-by-step guide for server implementors. The section includes a step-by-step guide for server implementors.
Although section 7 contains the formal definition of the syntax and Although section 6 contains the formal definition of the syntax and
is the authoritative reference in case of errors here, this section is the authoritative reference in case of errors here, this section
in conjunction with section 2 should be sufficient to build a in conjunction with section 3 should be sufficient to build a
correct implementation. correct implementation.
The server's authentication database contains an 8-octet salt and The server's authentication database contains an 8-octet salt, 16-
20-octet verifier for each local user. The server MAY support octet client verifier and a 16-octet server key for each local
remote users using the syntax "user@host" for the authentication user. The server MUST support "user@host" syntax for the
identity, but if it doesn't it MUST truncate the authentication authentication identity at least to the extent of stripping "@host"
identity at the "@" sign prior to lookup in the authentication when it matches the local hostname or rejecting the authentication
database. immediately after the initial client message if the hostname
doesn't match. The server MAY support remote user authentication
using this syntax.
The authentication verifier is equal to the result of step (C) The stored client verifier is equal to the result of step (D)
above, and the stored server key is equal to the result of step (J)
above. To create its initial response, the server simply looks up above. To create its initial response, the server simply looks up
the authentication identity to fetch the salt, and generates an 8 the authentication identity to fetch the salt, and generates an 8
to 32 octet nonce. This nonce MUST be unique to prevent replay to 248 octet nonce. This nonce MUST be unique to prevent replay
attacks. It can be generated by appending a system clock to a attacks. It can be generated by appending a system clock to a
random number [RANDOM]. To verify the client's credentials, the random number [RANDOM]. To verify the client's credentials, the
server preforms the following steps: server preforms the following steps:
(a) Generate a buffer identical to step (D) for the client. (a) Generate a buffer identical to step (E) above.
(b) Apply the HMAC-SHA1 function with the stored verifier as the (b) Apply the HMAC-MD5 function with the stored client verifier as
key and the result of (a) as the data. This produces a 20-octet the key and the result of (a) as the data. This produces a 16-
result equal to step (E) above. octet result equal to step (F) above.
(c) Exclusive-or the result of (b) with message (7) from the (c) Exclusive-or the result of (b) with message (8) from the
client. This produces a 20-octet result which should be equal to client. This produces a 16-octet result which should be equal to
the output of step (B) above. the result of step (C) above.
(d) Apply the HMAC-SHA1 function with (c) as the key and the stored (d) Apply the MD5 function to the output of step (c). This
salt as the data. This produces a 20-octet result. produces a 16-octet result which should be equal to the result of
step (D) above.
(e) if the result of (d) is equal to the stored verifier, then the (e) if the result of (d) is equal to the stored verifier, then the
user is authenticated. user is authenticated.
(f) Generate a buffer identical to step (G) above. If no client challenge was provided in step (3), the server is now
done and responds with the appropriate status code.
(g) Apply the HMAC-SHA1 function with the stored verifier as the
key and the buffer from (f) as the data. This produces a 20-octet
result.
The result of (g) is sent to the client as the mutual
authentication step.
4. Example
XXX: to be done
5. System Administrator Advice
This section includes advice for system administrators using this
mechanism.
Although the verifiers used by SCRAM-SHA1 are probably more secure
than those used by current plaintext mechanisms (such as Unix
/etc/password), it is still very important to keep them secret.
Just as tools exist to try common passwords against Unix
/etc/password files, it is also possible to build such tools for
SCRAM-SHA1. In addition, once a SCRAM-SHA1 verifier is stolen, a
passive (undetectable) snoop of that user logging in will result in
the output of step (B) above, which is sufficient to impersonate a
user. This is far better than current plaintext mechanisms where a
passive snoop always recovers the user's password, but is still a
serious concern.
Verifiers SHOULD be kept hidden from all users on the server.
Sites which distribute verifiers among multiple servers, SHOULD
encrypt them when distributing them.
SCRAM-SHA1 is only a good mechanism if passphrases are well chosen.
For this reason, implementations should use the term "passphrase"
rather than "password" and when a user's passphrase is set, site
policy restrictions should be applied. A reasonable site policy
would require passphrases of at least 10 characters with at least
one non-alphanumeric character.
SCRAM-SHA1 doesn't protect the integrity or privacy of data
exchanged after authentication. Use of an external encryption
layer or a stronger authentication mechanism such as Kerberos is
encouraged if this functionality is needed.
6. SCRAM-SHA1 Functional Notation
This section is designed to provide a quick understanding of
SCRAM-SHA1 for the mathematically inclined.
+ octet concatenation
XOR the exclusive-or function
AU is the authentication user identity (NUL terminated)
AZ is the authorization user identity (NUL terminated)
if AZ would be the same as AU, a single NUL is used instead.
SV is the name of the service and server
p is the plaintext passphrase
H(x) is a one-way hash function applied to "x", such as SHA-1
M(x,y) is a message authentication code (MAC) such as HMAC-SHA1
"y" is the key and "x" is the text signed by the key.
V is a per-user verifier the server stores
s is a per-user salt value the server stores
P is the proof the client sends the server
Us is a unique nonce the server sends to the client
Uc is a unique nonce the client sends to the server
The verifier (V) is computed by applying the hash function to the (f) Generate a buffer identical to step (I) above.
plaintext passphrase, then using the result to sign the salt.
Thus:
V = M(s, H(p)) (g) Apply the HMAC-MD5 function with the stored verifier as the key
and the buffer from (f) as the data. This produces a 16-octet
result.
The proof (P) is computed as follows: The result of (g) is sent to the client to authenticate the server.
P = H(p) XOR M(s + SV + Us + AZ + AU + Uc, V) 5. Example
The SCRAM exchange is as follows: The following is an example of the SCRAM-MD5 mechanism using the
IMAP [IMAP4] profile of SASL. Note that base64 encoding and the
lack of an initial client reponse with the first command are
characteristics of the IMAP profile of SASL and not characteristics
of SASL or SCRAM-MD5.
client -> server: AZ + AU + Uc In this example, "C:" represents lines sent from the client to the
server -> client: s + SV + Us server and "S:" represents lines sent from the server to the
client -> server: P client. The wrapped lines are for editorial clarity -- there are
server -> client: M(AZ + AU + Uc + s + SV + Us, V) no actual newlines in the middle of the messages.
The server verifies P by checking that the following is equal to V:
M(s, P XOR M(s + SV + Us + AZ + AU + Uc, V)) C: a001 AUTHENTICATE SCRAM-MD5
S: +
C: AGNocmlzADxwNVIxZTBWTzNLdFZBNEZITDdudWRRQGVsZWFub3Iua
W5ub3NvZnQuY29tPg==
S: AeYw5Ugm+blpbWFwQGVsZWFub3IuaW5ub3NvZnQuY29tAAA8b1JNa
nFFekYvL1J5WnhFMlF2cDNzd0BlbGVhbm9yLmlubm9zb2Z0LmNvbT4=
C: 5cZpsA9pODOVwuNU1xmJHA==
S: a001 OK [vJ1FEfRHulPALMwSb/UC9g==] AUTHENTICATE completed
The client verifies the server's identity by performing the same For this example, the user "chris", with an empty authorization
computation the server does and comparing it to the server's identity is using the passphrase "secret stuff". The client nonce
result. is "<p5R1e0VO3KtVA4FHL7nudQ@eleanor.innosoft.com>" and the server
nonce is "<oRMjqEzF//RyZxE2Qvp3sw@eleanor.innosoft.com>". The
service identity is "imap@eleanor.innosoft.com" and the server
extension data is empty. The salt, in hexidecimal, is "01e6 30e5
4826 f9b9". The complete 40 octet verifier stored on the server,
in base64, is
"AeYw5Ugm+bkHTj2Ouau2II2etDOwYVEXkVsKPP0Q6pV9hbFaweymdg", and in
hexidecimal it is "01e6 30e5 4826 f9b9 074e 3d8e b9ab b620 8d9e
b433 b061 5117 915b 0a3c fd10 ea95 7d85 b15a c1ec a676".
7. Formal Syntax of SCRAM-SHA1 Messages 6. Formal Syntax of SCRAM-MD5 Messages
This is the formal syntactic definition of the client and server This is the formal syntactic definition of the client and server
messages. This uses the ABNF [ABNF] notation. messages. This uses ABNF [ABNF] notation.
client-msg-1 = [authorize-id] NUL authenticate-id NUL client-nonce client-msg-1 = [authorize-id] NUL authenticate-id NUL [nonce]
;; MUST NOT exceed 1000 octets
server-msg-1 = salt server-id NUL server-nonce server-msg-1 = salt service-id NUL server-ext-data NUL nonce
;; MUST NOT exceed 1000 octets
client-msg-2 = proof client-msg-2 = client-proof
server-msg-2 = mutual-auth server-msg-2 = server-proof
passphrase = 8*UTF8-SAFE passphrase = *UTF8-SAFE
;; At least 64 octets MUST be supported ;; At least 64 octets MUST be supported
authorize-id = *UTF8-PRINT authorize-id = *UTF8-PRINT
;; No more than 255 octets ;; No more than 255 octets
authenticate-id = *UTF8-PRINT authenticate-id = *UTF8-PRINT
;; No more than 255 octets ;; No more than 255 octets
server-id = service-name "." server-domain service-id = service-name "@" server-domain
"@" [ server-ext-data ]
;; No more that 511 octets total
service-name = *USASCII-PRINT service-name = *US-ASCII-PRINT
;; a GSSAPI service name ;; a SASL/GSSAPI service name
server-domain = *USASCII-PRINT server-domain = *US-ASCII-PRINT
;; an internet domain name ;; an internet domain name
server-ext-data = *UTF8-SAFE server-ext-data = *(sasl-mech-list / tls-avail / ext-list)
;; extension data
server-id = *UTF8-PRINT sasl-mech-list = "SASL:" *(CFWS sasl-mech) CRLF
;; No more than 511 octets
client-nonce = 8*256OCTET CFWS = [CRLF] 1*SPACE
server-nonce = 8*32OCTET sasl-mech = 1*20(ALPHA / DIGIT / "-" / "_")
tls-avail = "TLS:" SPACE "yes"
ext-list = 1*UTF8PRINT ":" *(CFWS 1*UTF8PRINT) CRLF
nonce = 8*OCTET
salt = 8OCTET salt = 8OCTET
proof = 20OCTET client-proof = 16OCTET
mutual-auth = 20OCTET server-proof = 16OCTET
NUL = %x00 ;; US-ASCII NUL character NUL = %x00 ;; US-ASCII NUL character
US-ASCII-SAFE = %x01-09 / %x0B-0C / %x0E-7F US-ASCII-SAFE = %x01-09 / %x0B-0C / %x0E-7F
;; US-ASCII except CR, LF, NUL ;; US-ASCII except CR, LF, NUL
US-ASCII-PRINT = %x20-7E US-ASCII-PRINT = %x20-7E
;; printable US-ASCII including SPACE ;; printable US-ASCII including SPACE
UTF8-SAFE = US-ASCII-SAFE / UTF8-1 / UTF8-2 / UTF8-3 UTF8-SAFE = US-ASCII-SAFE / UTF8-1 / UTF8-2 / UTF8-3
/ UTF8-4 / UTF8-5 / UTF8-4 / UTF8-5
UTF8-PRINT = US-ASCII-PRINT / UTF8-1 / UTF8-2 / UTF8-3 UTF8-PRINT = US-ASCII-PRINT / UTF8-1 / UTF8-2 / UTF8-3
/ UTF8-4 / UTF8-5 / UTF8-4 / UTF8-5
UTF8-CONT = %x80..BF UTF8-CONT = %x80..BF
UTF8-1 = %xC0..DF UTF8-CONT UTF8-1 = %xC0..DF UTF8-CONT
UTF8-2 = %xE0..EF 2UTF8-CONT UTF8-2 = %xE0..EF 2UTF8-CONT
UTF8-3 = %xF0..F7 3UTF8-CONT UTF8-3 = %xF0..F7 3UTF8-CONT
UTF8-4 = %xF8..FB 4UTF8-CONT UTF8-4 = %xF8..FB 4UTF8-CONT
UTF8-5 = %xFC..FD 5UTF8-CONT UTF8-5 = %xFC..FD 5UTF8-CONT
8. Security Considerations 7. System Administrator Advice
This section includes advice for system administrators using this
mechanism.
SCRAM stores three pieces of information for each user: a salt, a
client verifier and server key. The latter two are derived from
the salt and the user's passphrase.
The salt prevents global dictionary attacks, similar to the salt
used in Unix /etc/passwd files. As the 12 bits of salt in Unix
/etc/passwd has proved to be insufficient, SCRAM uses 64 bits of
salt. See [SCHNEIER] for a good discussion of salt and dictionary
attacks. In a multi-server site, security can be increased by
using a different salt on each server.
Although the verifiers used by SCRAM-MD5 have roughly comparable
security to those used by current plaintext mechanisms (such as
Unix /etc/passwd), it is still very important to keep them secret.
Just as tools exist to try common passwords against Unix
/etc/passwd files, it is also possible to build such tools for
SCRAM-MD5. In addition, once a SCRAM-MD5 verifier is stolen, a
passive (undetectable) evesdropper of that user logging in gains
the output of step (C) above, which is sufficient to impersonate
the user to all services with the same salt. This is far better
than current plaintext mechanisms where a passive evesdropper
always recovers the user's password, but is still a serious
concern.
Verifiers SHOULD be kept hidden from all users on the server.
Sites which distribute verifiers among multiple servers, SHOULD
encrypt them when distributing them.
SCRAM-MD5 is only a good mechanism if passphrases are well chosen.
For this reason, implementations should use the term "passphrase"
rather than "password" and when a user's passphrase is set, site
policy restrictions should be applied. A reasonable site policy
would require passphrases of at least 10 characters with at least
one non-alphanumeric character.
SCRAM-MD5 doesn't protect the integrity or privacy of data
exchanged after authentication. Use of TLS [TLS] or a stronger
SASL mechanism such as Kerberos is encouraged if this functionality
is needed.
8. SCRAM-MD5 Functional Notation
This section is designed to provide a quick understanding of
SCRAM-MD5 for those who like functional notation.
+ octet concatenation
XOR the exclusive-or function
AU is the authentication user identity (NUL terminated)
AZ is the authorization user identity (NUL terminated)
if AZ is the same as AU, a single NUL is used instead.
service is the name of the service and server (NUL terminated)
ext-attr server extension attributes (NUL terminated)
pass is the plaintext passphrase
H(x) is a one-way hash function applied to "x", such as MD5
MAC(x,y) is a message authentication code (MAC) such as HMAC-MD5
"y" is the key and "x" is the text signed by the key.
salt is a per-user salt value the server stores
Us is a unique nonce the server sends to the client
Uc is a unique nonce the client sends to the server
The following computed values are used in the exchange:
client-chal = AZ + AU + Uc
server-chal = salt + service + ext-attr + Us
salted-pass = MAC(salt, pass)
client-key = H(salted-pass)
client-verifier = H(client-key)
shared-key = MAC(server-chal + client-chal, client-verifier)
client-proof = client-key XOR shared-key
server-key = MAC(salt, salted-pass)
server-proof = MAC(client-chal + server-chal, server-key)
The SCRAM exchange is as follows:
(1) client -> server: client-chal
(2) server -> client: server-chal
(3) client -> server: client-proof
(4) server -> client: server-proof
The server stores the salt, client-verifier and server-key. It
authenticates the client by computing:
H(client-proof XOR shared-key)
after step 3 and comparing it to the stored client-verifier.
The client verifies the server by computing the server-proof
directly and comparing.
9. Usage Scenarios
Single Sign-on
As with CRAM, the intermediate HMAC context from step (B) can
be used for a single sign-on client model. SCRAM also adds
the ability to store the output of step (B) for the single
sign-on only to services with the same salt. If expiration is
needed, it can be built into the single sign-on facility.
Kerberos is necessary if server-enforced expiration is needed.
OTP is necessary if expiration after a fixed number of
authentications is necessary.
Simplicity
CRAM, SCRAM and OTP are all suitable for use in lightweight
clients or servers. Kerberos and public key technology are
not simple enough.
Frequent Authentications
Protocols such as IMAP or POP result in frequent
authentications by the same user. OTP, by itself, is not
suitable for such services as the sequence needs to be reset.
OTP with OTP extended responses still does not permit
simulatanous connections by the same user.
Location Independent User
SCRAM, CRAM and OTP are all suitable for users which move
between many clients. Public key client authentication will
not be suitable for such uses until there is a worldwide smart
card standard.
Scalability / Server Efficiency
CRAM and SCRAM are believed to be scalable to large numbers of
users. OTP is less scalable due to the need to provide per-
user locking and update services to the authentication
database.
Client Efficiency
SCRAM has about half the client efficiency of CRAM. OTP's
client efficiency varies with the sequence number and it is
usually many times slower than SCRAM. Public key systems are
even slower.
Limited Server Trust
The server-key may be stored on a central SCRAM server which
limits the services an application server is permitted to
offer. CRAM and OTP do not offer this functionality.
Multi-Vendor Scenarios
SCRAM does not require cooperation between multiple services
on the same server or multiple applications on the same
client. This has proved to be a deployment problem for
Kerberos.
Proxy Authentication
SCRAM supports proxy authentication by including a separate
authentication and authorization identifiers. CRAM lacks this
facility.
10. Security Considerations
Security considerations are discussed throughout this document. Security considerations are discussed throughout this document.
The security considerations of SHA1 [SHA1] and HMAC [HMAC] also The security considerations of MD5 [MD5] and HMAC [HMAC] also
apply. apply. SCRAM relies primarily on the one-way characteristic of MD5
and HMAC-MD5 for cryptographic security.
SCRAM-SHA1 is conjectured to be a reasonably strong mechanism as An analysis of different attacks follows:
long as passphrases are well chosen and verifiers are kept secret.
Making a SCRAM-SHA1 verifier public is believed to be no worse than
making a Unix /etc/password verifier public when a plaintext-only
mechanism is used.
There are two particularly dangerous attacks against SCRAM-SHA1. Passive Network Attacks
The first is to passively record an authentication session (or
steal the verifier) and perform an offline dictionary attack to
find the passphrase. This type of attack is estimated to be about
40% effective at typical sites with current behavior patterns
[SCHNEIER]. Use of the term "passphrase", enforcement of site
policy when passphrases are changed and user education may improve
this to acceptable levels for many sites.
The second attack is to both steal the verifier for a user and SCRAM is resistant to replay attacks as long as the appropriate
passively record an authentication session by that user. This nonce is unique.
results in the ability to impersonate that user and more than
doubles the speed of a dictionary attack or brute-force attack to
recover the actual passphrase. For this reason, verifiers should
be kept well-protected.
This mechanism provides no protection for the session after SCRAM is not resistant to passive dictionary attacks. User
authentication. A passive observer can see information education, passphrase setting policy and TLS [TLS] may be used to
transmitted, and an active attacker can hijack the session. Use of protect against such attacks.
an external encryption layer such as TLS [TLS] can address this
problem.
This mechanism uses a hash-function combined with exclusive-or as a SCRAM does not protect against session data evesdropping. TLS
simple single-block cipher. [SCHNEIER] expresses reservations [TLS] may be used to protect against this.
about ciphers built using one-way hash functions, although not all
of his reservations may apply to this limited use.
9. Intellectual Property Issues and Prior Art Active Network Attacks
SCRAM protects against server impersonation with the optional
server authentication. CRAM and OTP do not have this facility.
SCRAM can protect against client impersonation by providing no
information beyond the salt to a client which fails verification.
Note that in order to prevent revealing the existance of a user to
such attackers, the server will have to invent consistant salt
between attempts and fail after the second client message. One way
to do this would be to store a random secret and use
HMAC(user-name, random-secret) to generate consistant salt values.
The server-ext-data may be used to protect against downgrade active
attacks (where the active attacker changes the advertised protocol
security services). CRAM and OTP do not have this facility.
SCRAM protects against account hijacking by an active attacker.
Use of OTP extended response [OTP-EXT] to reset the sequence is
susceptible to account hijacking.
SCRAM does not protect against connection hijacking or corruption.
TLS [TLS] or IPAUTH [IPAUTH] may be used to protect against this.
SCRAM does not protect against active denial of service attacks.
Server Attacks
SCRAM verifiers by themselves can not be used to impersonate the
user. CRAM verifiers have this weakness.
An attacker which has access to both the SCRAM verifier and a
client exchange for a particular user gains the ability to
impersonate that user to other servers using the same salt. TLS
[TLS] can make it more difficult to obtain the client exchange, but
does not defend against installation of a trojan horse server.
Client Attacks
As SCRAM is designed for user entry of a plaintext passphrase, it
is vulnerable to passphrase hijacking by trojan horse clients. OTP
[OTP] with an independent OTP calculator can be used to limit the
vulnerability to a single session.
11. Intellectual Property Issues and Prior Art
The author is not aware of any patents which apply to this The author is not aware of any patents which apply to this
mechanism. mechanism.
This is primarily a derivative of simple hash-based challenge This is primarily a derivative of simple hash-based challenge
response systems. The hash-based challenge response idea has response systems. The hash-based challenge response idea has
existed since at least 1992, when the RIPE project published the existed since at least 1992, when the RIPE project published the
SKID algorithm according to [SCHNEIER]. SKID algorithm according to [SCHNEIER].
The repeated-hash idea used to verify the client's authenticator is The repeated-hash idea used to verify the client's authenticator is
derived from S/KEY [SKEY]. derived from S/KEY [SKEY].
The idea of using a hash function to construct a cipher (with
exclusive-or) was originally invented by Peter Gutmann in 1993
according to [SCHNEIER].
The idea of using salt to protect against global dictionary attacks The idea of using salt to protect against global dictionary attacks
dates back to the unix /etc/password system or before. There is dates back to at least the Unix /etc/password system. There is
some discussion of this in [SCHNEIER]. some discussion of this in [SCHNEIER].
SCRAM combines these four techniques. The author of this SCRAM combines these techniques. The author of this specification
specification first proposed this publicly on a mailing list July first proposed this on a public mailing list July 16, 1997.
16, 1997. There is nothing new about this mechanism beyond the
idea of combining these existing techniques.
The SCRAM algorithm includes a single-block cipher capable of
encrypting 20 octets of authentication data. The author does not
believe this will cause problems for export restrictions, but
checking with the appropriate government(s) should be considered.
Computer readable source code for cryptographic hash functions such
as MD5 and SHA1 have been exported from the United States without
problems.
10. References 12. References
[ABNF] Crocker, D., "Augmented BNF for Syntax Specifications: [ABNF] Crocker, D., "Augmented BNF for Syntax Specifications:
ABNF", Work in progress: draft-ietf-drums-abnf-xx.txt ABNF", Work in progress: draft-ietf-drums-abnf-xx.txt
[CRAM-MD5] Klensin, Catoe, Krumviede, "IMAP/POP AUTHorize Extension [CRAM-MD5] Klensin, Catoe, Krumviede, "IMAP/POP AUTHorize Extension
for Simple Challenge/Response", RFC 2095, MCI, January 1997. for Simple Challenge/Response", RFC 2195, MCI, September 1997.
<ftp://ds.internic.net/rfc/rfc2095.txt> <ftp://ds.internic.net/rfc/rfc2195.txt>
[HMAC] Krawczyk, Bellare, Canetti, "HMAC: Keyed-Hashing for Message [HMAC] Krawczyk, Bellare, Canetti, "HMAC: Keyed-Hashing for Message
Authentication", RFC 2104, IBM, UCSD, February 1997. Authentication", RFC 2104, IBM, UCSD, February 1997.
<ftp://ds.internic.net/rfc/rfc2104.txt> <ftp://ds.internic.net/rfc/rfc2104.txt>
[IMAP4] Crispin, M., "Internet Message Access Protocol - Version [IMAP4] Crispin, M., "Internet Message Access Protocol - Version
4rev1", RFC 2060, University of Washington, December 1996. 4rev1", RFC 2060, University of Washington, December 1996.
<ftp://ds.internic.net/rfc/rfc2060.txt> <ftp://ds.internic.net/rfc/rfc2060.txt>
[IPAUTH] Atkinson, "IP Authentication Header", RFC 1826, Naval
Research Laboratory, August 1995.
<ftp://ds.internic.net/rfc/rfc1826.txt>
[KEYWORDS] Bradner, "Key words for use in RFCs to Indicate [KEYWORDS] Bradner, "Key words for use in RFCs to Indicate
Requirement Levels", RFC 2119, Harvard University, March 1997. Requirement Levels", RFC 2119, Harvard University, March 1997.
<ftp://ds.internic.net/rfc/rfc2119.txt> <ftp://ds.internic.net/rfc/rfc2119.txt>
[MD5] Rivest, "The MD5 Message Digest Algorithm", RFC 1321, MIT
Laboratory for Computer Science, April 1992.
<ftp://ds.internic.net/rfc/rfc1321.txt>
[OTP] Haller, Metz, "A One-Time Password System", RFC 1938,
Bellcore, Kaman Sciences Corporation, May 1996.
<ftp://ds.internic.net/rfc/rfc1938.txt>
[OTP-EXT] Metz, "OTP Extended Responses", work in progress.
[POP3] Myers, J., Rose, M., "Post Office Protocol - Version 3", RFC
1939, Carnegie Mellon, Dover Beach Consulting, Inc., May 1996.
<ftp://ds.internic.net/rfc/rfc1939.txt>
[RANDOM] Eastlake, Crocker, Schiller, "Randomness Recommendations [RANDOM] Eastlake, Crocker, Schiller, "Randomness Recommendations
for Security", RFC 1750, DEC, Cybercash, MIT, December 1994. for Security", RFC 1750, DEC, Cybercash, MIT, December 1994.
<ftp://ds.internic.net/rfc/rfc1750.txt> <ftp://ds.internic.net/rfc/rfc1750.txt>
[SASL] Myers, "Simple Authentication and Security Layer (SASL)", [SASL] Myers, "Simple Authentication and Security Layer (SASL)",
work in progress. work in progress.
[SCHNEIER] Schneier, "Applied Cryptography: Protocols, Algorithms [SCHNEIER] Schneier, "Applied Cryptography: Protocols, Algorithms
and Source Code in C," John Wiley and Sons, Inc., 1996. and Source Code in C," John Wiley and Sons, Inc., 1996.
[SHA1] NIST, FIPS PUB 180-1: Secure Hash Standard, April 1995.
[SKEY] Haller, Neil M. "The S/Key One-Time Password System", RFC [SKEY] Haller, Neil M. "The S/Key One-Time Password System", RFC
1760, Bellcore, February 1995. 1760, Bellcore, February 1995.
<ftp://ds.internic.net/rfc/rfc1760.txt> <ftp://ds.internic.net/rfc/rfc1760.txt>
[TLS] Dierks, Allen, "The TLS Protocol Version 1.0", Work in [TLS] Dierks, Allen, "The TLS Protocol Version 1.0", Work in
progress. progress.
[UTF8] Yergeau, F. "UTF-8, a transformation format of Unicode and [UTF8] Yergeau, F. "UTF-8, a transformation format of Unicode and
ISO 10646", RFC 2044, Alis Technologies, October 1996. ISO 10646", RFC 2044, Alis Technologies, October 1996.
<ftp://ds.internic.net/rfc/rfc2044.txt> <ftp://ds.internic.net/rfc/rfc2044.txt>
11. Author's Address 13. Author's Address
Chris Newman Chris Newman
Innosoft International, Inc. Innosoft International, Inc.
1050 Lakes Drive 1050 Lakes Drive
West Covina, CA 91790 USA West Covina, CA 91790 USA
Email: chris.newman@innosoft.com Email: chris.newman@innosoft.com
A. Appendix - Sample Source Code A. Appendix - TWEKE Proposal
XXX: to be done
B. Appendix - TWEKE Proposal
Tom Wu has proposed adding a Diffie-Hellman key exchange to this Tom Wu has proposed adding a Diffie-Hellman key exchange to this
mechanism. Diffie-Hellman works roughly as follows: mechanism. Diffie-Hellman works roughly as follows:
Server picks g, n and x. Server computes X = g^x mod n. Server picks g, n and x. Server computes X = g^x mod n.
server -> client: g, n, X server -> client: g, n, X
Client picks y and computes Y = g^y mod n and K = X^y mod n. Client picks y and computes Y = g^y mod n and K = X^y mod n.
skipping to change at page 12, line 11 skipping to change at page 16, line 18
K). K).
If g, n, x and y are sufficiently big and have the right If g, n, x and y are sufficiently big and have the right
characteristics, then both the client and server share K which is characteristics, then both the client and server share K which is
very difficult for a passive evesdropper to obtain. very difficult for a passive evesdropper to obtain.
The TWEKE proposal would add the following steps: The TWEKE proposal would add the following steps:
(4.5) Server sends g, n, X. (4.5) Server sends g, n, X.
(7.5) Client sends Y. (8.5) Client sends Y.
and would modify steps (D) and (a) to include the value K. This and would modify steps (F), (J), (b) and (g) to include the value
would result in a protocol safe from passive attacks. The expense K. This would result in a protocol safe from passive network
would be reduced performance, the need for a bignum math library attacks. The expense would be reduced performance, the need for a
and a requirement that an export license be obtained from certain bignum math library and possibly a requirement that an export
governments (included the United States). This would not defend license be obtained from certain governments (included the United
against active attacks, but should be free of patent restrictions States). This would not defend against active attacks unless an
after October 6th, 1997. encryption service was added. This may be free of patent
restrictions.
TWEKE might be harder to deploy than SCRAM due to the higher math TWEKE would be harder to deploy than SCRAM due to the higher math,
and the use of public key technology. the use of public key technology and the performance loss.
C. Appendix - Additional Services B. Appendix - Additional Services
Several additional services are needed to make SCRAM useful in Several additional services are needed to make SCRAM useful in
various usage scenarios. These include remote authentication various usage scenarios. These include remote authentication
database support for servers, authentication database APIs for database support for servers, authentication database APIs for
servers, remote passphrase change support for clients, single- servers, remote passphrase change support for clients,
sign-on APIs for clients and management tools. The server-id is single-sign-on APIs for clients and management tools. The
included to facilite the remote authentication database service. service-id and server-key are included to facilite the remote
Otherwise these issues are deferred for future work. authentication database service. Otherwise these issues are
deferred for future work.
C. Appendix - HMAC-MD5 Sample Source Code
The following sample C source code is calls the source code in
[MD5] and is derived from the source code in [HMAC]. It is needed
by the SCRAM source code in the next section.
/* hmac-md5.h -- HMAC-MD5 functions
*/
#define HMAC_MD5_SIZE 16
/* intermediate MD5 context */
typedef struct HMAC_MD5_CTX_s {
MD5_CTX ictx, octx;
} HMAC_MD5_CTX;
/* One step hmac computation
*
* digest may be same as text or key
*/
void hmac_md5(const unsigned char *text, int text_len,
const unsigned char *key, int key_len,
unsigned char digest[HMAC_MD5_SIZE]);
/* create intermediate result from key
*/
void hmac_md5_init(HMAC_MD5_CTX *hmac,
const unsigned char *key, int key_len);
#define hmac_md5_update(hmac, text, text_len) \
MD5Update(&(hmac)->ictx, (text), (text_len))
/* finish hmac from intermediate result.
* Intermediate result is zeroed.
*/
void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
HMAC_MD5_CTX *hmac);
/* hmac-md5.c -- Keyed-Hashing
* derived from RFC 2104 by H. Krawczyk, M. Bellare, R.Canetti
*/
#include <stdio.h>
#include <string.h>
#include "md5.h"
#include "hmac-md5.h"
/* MD5 block size */
#define BLOCK_SIZE 64
void hmac_md5_init(HMAC_MD5_CTX *hmac,
const unsigned char *key, int key_len)
{
unsigned char k_pad[BLOCK_SIZE]; /* padded key */
int i;
/* if key longer than BLOCK_SIZE bytes reset it to MD5(key) */
if (key_len > BLOCK_SIZE) {
MD5Init(&hmac->ictx);
MD5Update(&hmac->ictx, key, key_len);
MD5Final(k_pad, &hmac->ictx);
key = k_pad;
key_len = HMAC_MD5_SIZE;
}
/* XOR padded key with inner pad value */
for (i = 0; i < key_len; i++) {
k_pad[i] = key[i] ^ 0x36;
}
while (i < BLOCK_SIZE) {
k_pad[i++] = 0x36;
}
/* Begin inner MD5 */
MD5Init(&hmac->ictx);
MD5Update(&hmac->ictx, k_pad, BLOCK_SIZE);
/* XOR padded key with outer pad value */
for (i = 0; i < BLOCK_SIZE; ++i) {
k_pad[i] ^= (0x36 ^ 0x5c);
}
/* Begin outer MD5 */
MD5Init(&hmac->octx);
MD5Update(&hmac->octx, k_pad, BLOCK_SIZE);
/* clean up workspace */
memset(k_pad, 0, BLOCK_SIZE);
}
void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
HMAC_MD5_CTX *hmac)
{
/* finish inner MD5 */
MD5Final(digest, &hmac->ictx);
/* finish outer MD5 */
MD5Update(&hmac->octx, digest, HMAC_MD5_SIZE);
MD5Final(digest, &hmac->octx);
/* MD5Final zeros context */
}
void hmac_md5(const unsigned char *text, int text_len,
const unsigned char *key, int key_len,
unsigned char digest[HMAC_MD5_SIZE])
{
HMAC_MD5_CTX hmac;
hmac_md5_init(&hmac, key, key_len);
hmac_md5_update(&hmac, text, text_len);
hmac_md5_final(digest, &hmac);
}
D. Appendix - SCRAM sample source code
The following sample source code implements SCRAM itself for both
server and client.
Please note the comments marked "/*XXX ... */" as they need to be
translated from English to computer readable code.
A client implementation simply calls scram_md5_generate() with the
passphrase after receiving the first server reply. The cproof
parameter will hold the message to send to the server and the
sproof parameter will hold the expected server mutual
authentication. A client may also call cram_md5_cred() to turn a
passphrase into CRAM/SCRAM credentials for later use in
scram_md5_generate().
A server implementation simply calls scram_md5_generate() with the
stored verifier, the second client message and the SCRAM_VERIFY
option. Server verifiers are generated by creating a random salt
and calling scram_md5_vgen() with either the passphrase or
CRAM/SCRAM credentials.
/* scram.h -- scram utility functions
*/
/* size of CRAM_MD5 verifier and CRAM_MD5/SCRAM_MD5 credentials */
#define CRAM_MD5_SIZE 32
/* size of SCRAM_MD5 salt and verifier */
#define SCRAM_MD5_SALTSIZE 8
#define SCRAM_MD5_DATASIZE 16
/* SCRAM verifier */
typedef struct SCRAM_MD5_VRFY_s {
unsigned char salt[SCRAM_MD5_SALTSIZE];
unsigned char clidata[SCRAM_MD5_DATASIZE];
unsigned char svrdata[SCRAM_MD5_DATASIZE];
} SCRAM_MD5_VRFY;
/* prepare CRAM-MD5 credentials/verifier also SCRAM-MD5 credential
* buf -- must be aligned and have room for CRAM_MD5_SIZE
* pass -- passphrase or verifier
* passlen -- len of pass/verifier (0 ok if NUL terminated)
*/
void cram_md5_cred(char *buf, const char *pass, int passlen);
/* generate SCRAM-MD5 verifier
* vptr -- gets result
* salt -- contains salt of SCRAM_MD5_SALTSIZE
* pass -- passphrase or verifier
* passlen -- len of pass/verifier (0 ok if NUL terminated)
* plainflag -- 1 = plaintext passphrase,
* 0 = result of cram_md5_cred()
* clientkey -- cache for client proof, usually NULL
*/
void scram_md5_vgen(SCRAM_MD5_VRFY *vptr,
const unsigned char *salt,
const char *pass, int passlen, int plainflag,
unsigned char *clientkey);
/* scram secret action type
*/
#define SCRAM_CREDENTIAL 0 /* generate replies using credentials */
#define SCRAM_PLAINTEXT 1 /* generate replies using plaintext */
#define SCRAM_VERIFY 2 /* use SCRAM_MD5_VRFY to verify client,
and generate server reply */
/* generate or verify SCRAM-MD5
* input params:
* cchal -- client challenge string
* cchallen -- length of client challenge
* schal -- server challenge string
* schallen -- length of server challenge
* secret -- passphrase, credentials or verifier
* secretlen -- length of passphrase (0 ok if NUL terminated)
* action -- see above
* in/out:
* cproof -- client proof of length SCRAM_MD5_DATASIZE
* output:
* sproof -- server proof of length SCRAM_MD5_DATASIZE
* returns:
* -2 if params invalid
* -1 if verify fails
* 0 on success
*/
int scram_md5_generate(const char *cchal, int cchallen,
const char *schal, int schallen,
const char *secret, int secretlen,
int action, unsigned char *cproof,
unsigned char *sproof);
/* scram.c -- routines for SCRAM-MD5 calculations
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "md5.h"
#include "hmac-md5.h"
#include "scram.h"
/* for htonl() and ntohl() */
#include <sys/types.h>
#include <netinet/in.h>
/* MD5 block size */
#define BLOCK_SIZE 64
/* intermediate CRAM context
* values stored in network byte order (Big Endian)
*/
typedef struct CRAM_MD5_CTX_s {
UINT4 istate[4];
UINT4 ostate[4];
} CRAM_MD5_CTX;
void cram_md5_cred(char *buf, const char *pass, int passlen)
{
HMAC_MD5_CTX hctx;
CRAM_MD5_CTX *ctx = (CRAM_MD5_CTX *) buf;
if (passlen == 0) passlen = strlen(pass);
hmac_md5_init(&hctx, (const unsigned char *) pass, passlen);
ctx->istate[0] = htonl(hctx.ictx.state[0]);
ctx->istate[1] = htonl(hctx.ictx.state[1]);
ctx->istate[2] = htonl(hctx.ictx.state[2]);
ctx->istate[3] = htonl(hctx.ictx.state[3]);
ctx->ostate[0] = htonl(hctx.octx.state[0]);
ctx->ostate[1] = htonl(hctx.octx.state[1]);
ctx->ostate[2] = htonl(hctx.octx.state[2]);
ctx->ostate[3] = htonl(hctx.octx.state[3]);
memset(&hctx, 0, sizeof (hctx));
}
/* extract hmac context from CRAM-MD5 credentials
*/
void hmac_cram_md5_init(HMAC_MD5_CTX *hctx, CRAM_MD5_CTX *ctx)
{
hctx->ictx.state[0] = ntohl(ctx->istate[0]);
hctx->ictx.state[1] = ntohl(ctx->istate[1]);
hctx->ictx.state[2] = ntohl(ctx->istate[2]);
hctx->ictx.state[3] = ntohl(ctx->istate[3]);
hctx->octx.state[0] = ntohl(ctx->ostate[0]);
hctx->octx.state[1] = ntohl(ctx->ostate[1]);
hctx->octx.state[2] = ntohl(ctx->ostate[2]);
hctx->octx.state[3] = ntohl(ctx->ostate[3]);
hctx->ictx.count[0] = hctx->octx.count[0] = BLOCK_SIZE << 3;
hctx->ictx.count[1] = hctx->octx.count[1] = 0;
}
void scram_md5_vgen(SCRAM_MD5_VRFY *vptr,
const unsigned char *salt,
const char *pass, int passlen, int plainflag,
unsigned char *clientkey)
{
HMAC_MD5_CTX hctx;
if (clientkey == NULL) clientkey = vptr->clidata;
/* get context */
if (plainflag) {
if (passlen == 0) passlen = strlen(pass);
hmac_md5_init(&hctx, (const unsigned char *) pass,
passlen);
} else {
hmac_cram_md5_init(&hctx, (CRAM_MD5_CTX *) pass);
}
/* generate salted passphrase */
hmac_md5_update(&hctx, salt, SCRAM_MD5_SALTSIZE);
hmac_md5_final(vptr->clidata, &hctx);
/* generate server proof */
hmac_md5(salt, SCRAM_MD5_SALTSIZE, vptr->clidata,
sizeof (vptr->clidata), vptr->svrdata);
/* generate client key and client verifier */
MD5Init(&hctx.ictx);
MD5Update(&hctx.ictx, vptr->clidata, sizeof (vptr->clidata));
MD5Final(clientkey, &hctx.ictx);
MD5Init(&hctx.ictx);
MD5Update(&hctx.ictx, clientkey, SCRAM_MD5_DATASIZE);
MD5Final(vptr->clidata, &hctx.ictx);
/* copy salt to verifier */
if (salt != vptr->salt) {
memcpy(vptr->salt, salt, SCRAM_MD5_SALTSIZE);
}
}
int scram_md5_generate(const char *cchal, int cchallen,
const char *schal, int schallen,
const char *secret, int secretlen,
int action, unsigned char *cproof,
unsigned char *sproof)
{
SCRAM_MD5_VRFY verifier, *vptr;
HMAC_MD5_CTX hctx;
unsigned char clientkey[HMAC_MD5_SIZE];
unsigned char sharedkey[HMAC_MD5_SIZE];
int i, result = 0;
/* check params */
if ((action == SCRAM_CREDENTIAL && secretlen != CRAM_MD5_SIZE)
|| (action == SCRAM_VERIFY
&& secretlen != sizeof (verifier))
|| schallen < SCRAM_MD5_SALTSIZE) {
return (-2);
}
/* get verifier */
if (action == SCRAM_VERIFY) {
vptr = (SCRAM_MD5_VRFY *) secret;
} else {
scram_md5_vgen(&verifier, (const unsigned char *) schal,
secret, secretlen, action, clientkey);
vptr = &verifier;
}
/* calculate shared key */
hmac_md5_init(&hctx, vptr->clidata, sizeof (vptr->clidata));
hmac_md5_update(&hctx, (unsigned char *) schal, schallen);
hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen);
hmac_md5_final(sharedkey, &hctx);
if (action == SCRAM_VERIFY) {
/* verify client proof */
for (i = 0; i < HMAC_MD5_SIZE; ++i) {
/*XXX: the line which belongs here is omitted due to U.S.
export regulations, but it exclusive-ors the
"sharedkey" with the "cproof" and places the result in
"clientkey" (see step (c) above) */
}
MD5Init(&hctx.ictx);
MD5Update(&hctx.ictx, clientkey, sizeof (clientkey));
MD5Final(clientkey, &hctx.ictx);
if (memcmp(clientkey, vptr->clidata,
sizeof (clientkey)) != 0) {
result = -1;
}
} else {
/* generate client proof */
for (i = 0; i < HMAC_MD5_SIZE; ++i) {
/*XXX: the line which belongs here is omitted due to U.S.
export regulations, but it exclusive-ors the
"sharedkey" with the "clientkey" and places the result
in "cproof" (see step (G) above) */
}
}
/* calculate server result */
if (result == 0) {
hmac_md5_init(&hctx, vptr->svrdata, HMAC_MD5_SIZE);
hmac_md5_update(&hctx, (unsigned char *) schal, schallen);
hmac_md5_update(&hctx, (unsigned char *) cchal, cchallen);
hmac_md5_final(sproof, &hctx);
}
/* cleanup workspace */
memset(clientkey, 0, sizeof (clientkey));
memset(sharedkey, 0, sizeof (sharedkey));
if (vptr == &verifier) memset(&verifier, 0, sizeof (verifier));
return (result);
}
 End of changes. 88 change blocks. 
260 lines changed or deleted 454 lines changed or added

This html diff was produced by rfcdiff 1.48. The latest version is available from http://tools.ietf.org/tools/rfcdiff/