Network Working Group                                          C. Newman
Internet Draft: SCRAM-SHA1 SCRAM-MD5 SASL Mechanism                        Innosoft
Document: draft-newman-auth-scram-00.txt                  September draft-newman-auth-scram-01.txt                    October 1997
                                                   Expires in six months

       Salted Challenge Response Authentication Mechanism (SCRAM)

Status of this memo

     This document is an Internet-Draft.  Internet-Drafts are working
     documents of the Internet Engineering Task Force (IETF), its areas,
     and its working groups.  Note that other groups may also distribute
     working documents as Internet-Drafts.

     Internet-Drafts are draft documents valid for a maximum of six
     months and may be updated, replaced, or obsoleted by other
     documents at any time.  It is inappropriate to use Internet-Drafts
     as reference material or to cite them other than as "work in
     progress."

     To view the entire list of current Internet-Drafts, please check
     the "1id-abstracts.txt" listing contained in the Internet-Drafts
     Shadow Directories on ftp.is.co.za (Africa), ftp.nordu.net
     (Europe), munnari.oz.au (Pacific Rim), ds.internic.net (US East
     Coast), or ftp.isi.edu (US West Coast).

Abstract

     SCRAM is a simple passphrase-based authentication mechanism which
     uses only a publicly available cryptographic hash function to
     provide authentication
     suitable for protocols. a wide variety of usage scenarios.  It is designed to replace
     plaintext password mechanisms without significant additional
     complexity, loss combines the
     best properties of performance or plaintext equivalent verifiers. CRAM-MD5 [CRAM-MD5], a similar mechanism, has the drawback that the
     password verifier stored on the server can be used to impersonate
     the user.  Current plaintext password mechanisms do not have this
     drawback [CRAM-MD5] and it is OTP [OTP] without 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
     significant increase in complexity.

     This document defines the SCRAM-SHA1 SCRAM-MD5 SASL mechanism [SASL] using the SHA1 [SHA1]
     MD5 [MD5] and HMAC-SHA1 HMAC-MD5 [HMAC] algorithms.  It is suitable for use
     directly with protocols such as IMAP [IMAP4] and POP [POP3].

