3737public class Realm {
3838
3939private static final String DEFAULT_NC ="00000001" ;
40+ // MD5("")
4041private static final String EMPTY_ENTITY_MD5 ="d41d8cd98f00b204e9800998ecf8427e" ;
4142
4243private final String principal ;
@@ -412,26 +413,35 @@ private byte[] md5FromRecycledStringBuilder(StringBuilder sb, MessageDigest md)
412413return md .digest ();
413414 }
414415
415- private byte []secretDigest (StringBuilder sb ,MessageDigest md ) {
416+ private byte []ha1 (StringBuilder sb ,MessageDigest md ) {
417+ // if algorithm is "MD5" or is unspecified => A1 = username ":" realm-value ":" passwd
418+ // if algorithm is "MD5-sess" => A1 = MD5( username-value ":" realm-value ":" passwd ) ":" nonce-value ":" cnonce-value
416419
417420sb .append (principal ).append (':' ).append (realmName ).append (':' ).append (password );
418- byte []ha1 =md5FromRecycledStringBuilder (sb ,md );
421+ byte []core =md5FromRecycledStringBuilder (sb ,md );
419422
420423if (algorithm ==null ||algorithm .equals ("MD5" )) {
421- return ha1 ;
424+ // A1 = username ":" realm-value ":" passwd
425+ return core ;
422426 }else if ("MD5-sess" .equals (algorithm )) {
423- appendBase16 (sb ,ha1 );
427+ // A1 = MD5(username ":" realm-value ":" passwd ) ":" nonce ":" cnonce
428+ appendBase16 (sb ,core );
424429sb .append (':' ).append (nonce ).append (':' ).append (cnonce );
425430return md5FromRecycledStringBuilder (sb ,md );
426431 }
427432
428433throw new UnsupportedOperationException ("Digest algorithm not supported: " +algorithm );
429434 }
430435
431- private byte []dataDigest (StringBuilder sb ,String digestUri ,MessageDigest md ) {
436+ private byte []ha2 (StringBuilder sb ,String digestUri ,MessageDigest md ) {
432437
438+ // if qop is "auth" or is unspecified => A2 = Method ":" digest-uri-value
439+ // if qop is "auth-int" => A2 = Method ":" digest-uri-value ":" H(entity-body)
433440sb .append (methodName ).append (':' ).append (digestUri );
434441if ("auth-int" .equals (qop )) {
442+ // when qop == "auth-int", A2 = Method ":" digest-uri-value ":" H(entity-body)
443+ // but we don't have the request body here
444+ // we would need a new API
435445sb .append (':' ).append (EMPTY_ENTITY_MD5 );
436446
437447 }else if (qop !=null && !qop .equals ("auth" )) {
@@ -441,7 +451,8 @@ private byte[] dataDigest(StringBuilder sb, String digestUri, MessageDigest md)
441451return md5FromRecycledStringBuilder (sb ,md );
442452 }
443453
444- private void appendDataBase (StringBuilder sb ) {
454+ private void appendMiddlePart (StringBuilder sb ) {
455+ // request-digest = MD5(H(A1) ":" nonce ":" nc ":" cnonce ":" qop ":" H(A2))
445456sb .append (':' ).append (nonce ).append (':' );
446457if ("auth" .equals (qop ) ||"auth-int" .equals (qop )) {
447458sb .append (nc ).append (':' ).append (cnonce ).append (':' ).append (qop ).append (':' );
@@ -457,12 +468,12 @@ private void newResponse(MessageDigest md) {
457468StringBuilder sb =StringBuilderPool .DEFAULT .stringBuilder ();
458469
459470// WARNING: DON'T MOVE, BUFFER IS RECYCLED!!!!
460- byte []secretDigest =secretDigest (sb ,md );
461- byte []dataDigest =dataDigest (sb ,digestUri ,md );
471+ byte []ha1 =ha1 (sb ,md );
472+ byte []ha2 =ha2 (sb ,digestUri ,md );
462473
463- appendBase16 (sb ,secretDigest );
464- appendDataBase (sb );
465- appendBase16 (sb ,dataDigest );
474+ appendBase16 (sb ,ha1 );
475+ appendMiddlePart (sb );
476+ appendBase16 (sb ,ha2 );
466477
467478byte []responseDigest =md5FromRecycledStringBuilder (sb ,md );
468479response =toHexString (responseDigest );