Java 中带有 CRAM-MD5 的 SMTP

发布于 2024-07-07 04:37:28 字数 125 浏览 15 评论 0原文

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

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

I need to send email through an (external) SMTP server from Java however this server will only accept CRAM-MD5 authentication, which is not supported by JavaMail.

What would be a good way to get these emails to send? (It must be in Java.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

荭秂 2024-07-14 04:37:28

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

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

在 Geronimo 实现中还有 CramMD5Authenticator

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

Here is thread which says that you need to add the following property:

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

Also in Geronimo implementation there is CramMD5Authenticator

Hope it helps to resolve this old question.

情定在深秋 2024-07-14 04:37:28

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

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

Since Java Mail 1.4.4, CRAM-MD5 is supported for use with smtp.
Just set this parameter to your properties and it will work:

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

野心澎湃 2024-07-14 04:37:28

这并不能直接帮助您,但是,JavaMail 中的 IMAP 连接确实支持 SASL(因此也支持 CRAM-MD5,请参阅 Java SASL 文档) 如果您设置 mail.imap.sasl.enable 布尔属性为 true

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

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

This doesn't help you directly, however, IMAP connections in JavaMail do support SASL (and thus CRAM-MD5, see the Java SASL documentation) if you set the mail.imap.sasl.enable boolean property to true.

Unfortunately, there is no mail.smtp.sasl.enable property, and SASL cannot be enabled for SMTP in JavaMail. :-(

However, you can download the JavaMail source code, and you can try to edit the SMTP code to support SASL in a similar manner to the IMAP code. Good luck!

烂人 2024-07-14 04:37:28

这可能不会对您有帮助,但假设您有正确的库(md5/sha1)并且理想情况下有一个base64编码库(尽管base64的东西很容易自己实现),那么CRAM-MD5和CRAM-SHA1相当容易实现在紧要关头)。

交易如下所示:

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("<[email protected]>")
C: BASE64("[email protected] 8b7c809c4453ce5aa097ea5c899f4f87")

备份一步在计算摘要之前,您会得到:

S: 334 BASE64("<[email protected]>")
C: BASE64("[email protected] ", MD5(("password" XOR opad),MD5(("password" XOR ipad), "<[email protected]>")))

我想现在我把它写出来有点令人困惑,但是相信我,与尝试手动执行 NTLM/SPA 相比,这是轻而易举的事。 如果你有动力,实际上很容易实现。 或者,也许我只是花了很长时间把手放在邮件客户端和服务器的内部,以便再清楚地思考它......

This probably won't help you but CRAM-MD5 and CRAM-SHA1 are fairly easy to implement assuming you have the correct library (md5/sha1) and, idealy, a base64 encoding library (though the base64 stuff is fairly easy to implement yourself in a pinch).

The transaction looks like this:

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

Where NONCE is the once time challenge string, USERNAME is the username you are tryng to authenticate, SECRET is the shared secret ("password"), opad is 0x5C, and ipad is 0x36.

(CRAM-SHA1 would be the same transaction, but using SHA1() instead of MD5() to do the digesting)

So, here's an example of a real CRAM-MD5 transaction

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

Backing up the process a step you get:

S: 334 BASE64("<[email protected]>")
C: BASE64("[email protected] 8b7c809c4453ce5aa097ea5c899f4f87")

Backing up one step further to before the digest is calculated, you get:

S: 334 BASE64("<[email protected]>")
C: BASE64("[email protected] ", MD5(("password" XOR opad),MD5(("password" XOR ipad), "<[email protected]>")))

I guess that's kind of confusing now that I write it out, but trust me, compared to trying to do NTLM/SPA by hand, it's a breeze. If you're motivated, it's actually pretty easy to implement. Or maybe I've just spent way to long with my hands in the guts of mail clients and servers to think about it clearly anymore...

初见终念 2024-07-14 04:37:28

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 = "[email protected]";

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

Very Simple CRAMMD5 program in 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 = "[email protected]";

    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()));
    }
}
吃→可爱长大的 2024-07-14 04:37:28

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

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

如果您下载javaMail的源代码,您将看到函数toHex在“DigestMD5”单元中的实现。 使用这个转换,它会起作用。

I tried the code on the example of a real CRAM-MD5 transaction, and also on the example given into the RFC 2195.

It does not work because the conversion to an hexadecimal string is not correct. For exmaple, with this code, you will obtain "b913a62c7eda7a495b4e6e7334d3890" instead of "b913a602c7eda7a495b4e6e7334d3890" and the sent authentication string will not be correct.

If you download the source code of javaMail, you will see the implementation of the function toHex into the unit "DigestMD5". Using this conversion, it will work.

只为守护你 2024-07-14 04:37:28

更改:

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

Change:

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

To:

for (int i=0;i < result.length; i++) {
  hexString.append(Integer.toHexString((result[i] >>> 4) & 0x0F));
  hexString.append(Integer.toHexString(0x0F & result[i]));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文