0. Open Issues Changes from Previous Version

     (1) Although this mechanism has no new concepts, MD5 is used instead of SHA1 as it has not had
     extensive review.  Advice permits backwards-
     compatibility with CRAM-MD5 verifiers on the completeness of the security
     considerations server and it is appreciated. a
     more commonly available hash function.  This should not effect
     SCRAM's security significantly.

     (2) The TWEKE proposal (appendix B) server-proof is more secure and more
     complex.  Is it an acceptable or desirable tradeoff?  Perhaps SCRAM
     could get 40% penetration into now independent of the plaintext market and TWEKE could
     get 30%, would it be worthwhile client-verifier.
     This allows a remote authentication service to do TWEKE instead of SCRAM efficiently restrict
     the services an application server may offer to clients.

     (3) The salt is included in
     this case?  What if there's the client-key which means that a bigger difference?
     compromised verifier and client-server exchange only gains access
     to services which use the same salt.

     (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. Conventions Used in this 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"
     in this document are to be interpreted as defined in "Key words for
     use in RFCs to Indicate Requirement Levels" [KEYWORDS].

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-SHA1 SCRAM-MD5

     This section includes a step-by-step guide for client implementors.
     Although section 7 6 contains the formal definition of the syntax and
     is the authoritative reference in case of errors here, this section
     should be sufficient to build a correct implementation.

     When used with SASL the mechanism name is "SCRAM-SHA1". "SCRAM-MD5".  The
     mechanism does not provide a security layer.

     The client begins by sending a message to the server containing the
     following three pieces of information: information.  The entire message MUST NOT
     exceed 1000 characters.

     (1) An authorization identity.  When the empty string is used, this
     defaults to the authentication identity.  This is used by system
     administrators or proxy servers to login with a different user
     identity.  This field may be up to 255 octets and is terminated by
     a NUL (0) octet.  US-ASCII printable characters are preferred,
     although UTF-8 [UTF-8] printable characters are permitted to
     support international names.  Use of character sets other than
     US-ASCII and UTF-8 is forbidden.

     (2) An authentication identity.  The identity whose passphrase will
     be used.  This field may be up to 255 octets and is terminated by a
     NUL (0) octet.  US-ASCII printable characters are preferred,
     although UTF-8 [UTF-8] printable characters are permitted to
     support international names.  Use of character sets other than
     US-ASCII and UTF-8 is forbidden.

     (3) A An optional "client nonce" of 8 to 256 octets.  It nonce."  If this is omitted, it indicates a
     desire for client-only authentication.  When present, it is
     important that this be globally unique.  One common technique for
     generating globally unique and somewhat random.  It can be generated by
     appending identifiers combines a process
     identifier with the system clock to clock, a sequence number, a random
     number (advice and the client's domain name.  The random number is
     important as clocks are often synchronized using insecure
     protocols.  Advice for generating good strong random numbers can be
     found in [RANDOM]) and the
     client's IP address or domain name. [RANDOM].

     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.

     (5) A server service id consisting of the service name of the protocol's
     SASL profile followed by a "." an "@" followed by the domain name of the
     server followed by an "@" and optional extension data terminated by NUL.  This will not be longer than 512 octets.  The client SHOULD verify this is
     correct.

     (6) A "server nonce" of 8 string containing extension data, terminated by NUL.  A
     client which supports TLS [TLS] or stronger SASL mechanisms can
     check this to 32 octets. 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:

     (A) Create a buffer containing the user's passphrase.  The client
     MUST support passphrases of at least 64 octets.  US-ASCII
     characters are preferred, although UTF-8 characters are permitted.
     Character sets other than UTF-8 MUST NOT be used.

     (B) Apply the SHA1 HMAC-MD5 function to (A), with (A) as the key and the 8-octet
     salt as the data, producing a 20 octet 16-octet result.  Once this is done,
     (A) SHOULD be erased from memory.

     (C) Apply the HMAC-SHA1 MD5 function with to the result of (B) as the key
     and (B).  This produces a
     16-octet result.

     (D) Apply the 8-octet salt (4) value as MD5 function to the data. result of (C).  This produces a 20
     octet
     16-octet result.

     (D)

     (E) Create a buffer containing the server's response (4)-(6), (4)-(7),
     immediately followed by the initial client message (1)-(3).

     (E)

     (F) Apply the HMAC-SHA1 HMAC-MD5 function with the result of (C) (D) as the key
     and the buffer from (D) (E) as the data.  This produces a 20-octet 16-octet
     result.

     (F)

     (G) Create a 20-octet 16-octet buffer containing the exclusive-or of (B) (C) and
     (E).
     (F).

     The client then sends a message to the server containing the
     following:

     (7)

     (8) The 20-octet 16-octet result of step (F). (G).

     If no client challenge was suppled in step 3, the one-way
     authentication is successful, then the server responds with the
     following:

     (8) now complete.

     (9) A 20-octet mutual 16-octet server authentication verifier.

     The client SHOULD verify this with the following procedure:

     (G)

     (H) Apply the HMAC-MD5 function with the result of (B) as the key
     and the 8-octet salt as the data.  This produces a 16-octet result.

     (I) Create a buffer containing the initial client message (1)-(3)
     immediately followed by the initial server response (4)-(6).

     (H) (4)-(7).

     (J) Apply the HMAC-SHA1 HMAC-MD5 function with the result of (C) (H) as the key
     and the buffer from (G) (I) as the data.

     (I)

     (K) If the result of (H) (J) matches (8), (9), the server is authenticated.

     A secured client MAY store the result of (B) to re-authenticate.
     Permanent storage of (B) by re-authenticate to
     services using the client is discouraged although it
     is preferable same salt, or the intermediate HMAC state from
     (B) to storing re-authenticate to any service.  Clients SHOULD NOT store
     the actual passphrase.

3. passphrase itself.

4. Server Implementation of SCRAM-SHA1. SCRAM-MD5.

     The section includes a step-by-step guide for server implementors.
     Although section 7 6 contains the formal definition of the syntax and
     is the authoritative reference in case of errors here, this section
     in conjunction with section 2 3 should be sufficient to build a
     correct implementation.

     The server's authentication database contains an 8-octet salt and
     20-octet salt, 16-
     octet client verifier and a 16-octet server key for each local
     user.  The server MAY MUST support
     remote users using the syntax "user@host" syntax for the
     authentication
     identity, but if it doesn't it MUST truncate the authentication identity at the "@" sign prior least to lookup in the extent of stripping "@host"
     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 stored client verifier is equal to the result of step (C) (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
     the authentication identity to fetch the salt, and generates an 8
     to 32 248 octet nonce. This nonce MUST be unique to prevent replay
     attacks.  It can be generated by appending a system clock to a
     random number [RANDOM].  To verify the client's credentials, the
     server preforms the following steps:

     (a) Generate a buffer identical to step (D) for the client. (E) above.

     (b) Apply the HMAC-SHA1 HMAC-MD5 function with the stored client verifier as
     the key and the result of (a) as the data.  This produces a 20-octet 16-
     octet result equal to step (E) (F) above.

     (c) Exclusive-or the result of (b) with message (7) (8) from the
     client.  This produces a 20-octet 16-octet result which should be equal to
     the output result of step (B) (C) above.

     (d) Apply the HMAC-SHA1 MD5 function with (c) as the key and the stored
     salt as to the data. output of step (c).  This
     produces a 20-octet result. 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
     user is authenticated.

     If no client challenge was provided in step (3), the server is now
     done and responds with the appropriate status code.

     (f) Generate a buffer identical to step (G) (I) above.

     (g) Apply the HMAC-SHA1 HMAC-MD5 function with the stored verifier as the key
     and the buffer from (f) as the data.  This produces a 20-octet 16-octet
     result.

     The result of (g) is sent to the client as to authenticate the mutual
     authentication step.

4. server.

5. Example

     XXX:

     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.

     In this example, "C:" represents lines sent from the client to the
     server and "S:" represents lines sent from the server to the
     client.  The wrapped lines are for editorial clarity -- there are
     no actual newlines in the middle of the messages.

       C: a001 AUTHENTICATE SCRAM-MD5
       S: +
       C: AGNocmlzADxwNVIxZTBWTzNLdFZBNEZITDdudWRRQGVsZWFub3Iua
          W5ub3NvZnQuY29tPg==
       S: AeYw5Ugm+blpbWFwQGVsZWFub3IuaW5ub3NvZnQuY29tAAA8b1JNa
          nFFekYvL1J5WnhFMlF2cDNzd0BlbGVhbm9yLmlubm9zb2Z0LmNvbT4=
       C: 5cZpsA9pODOVwuNU1xmJHA==
       S: a001 OK [vJ1FEfRHulPALMwSb/UC9g==] AUTHENTICATE completed

     For this example, the user "chris", with an empty authorization
     identity is using the passphrase "secret stuff".  The client nonce
     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".

6. Formal Syntax of SCRAM-MD5 Messages

     This is the formal syntactic definition of the client and server
     messages.  This uses ABNF [ABNF] notation.

     client-msg-1     = [authorize-id] NUL authenticate-id NUL [nonce]
                        ;; MUST NOT exceed 1000 octets

     server-msg-1     = salt service-id NUL server-ext-data NUL nonce
                        ;; MUST NOT exceed 1000 octets

     client-msg-2     = client-proof

     server-msg-2     = server-proof

     passphrase       = *UTF8-SAFE
                        ;; At least 64 octets MUST be done

5. supported

     authorize-id     = *UTF8-PRINT
                        ;; No more than 255 octets

     authenticate-id  = *UTF8-PRINT
                        ;; No more than 255 octets

     service-id       = service-name "@" server-domain

     service-name     = *US-ASCII-PRINT
                        ;; a SASL/GSSAPI service name

     server-domain    = *US-ASCII-PRINT
                        ;; an internet domain name

     server-ext-data  = *(sasl-mech-list / tls-avail / ext-list)

     sasl-mech-list   = "SASL:" *(CFWS sasl-mech) CRLF

     CFWS             = [CRLF] 1*SPACE

     sasl-mech        = 1*20(ALPHA / DIGIT / "-" / "_")

     tls-avail        = "TLS:" SPACE "yes"

     ext-list         = 1*UTF8PRINT ":" *(CFWS 1*UTF8PRINT) CRLF

     nonce            = 8*OCTET

     salt             = 8OCTET

     client-proof     = 16OCTET

     server-proof     = 16OCTET

     NUL              = %x00  ;; US-ASCII NUL character

     US-ASCII-SAFE    = %x01-09 / %x0B-0C / %x0E-7F
                       ;; US-ASCII except CR, LF, NUL

     US-ASCII-PRINT   = %x20-7E
                       ;; printable US-ASCII including SPACE

     UTF8-SAFE        = US-ASCII-SAFE / UTF8-1 / UTF8-2 / UTF8-3
                          / UTF8-4 / UTF8-5

     UTF8-PRINT       = US-ASCII-PRINT / UTF8-1 / UTF8-2 / UTF8-3
                          / UTF8-4 / UTF8-5

     UTF8-CONT        = %x80..BF

     UTF8-1           = %xC0..DF UTF8-CONT

     UTF8-2           = %xE0..EF 2UTF8-CONT

     UTF8-3           = %xF0..F7 3UTF8-CONT

     UTF8-4           = %xF8..FB 4UTF8-CONT

     UTF8-5           = %xFC..FD 5UTF8-CONT

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-SHA1 are probably more secure
     than SCRAM-MD5 have roughly comparable
     security to those used by current plaintext mechanisms (such as
     Unix
     /etc/password), /etc/passwd), it is still very important to keep them secret.
     Just as tools exist to try common passwords against Unix
     /etc/password
     /etc/passwd files, it is also possible to build such tools for
     SCRAM-SHA1.
     SCRAM-MD5.  In addition, once a SCRAM-SHA1 SCRAM-MD5 verifier is stolen, a
     passive (undetectable) snoop evesdropper of that user logging in will result in gains
     the output of step (B) (C) above, which is sufficient to impersonate a
     user.
     the user to all services with the same salt.  This is far better
     than current plaintext mechanisms where a passive snoop 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-SHA1

     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-SHA1

     SCRAM-MD5 doesn't protect the integrity or privacy of data
     exchanged after authentication.  Use of an external encryption
     layer TLS [TLS] or a stronger authentication
     SASL mechanism such as Kerberos is encouraged if this functionality
     is needed.

6. SCRAM-SHA1

8. SCRAM-MD5 Functional Notation

     This section is designed to provide a quick understanding of
     SCRAM-SHA1
     SCRAM-MD5 for the mathematically inclined. 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 would be is the same as AU, a single NUL is used instead.
     SV
     service   is the name of the service and server
     p (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 SHA-1
     M(x,y) MD5
     MAC(x,y)  is a message authentication code (MAC) such as HMAC-SHA1 HMAC-MD5
               "y" is the key and "x" is the text signed by the key.
     V        is a per-user verifier the server stores
     s
     salt      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 following computed by applying the hash function to the
     plaintext passphrase, then using the result to sign values are used in the salt.
     Thus:

     V exchange:

     client-chal     = M(s, H(p))

     The proof (P) is computed as follows:

     P AZ + AU + Uc
     server-chal     = H(p) XOR M(s salt + SV service + Us ext-attr + AZ Us
     salted-pass     = MAC(salt, pass)
     client-key      = H(salted-pass)
     client-verifier = H(client-key)
     shared-key      = MAC(server-chal + AU client-chal, client-verifier)
     client-proof    = client-key XOR shared-key
     server-key      = MAC(salt, salted-pass)
     server-proof    = MAC(client-chal + Uc, V) server-chal, server-key)

     The SCRAM exchange is as follows:

     (1) client -> server: AZ + AU + Uc client-chal
     (2) server -> client: s + SV + Us server-chal
     (3) client -> server: P client-proof
     (4) server -> client: M(AZ + AU + Uc + s + SV + Us, V) server-proof

     The server verifies P by checking that stores the following is equal to V:

     M(s, P salt, client-verifier and server-key.  It
     authenticates the client by computing:

       H(client-proof XOR M(s + SV + Us + AZ + AU + Uc, V)) shared-key)

     after step 3 and comparing it to the stored client-verifier.

     The client verifies the server's identity 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 performing the same
     computation user.  OTP, by itself, is not
          suitable for such services as the server 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 comparing it 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 the server's
     result.

7. Formal Syntax be scalable to large numbers of SCRAM-SHA1 Messages

     This
          users.  OTP is less scalable due to the formal syntactic definition of 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
     messages.  This uses which
          limits the ABNF [ABNF] notation.

     client-msg-1     = [authorize-id] NUL authenticate-id NUL client-nonce

     server-msg-1     = salt server-id NUL server-nonce

     client-msg-2     = proof

     server-msg-2     = mutual-auth

     passphrase       = 8*UTF8-SAFE
                        ;; At least 64 octets MUST 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 supported

     authorize-id     = *UTF8-PRINT
                        ;; No more than 255 octets

     authenticate-id  = *UTF8-PRINT
                        ;; No more than 255 octets

     server-id        = service-name "." server-domain
                        "@" [ server-ext-data ]
                        ;; No more that 511 octets total

     service-name     = *USASCII-PRINT
                        ;; a GSSAPI service name

     server-domain    = *USASCII-PRINT
                        ;; an internet domain name

     server-ext-data  = *UTF8-SAFE
                        ;; extension data

     server-id        = *UTF8-PRINT
                        ;; No more than 511 octets

     client-nonce     = 8*256OCTET

     server-nonce     = 8*32OCTET

     salt             = 8OCTET

     proof            = 20OCTET

     mutual-auth      = 20OCTET

     NUL              = %x00  ;; US-ASCII NUL character

     US-ASCII-SAFE    = %x01-09 / %x0B-0C / %x0E-7F
                       ;; US-ASCII except CR, LF, NUL

     US-ASCII-PRINT   = %x20-7E
                       ;; printable US-ASCII deployment problem for
          Kerberos.

     Proxy Authentication
          SCRAM supports proxy authentication by including SPACE

     UTF8-SAFE        = US-ASCII-SAFE / UTF8-1 / UTF8-2 / UTF8-3
                          / UTF8-4 / UTF8-5

     UTF8-PRINT      = US-ASCII-PRINT / UTF8-1 / UTF8-2 / UTF8-3
                          / UTF8-4 / UTF8-5

     UTF8-CONT        = %x80..BF

     UTF8-1           = %xC0..DF UTF8-CONT

     UTF8-2           = %xE0..EF 2UTF8-CONT

     UTF8-3           = %xF0..F7 3UTF8-CONT

     UTF8-4           = %xF8..FB 4UTF8-CONT

     UTF8-5           = %xFC..FD 5UTF8-CONT

8. a separate
          authentication and authorization identifiers.  CRAM lacks this
          facility.

10. Security Considerations

     Security considerations are discussed throughout this document.
     The security considerations of SHA1 [SHA1] MD5 [MD5] and HMAC [HMAC] also
     apply.

     SCRAM-SHA1  SCRAM relies primarily on the one-way characteristic of MD5
     and HMAC-MD5 for cryptographic security.

     An analysis of different attacks follows:

     Passive Network Attacks

     SCRAM is conjectured resistant to be a reasonably strong mechanism replay attacks as long as passphrases are well chosen and verifiers are kept secret.
     Making a SCRAM-SHA1 verifier public the appropriate
     nonce is believed unique.

     SCRAM is not resistant to passive dictionary attacks.  User
     education, passphrase setting policy and TLS [TLS] may be used to
     protect against such attacks.

     SCRAM does not protect against session data evesdropping.  TLS
     [TLS] may be used to protect against this.

     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 worse than
     making
     information beyond the salt to a Unix /etc/password verifier public when client which fails verification.
     Note that in order to prevent revealing the existance of a plaintext-only
     mechanism is used.

     There are two particularly dangerous attacks against SCRAM-SHA1. 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 first is server-ext-data may be used to passively record an authentication session (or
     steal protect against downgrade active
     attacks (where the verifier) active attacker changes the advertised protocol
     security services).  CRAM and perform OTP do not have this facility.

     SCRAM protects against account hijacking by an offline dictionary attack active attacker.
     Use of OTP extended response [OTP-EXT] to
     find reset the passphrase.  This type of attack sequence is estimated
     susceptible to account hijacking.

     SCRAM does not protect against connection hijacking or corruption.
     TLS [TLS] or IPAUTH [IPAUTH] may be about
     40% effective at typical sites with current behavior patterns
     [SCHNEIER].  Use 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 term "passphrase", enforcement of site
     policy when passphrases are changed and user education may improve
     user.  CRAM verifiers have this to acceptable levels for many sites.

     The second attack is weakness.

     An attacker which has access to both steal the SCRAM verifier and a
     client exchange for a particular user and
     passively record an authentication session by that user.  This
     results in gains the ability to
     impersonate that user and to other servers using the same salt.  TLS
     [TLS] can make it more than
     doubles difficult to obtain the speed client exchange, but
     does not defend against installation 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 trojan horse server.

     Client Attacks

     As SCRAM is designed for the session after
     authentication.  A passive observer can see information
     transmitted, and an active attacker can hijack the session.  Use user entry of
     an external encryption layer such as TLS [TLS] can address this
     problem.

     This mechanism uses a hash-function combined plaintext passphrase, it
     is vulnerable to passphrase hijacking by trojan horse clients.  OTP
     [OTP] with exclusive-or as a
     simple single-block cipher.  [SCHNEIER] expresses reservations
     about ciphers built using one-way hash functions, although not all
     of his reservations may apply an independent OTP calculator can be used to this limited use.

9. 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
     mechanism.

     This is primarily a derivative of simple hash-based challenge
     response systems.  The hash-based challenge response idea has
     existed since at least 1992, when the RIPE project published the
     SKID algorithm according to [SCHNEIER].

     The repeated-hash idea used to verify the client's authenticator is
     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
     dates back to at least the unix Unix /etc/password system or before. system.  There is
     some discussion of this in [SCHNEIER].

     SCRAM combines these four techniques.  The author of this specification
     first proposed this publicly on a public mailing list July 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.

12. References

     [ABNF] Crocker, D., "Augmented BNF for Syntax Specifications:
     ABNF", Work in progress: draft-ietf-drums-abnf-xx.txt

     [CRAM-MD5] Klensin, Catoe, Krumviede, "IMAP/POP AUTHorize Extension
     for Simple Challenge/Response", RFC 2095, 2195, MCI, January 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
     Authentication", RFC 2104, IBM, UCSD, February 1997.

         <ftp://ds.internic.net/rfc/rfc2104.txt>

     [IMAP4] Crispin, M., "Internet Message Access Protocol - Version
     4rev1", RFC 2060, University of Washington, December 1996.

         <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
     Requirement Levels", RFC 2119, Harvard University, March 1997.

         <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
     for Security", RFC 1750, DEC, Cybercash, MIT, December 1994.

         <ftp://ds.internic.net/rfc/rfc1750.txt>

     [SASL] Myers, "Simple Authentication and Security Layer (SASL)",
     work in progress.

     [SCHNEIER] Schneier, "Applied Cryptography: Protocols, Algorithms
     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
     1760, Bellcore, February 1995.

         <ftp://ds.internic.net/rfc/rfc1760.txt>

     [TLS] Dierks, Allen, "The TLS Protocol Version 1.0", Work in
     progress.

     [UTF8] Yergeau, F. "UTF-8, a transformation format of Unicode and
     ISO 10646", RFC 2044, Alis Technologies, October 1996.

         <ftp://ds.internic.net/rfc/rfc2044.txt>

11.

13. Author's Address

     Chris Newman
     Innosoft International, Inc.
     1050 Lakes Drive
     West Covina, CA 91790 USA

     Email: chris.newman@innosoft.com

A. Appendix - Sample Source Code

     XXX: to be done

B. Appendix - TWEKE Proposal

     Tom Wu has proposed adding a Diffie-Hellman key exchange to this
     mechanism.  Diffie-Hellman works roughly as follows:

     Server picks g, n and x.  Server computes X = g^x mod n.

     server -> client: g, n, X

     Client picks y and computes Y = g^y mod n  and  K = X^y mod n.

     client -> server: Y

     Server computes K = Y^x mod n  (which is the same as the client's
     K).

     If g, n, x and y are sufficiently big and have the right
     characteristics, then both the client and server share K which is
     very difficult for a passive evesdropper to obtain.

     The TWEKE proposal would add the following steps:

     (4.5) Server sends g, n, X.

     (7.5)

     (8.5) Client sends Y.

     and would modify steps (D) (F), (J), (b) and (a) (g) to include the value
     K.  This would result in a protocol safe from passive network
     attacks.  The expense would be reduced performance, the need for a
     bignum math library and possibly a requirement that an export
     license be obtained from certain governments (included the United
     States).  This would not defend against active attacks, but should attacks unless an
     encryption service was added.  This may be free of patent restrictions
     after October 6th, 1997.
     restrictions.

     TWEKE might would be harder to deploy than SCRAM due to the higher math
     and math,
     the use of public key technology.

C. technology and the performance loss.

B. Appendix - Additional Services

     Several additional services are needed to make SCRAM useful in
     various usage scenarios.  These include remote authentication
     database support for servers, authentication database APIs for
     servers, remote passphrase change support for clients, single-
     sign-on
     single-sign-on APIs for clients and management tools.  The server-id is
     service-id and server-key are included to facilite the remote
     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);
     }