使用Java中的CRAM-MD5的SMTP

时间:2008-10-09 11:28:23

标签: java smtp sasl

我需要通过(外部)SMTP服务器从Java发送电子邮件,但此服务器只接受CRAM-MD5身份验证,JavaMail不支持。

将这些电子邮件发送给您的好方法是什么? (它必须是Java。)

7 个答案:

答案 0 :(得分:6)

以下是thread,表示您需要添加以下属性:

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

同样在Geronimo实现中,有CramMD5Authenticator

希望有助于解决这个老问题。

答案 1 :(得分:4)

这对您没有直接帮助,但是,如果将Java SASL documentation布尔属性设置为{{1},则JavaMail中的IMAP连接会支持SASL(因此CRAM-MD5,请参阅mail.imap.sasl.enable) }}

不幸的是,没有true属性,并且无法在JavaMail中为SMTP启用SASL。 : - (

但是,您可以下载JavaMail source code,并且可以尝试编辑SMTP代码以支持SASL,其方式与IMAP代码类似。祝你好运!

答案 2 :(得分:4)

这可能对你没有帮助,但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相比,这是一件轻而易举的事。如果你有动力,实际上很容易实现。或者也许我只是花了很长时间用手掌握邮件客户端和服务器的内容,以便再清楚地思考它......

答案 3 :(得分:4)

JAVA中非常简单的CRAMMD5程序


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 :(得分:4)

自Java Mail 1.4.4起,支持CRAM-MD5与smtp一起使用。 只需将此参数设置为您的属性即可:

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

答案 5 :(得分:2)

我尝试了真实CRAM-MD5事务的示例代码,以及RFC 2195中给出的示例。

它不起作用,因为转换为十六进制字符串不正确。例如,使用此代码,您将获得“b913a62c7eda7a495b4e6e7334d3890”而不是“b913a602c7eda7a495b4e6e7334d3890”,并且发送的身份验证字符串将不正确。

如果你下载javaMail的源代码,你会看到函数toHex的实现进入单元“DigestMD5”。使用此转换,它将起作用。

答案 6 :(得分:1)

更改:

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]));
}