2011-04-07 11:11:32 -04:00
|
|
|
package com.fsck.k9.mail;
|
|
|
|
|
|
|
|
import java.security.MessageDigest;
|
|
|
|
|
|
|
|
import com.fsck.k9.mail.filter.Base64;
|
|
|
|
import com.fsck.k9.mail.filter.Hex;
|
|
|
|
|
|
|
|
public class Authentication {
|
2011-04-12 08:16:22 -04:00
|
|
|
private static final String US_ASCII = "US-ASCII";
|
2011-04-07 11:11:32 -04:00
|
|
|
|
2011-04-12 08:16:22 -04:00
|
|
|
/**
|
|
|
|
* Computes the response for CRAM-MD5 authentication mechanism given the user credentials and
|
|
|
|
* the server-provided nonce.
|
|
|
|
*
|
|
|
|
* @param username The username.
|
|
|
|
* @param password The password.
|
|
|
|
* @param b64Nonce The nonce as base64-encoded string.
|
|
|
|
* @return The CRAM-MD5 response.
|
|
|
|
*
|
|
|
|
* @throws AuthenticationFailedException If something went wrong.
|
|
|
|
*
|
|
|
|
* @see Authentication#computeCramMd5Bytes(String, String, byte[])
|
|
|
|
*/
|
|
|
|
public static String computeCramMd5(String username, String password, String b64Nonce)
|
|
|
|
throws AuthenticationFailedException {
|
2011-04-07 11:11:32 -04:00
|
|
|
|
|
|
|
try {
|
2011-04-12 08:16:22 -04:00
|
|
|
byte[] b64NonceBytes = b64Nonce.getBytes(US_ASCII);
|
|
|
|
byte[] b64CRAM = computeCramMd5Bytes(username, password, b64NonceBytes);
|
|
|
|
return new String(b64CRAM, US_ASCII);
|
2011-04-07 11:11:32 -04:00
|
|
|
} catch (AuthenticationFailedException e) {
|
2011-04-12 08:16:22 -04:00
|
|
|
throw e;
|
2011-04-07 11:11:32 -04:00
|
|
|
} catch (Exception e) {
|
2011-04-12 08:16:22 -04:00
|
|
|
throw new AuthenticationFailedException("This shouldn't happen", e);
|
2011-04-07 11:11:32 -04:00
|
|
|
}
|
2011-04-12 08:16:22 -04:00
|
|
|
}
|
2011-04-07 11:11:32 -04:00
|
|
|
|
2011-04-12 08:16:22 -04:00
|
|
|
/**
|
|
|
|
* Computes the response for CRAM-MD5 authentication mechanism given the user credentials and
|
|
|
|
* the server-provided nonce.
|
|
|
|
*
|
|
|
|
* @param username The username.
|
|
|
|
* @param password The password.
|
|
|
|
* @param b64Nonce The nonce as base64-encoded byte array.
|
|
|
|
* @return The CRAM-MD5 response as byte array.
|
|
|
|
*
|
|
|
|
* @throws AuthenticationFailedException If something went wrong.
|
|
|
|
*
|
|
|
|
* @see <a href="https://tools.ietf.org/html/rfc2195">RFC 2195</a>
|
|
|
|
*/
|
|
|
|
public static byte[] computeCramMd5Bytes(String username, String password, byte[] b64Nonce)
|
|
|
|
throws AuthenticationFailedException {
|
2011-04-07 11:11:32 -04:00
|
|
|
|
|
|
|
try {
|
2011-04-12 08:16:22 -04:00
|
|
|
byte[] nonce = Base64.decodeBase64(b64Nonce);
|
2011-04-07 11:11:32 -04:00
|
|
|
|
2011-04-12 08:16:22 -04:00
|
|
|
byte[] secretBytes = password.getBytes(US_ASCII);
|
|
|
|
MessageDigest md = MessageDigest.getInstance("MD5");
|
|
|
|
if (secretBytes.length > 64) {
|
|
|
|
secretBytes = md.digest(secretBytes);
|
|
|
|
}
|
2011-04-07 11:11:32 -04:00
|
|
|
|
2011-04-12 08:16:22 -04:00
|
|
|
byte[] ipad = new byte[64];
|
|
|
|
byte[] opad = new byte[64];
|
|
|
|
System.arraycopy(secretBytes, 0, ipad, 0, secretBytes.length);
|
|
|
|
System.arraycopy(secretBytes, 0, opad, 0, secretBytes.length);
|
|
|
|
for (int i = 0; i < ipad.length; i++) ipad[i] ^= 0x36;
|
|
|
|
for (int i = 0; i < opad.length; i++) opad[i] ^= 0x5c;
|
2011-04-07 11:11:32 -04:00
|
|
|
|
2011-04-12 08:16:22 -04:00
|
|
|
md.update(ipad);
|
|
|
|
byte[] firstPass = md.digest(nonce);
|
2011-04-07 11:11:32 -04:00
|
|
|
|
2011-04-12 08:16:22 -04:00
|
|
|
md.update(opad);
|
|
|
|
byte[] result = md.digest(firstPass);
|
2011-04-07 11:11:32 -04:00
|
|
|
|
2011-04-12 08:16:22 -04:00
|
|
|
String plainCRAM = username + " " + new String(Hex.encodeHex(result));
|
|
|
|
byte[] b64CRAM = Base64.encodeBase64(plainCRAM.getBytes(US_ASCII));
|
2011-04-07 11:11:32 -04:00
|
|
|
|
2011-04-12 08:16:22 -04:00
|
|
|
return b64CRAM;
|
2011-04-07 11:11:32 -04:00
|
|
|
|
|
|
|
} catch (Exception e) {
|
2011-04-12 08:16:22 -04:00
|
|
|
throw new AuthenticationFailedException("Something went wrong during CRAM-MD5 computation", e);
|
2011-04-07 11:11:32 -04:00
|
|
|
}
|
2011-04-12 08:16:22 -04:00
|
|
|
}
|
2011-04-07 11:11:32 -04:00
|
|
|
}
|