Network Working Group C. Newman Internet Draft:SCRAM-SHA1SCRAM-MD5 SASL Mechanism Innosoft Document:draft-newman-auth-scram-00.txt Septemberdraft-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 mechanismwhich uses only a publicly available cryptographic hash function to provide authenticationsuitable forprotocols.a wide variety of usage scenarios. Itis designed to replace plaintext password mechanisms without significant additional complexity, losscombines the best properties ofperformance 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] andit isOTP [OTP] without aserious 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 additionalsignificant increase in complexity. This document defines theSCRAM-SHA1SCRAM-MD5 SASL mechanism [SASL] using theSHA1 [SHA1]MD5 [MD5] andHMAC-SHA1HMAC-MD5 [HMAC] algorithms. It is suitable for use directly with protocols such as IMAP [IMAP4] and POP [POP3]. 0.Open IssuesChanges from Previous Version (1)Although this mechanism has no new concepts,MD5 is used instead of SHA1 as ithas not had extensive review. Advicepermits backwards- compatibility with CRAM-MD5 verifiers on thecompleteness of the security considerationsserver and it isappreciated.a more commonly available hash function. This should not effect SCRAM's security significantly. (2) TheTWEKE proposal (appendix B)server-proof ismore secure and more complex. Is it an acceptable or desirable tradeoff? Perhaps SCRAM could get 40% penetration intonow independent of theplaintext market and TWEKE could get 30%, would it be worthwhileclient-verifier. This allows a remote authentication service todo TWEKE instead of SCRAMefficiently restrict the services an application server may offer to clients. (3) The salt is included inthis case? What if there'sthe client-key which means that abigger 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 thisHow 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 ofSCRAM-SHA1SCRAM-MD5 This section includes a step-by-step guide for client implementors. Although section76 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 ofinformation: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)AAn optional "clientnonce" of 8 to 256 octets. Itnonce." 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 uniqueand somewhat random. It can be generated by appendingidentifiers combines a process identifier with the systemclock toclock, a sequence number, a random number(adviceand the client's domain name. The random number is important as clocks are often synchronized using insecure protocols. Advice for generatinggoodstrong 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 ofinformation:information. The entire message MUST NOT exceed 1000 characters. (4) An 8-octet salt value, specific to the authentication identity. (5) Aserverservice id consisting of the service name of the protocol's SASL profile followed bya "."an "@" followed by the domain name of the serverfollowed by an "@"andoptional extension dataterminated by NUL.This will not be longer than 512 octets.The client SHOULD verify this is correct. (6) A"server nonce" of 8string containing extension data, terminated by NUL. A client which supports TLS [TLS] or stronger SASL mechanisms can check this to32 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 theSHA1HMAC-MD5 functionto (A),with (A) as the key and the 8-octet salt as the data, producing a20 octet16-octet result. Once this is done, (A) SHOULD be erased from memory. (C) Apply theHMAC-SHA1MD5 functionwithto the result of(B) as the key and(B). This produces a 16-octet result. (D) Apply the8-octet salt (4) value asMD5 function to thedata.result of (C). This produces a20 octet16-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 theHMAC-SHA1HMAC-MD5 function with the result of(C)(D) as the key and the buffer from(D)(E) as the data. This produces a20-octet16-octet result.(F)(G) Create a20-octet16-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) The20-octet16-octet result of step(F).(G). If no client challenge was suppled in step 3, the one-way authentication issuccessful, then the server responds with the following: (8)now complete. (9) A20-octet mutual16-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 theHMAC-SHA1HMAC-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) tore-authenticate. Permanent storage of (B) byre-authenticate to services using theclient is discouraged although it is preferablesame salt, or the intermediate HMAC state from (B) tostoringre-authenticate to any service. Clients SHOULD NOT store theactual passphrase. 3.passphrase itself. 4. Server Implementation ofSCRAM-SHA1.SCRAM-MD5. The section includes a step-by-step guide for server implementors. Although section76 contains the formal definition of the syntax and is the authoritative reference in case of errors here, this section in conjunction with section23 should be sufficient to build a correct implementation. The server's authentication database contains an 8-octetsalt and 20-octetsalt, 16- octet client verifier and a 16-octet server key for each local user. The serverMAYMUST supportremote users using the syntax"user@host" syntax for the authenticationidentity, but if it doesn't it MUST truncate the authenticationidentity atthe "@" sign priorleast tolookup inthe extent of stripping "@host" when it matches the local hostname or rejecting the authenticationdatabase.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 to32248 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 theHMAC-SHA1HMAC-MD5 function with the stored client verifier as the key and the result of (a) as the data. This produces a20-octet16- octet result equal to step(E)(F) above. (c) Exclusive-or the result of (b) with message(7)(8) from the client. This produces a20-octet16-octet result which should be equal to theoutputresult of step(B)(C) above. (d) Apply theHMAC-SHA1MD5 functionwith (c) as the key and the stored salt asto thedata.output of step (c). This produces a20-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 theHMAC-SHA1HMAC-MD5 function with the stored verifier as the key and the buffer from (f) as the data. This produces a20-octet16-octet result. The result of (g) is sent to the clientasto authenticate themutual authentication step. 4.server. 5. ExampleXXX: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 bedone 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 bySCRAM-SHA1 are probably more secure thanSCRAM-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 forSCRAM-SHA1.SCRAM-MD5. In addition, once aSCRAM-SHA1SCRAM-MD5 verifier is stolen, a passive (undetectable)snoopevesdropper of that user logging inwill result ingains the output of step(B)(C) above, which is sufficient to impersonatea user.the user to all services with the same salt. This is far better than current plaintext mechanisms where a passivesnoopevesdropper 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-SHA1SCRAM-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-SHA1SCRAM-MD5 doesn't protect the integrity or privacy of data exchanged after authentication. Use ofan external encryption layerTLS [TLS] or a strongerauthenticationSASL mechanism such as Kerberos is encouraged if this functionality is needed.6. SCRAM-SHA18. SCRAM-MD5 Functional Notation This section is designed to provide a quick understanding ofSCRAM-SHA1SCRAM-MD5 forthe 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 AZwould beis the same as AU, a single NUL is used instead.SVservice is the name of the service and serverp(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 asSHA-1 M(x,y)MD5 MAC(x,y) is a message authentication code (MAC) such asHMAC-SHA1HMAC-MD5 "y" is the key and "x" is the text signed by the key.V is a per-user verifier the server stores ssalt is a per-user salt value the server storesP is the proof the client sends the serverUs is a unique nonce the server sends to the client Uc is a unique nonce the client sends to the server Theverifier (V) isfollowing computedby applying the hash function to the plaintext passphrase, then using the result to signvalues are used in thesalt. Thus: Vexchange: client-chal =M(s, H(p)) The proof (P) is computed as follows: PAZ + AU + Uc server-chal =H(p) XOR M(ssalt +SVservice +Usext-attr +AZUs salted-pass = MAC(salt, pass) client-key = H(salted-pass) client-verifier = H(client-key) shared-key = MAC(server-chal +AUclient-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 + Ucclient-chal (2) server -> client:s + SV + Usserver-chal (3) client -> server:Pclient-proof (4) server -> client:M(AZ + AU + Uc + s + SV + Us, V)server-proof The serververifies P by checking thatstores thefollowing is equal to V: M(s, Psalt, client-verifier and server-key. It authenticates the client by computing: H(client-proof XORM(s + SV + Us + AZ + AU + Uc, V))shared-key) after step 3 and comparing it to the stored client-verifier. The client verifies theserver's identityserver 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 byperformingthe samecomputationuser. OTP, by itself, is not suitable for such services as theserversequence needs to be reset. OTP with OTP extended responses still does not permit simulatanous connections by the same user. Location Independent User SCRAM, CRAM andcomparing itOTP 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 tothe server's result. 7. Formal Syntaxbe scalable to large numbers ofSCRAM-SHA1 Messages Thisusers. OTP is less scalable due to theformal syntactic definition ofneed 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 servermessages. This useswhich limits theABNF [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 MUSTservices 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 besupported 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 ;;aGSSAPI 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-ASCIIdeployment problem for Kerberos. Proxy Authentication SCRAM supports proxy authentication by includingSPACE 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 ofSHA1 [SHA1]MD5 [MD5] and HMAC [HMAC] also apply.SCRAM-SHA1SCRAM 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 isconjecturedresistant tobe a reasonably strong mechanismreplay attacks as long aspassphrases are well chosen and verifiers are kept secret. Making a SCRAM-SHA1 verifier publicthe appropriate nonce isbelievedunique. 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 noworse than makinginformation beyond the salt to aUnix /etc/password verifier public whenclient which fails verification. Note that in order to prevent revealing the existance of aplaintext-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. Thefirst isserver-ext-data may be used topassively record an authentication session (or stealprotect against downgrade active attacks (where theverifier)active attacker changes the advertised protocol security services). CRAM andperformOTP do not have this facility. SCRAM protects against account hijacking by anoffline dictionary attackactive attacker. Use of OTP extended response [OTP-EXT] tofindreset thepassphrase. This type of attacksequence isestimatedsusceptible to account hijacking. SCRAM does not protect against connection hijacking or corruption. TLS [TLS] or IPAUTH [IPAUTH] may beabout 40% effective at typical sites with current behavior patterns [SCHNEIER]. Useused 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 theterm "passphrase", enforcement of site policy when passphrases are changed and user education may improveuser. CRAM verifiers have thisto acceptable levels for many sites. The second attack isweakness. An attacker which has access to bothstealthe SCRAM verifier and a client exchange for a particular userand passively record an authentication session by that user. This results ingains the ability to impersonate that userandto other servers using the same salt. TLS [TLS] can make it morethan doublesdifficult to obtain thespeedclient exchange, but does not defend against installation of adictionary attack or brute-force attack to recover the actual passphrase. For this reason, verifiers should be kept well-protected. This mechanism provides no protectiontrojan horse server. Client Attacks As SCRAM is designed forthe session after authentication. A passive observer can see information transmitted, and an active attacker can hijack the session. Useuser entry ofan external encryption layer such as TLS [TLS] can address this problem. This mechanism usesahash-function combinedplaintext passphrase, it is vulnerable to passphrase hijacking by trojan horse clients. OTP [OTP] withexclusive-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 applyan independent OTP calculator can be used tothis 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 usinga hash function to construct a cipher (with exclusive-or) was originally invented by Peter Gutmann in 1993 according to [SCHNEIER]. The idea of usingsalt to protect against global dictionary attacks dates back to at least theunixUnix /etc/passwordsystem or before.system. There is some discussion of this in [SCHNEIER]. SCRAM combines thesefourtechniques. The author of this specification first proposed thispubliclyon 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", RFC2095,2195, MCI,JanuarySeptember 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 activeattacks, but shouldattacks unless an encryption service was added. This may be free of patentrestrictions after October 6th, 1997.restrictions. TWEKEmightwould be harder to deploy than SCRAM due to the highermath andmath, the use of public keytechnology. 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-onsingle-sign-on APIs for clients and management tools. Theserver-id isservice-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); }