使用Java中的CRAM-MD5的SMTP

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

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

这是一个线程 ,表示您需要添加以下属性:

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

同样在Geronimo实现中有CramMD5Authenticator

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

这对您没有直接帮助,但是,如果将mail.imap.sasl.enable布尔属性设置为true ,则JavaMail中的IMAP连接会支持SASL(以及CRAM-MD5,请参阅Java SASL文档 )。

遗憾的是,没有mail.smtp.sasl.enable属性,并且无法在JavaMail中为SMTP启用SASL。 🙁

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

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

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

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

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

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

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

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

更改:

 for (int i=0; i 

至:

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