SMTP с CRAM-MD5 в Java - PullRequest
       59

SMTP с CRAM-MD5 в Java

6 голосов
/ 09 октября 2008

Мне нужно отправлять электронную почту через (внешний) SMTP-сервер из Java, однако этот сервер будет принимать только аутентификацию CRAM-MD5, которая не поддерживается JavaMail.

Как можно было бы получить эти электронные письма для отправки? (Должно быть на Java.)

Ответы [ 7 ]

6 голосов
/ 24 августа 2012

Вот поток , который говорит, что вам нужно добавить следующее свойство:

props.put("mail.smtp.auth.mechanisms", "CRAM-MD5")

Также в реализации Geronimo есть CramMD5Authenticator

Надеюсь, это поможет решить этот старый вопрос.

4 голосов
/ 28 августа 2012

Начиная с Java Mail 1.4.4, CRAM-MD5 поддерживается для использования с SMTP. Просто установите этот параметр для ваших свойств, и он будет работать:

props.put("mail.smtp.sasl.enable", "true");

4 голосов
/ 31 декабря 2008

Очень простая программа CRAMMD5 на JAVA


import java.security.*;

class CRAMMD5Test
{
public static void main(String[] args) throws Exception
{
    // This represents the BASE64 encoded timestamp sent by the POP server
    String dataString = Base64Decoder.decode("PDAwMDAuMDAwMDAwMDAwMEBteDEuc2VydmVyLmNvbT4=");
    byte[] data = dataString.getBytes();

    // The password to access the account
    byte[] key  = new String("password").getBytes();

    // The address of the e-mail account
    String user = "client@server.com";

    MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.reset();

    if (key.length > 64)
        key = md5.digest(key);

    byte[] k_ipad = new byte[64];
    byte[] k_opad = new byte[64];

    System.arraycopy(key, 0, k_ipad, 0, key.length);
    System.arraycopy(key, 0, k_opad, 0, key.length);

    for (int i=0; i<64; i++)
    {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
    }

    byte[] i_temp = new byte[k_ipad.length + data.length];

    System.arraycopy(k_ipad, 0, i_temp, 0, k_ipad.length);
    System.arraycopy(data, 0, i_temp, k_ipad.length, data.length);

    i_temp = md5.digest(i_temp);

    byte[] o_temp = new byte[k_opad.length + i_temp.length];

    System.arraycopy(k_opad, 0, o_temp, 0, k_opad.length);
    System.arraycopy(i_temp, 0, o_temp, k_opad.length, i_temp.length);

        byte[] result = md5.digest(o_temp);
        StringBuffer hexString = new StringBuffer();

        for (int i=0;i < result.length; i++) {
                hexString.append(Integer.toHexString((result[i] >>> 4) & 0x0F));
                hexString.append(Integer.toHexString(0x0F & result[i]));
             }


        System.out.println(Base64Encoder.encode(user + " " + hexString.toString()));
    }
}
4 голосов
/ 09 октября 2008

Это, вероятно, не поможет, но CRAM-MD5 и CRAM-SHA1 довольно легко реализовать, если у вас есть правильная библиотека (md5 / sha1) и, в идеале, библиотека кодирования base64 (хотя вещи с base64 довольно просты) реализовать себя в крайнем случае).

Транзакция выглядит так:

C: AUTH CRAM-MD5
S: 334 BASE64(NONCE)
C: BASE64(USERNAME, " ", MD5((SECRET XOR opad),MD5((SECRET XOR ipad), NONCE)))
S: 235 Authentication succeeded

Где NONCE - это строка вызова для однократного времени, USERNAME - это имя пользователя, которое вы пытаетесь аутентифицировать, SECRET - это общий секрет («пароль»), opad - 0x5C, а ipad - 0x36.

(CRAM-SHA1 будет той же транзакцией, но с использованием SHA1 () вместо MD5 () для переваривания)

Итак, вот пример реальной транзакции CRAM-MD5

C: AUTH CRAM-MD5
S: 334 PDQ1MDMuMTIyMzU1Nzg2MkBtYWlsMDEuZXhhbXBsZS5jb20+
C: dXNlckBleGFtcGxlLmNvbSA4YjdjODA5YzQ0NTNjZTVhYTA5N2VhNWM4OTlmNGY4Nw==
S: 235 Authentication succeeded

Резервное копирование процесса на шаг, который вы получите:

S: 334 BASE64("<4503.1223557862@mail01.example.com>")
C: BASE64("user@example.com 8b7c809c4453ce5aa097ea5c899f4f87")

Если сделать шаг вперед до вычисления дайджеста, вы получите:

S: 334 BASE64("<4503.1223557862@mail01.example.com>")
C: BASE64("user@example.com ", MD5(("password" XOR opad),MD5(("password" XOR ipad), "<4503.1223557862@mail01.example.com>")))

Полагаю, это немного сбивает с толку, когда я это записываю, но, поверьте мне, по сравнению с попыткой сделать NTLM / SPA вручную, это очень просто. Если вы мотивированы, это на самом деле довольно легко реализовать. Или, может быть, я потратил много времени на то, чтобы держать в руках почтовых клиентов и серверов, чтобы больше думать об этом ...

4 голосов
/ 09 октября 2008

Это не поможет вам напрямую, однако соединения IMAP в JavaMail поддерживают SASL (и, следовательно, CRAM-MD5, см. Документацию Java SASL ), если вы установите mail.imap.sasl.enable логическое свойство до true.

К сожалению, свойства mail.smtp.sasl.enable нет, и SASL не может быть включен для SMTP в JavaMail. : - (

Однако вы можете загрузить исходный код JavaMail и попытаться отредактировать код SMTP для поддержки SASL аналогично коду IMAP. Удачи!

2 голосов
/ 22 января 2009

Я попробовал код на примере реальной транзакции CRAM-MD5, а также на примере, приведенном в RFC 2195.

Это не работает, потому что преобразование в шестнадцатеричную строку не является правильным. Например, с этим кодом вы получите «b913a62c7eda7a495b4e6e7334d3890» вместо «b913a602c7eda7a495b4e6e7334d3890», и отправленная строка аутентификации будет неправильной.

Если вы загрузите исходный код javaMail, вы увидите реализацию функции toHex в модуле «DigestMD5». Используя это преобразование, оно будет работать.

1 голос
/ 04 февраля 2009

Изменение:

for (int i=0; i<result.length; i++)
  hexString.append(Integer.toHexString(0xFF & result[i]));

Кому:

for (int i=0;i < result.length; i++) {
  hexString.append(Integer.toHexString((result[i] >>> 4) & 0x0F));
  hexString.append(Integer.toHexString(0x0F & result[i]));
}
...