Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

New self-contained NTLM support, from the JDK (with permission).

  • Loading branch information...
Bill Shannon
Bill Shannon committed Dec 19, 2009
1 parent 84cfb07 commit 081f632e1fd8ae5fa6f96a0360dc9a681c3eaa79
@@ -25,6 +25,7 @@ G 11069 update the mail.jar manifest to include DynamicImport-Package
<no id> properly disable TOP if POP3 CAPA response doesn't include it
<no id> add mail.pop3.disablecapa property to disable use of the CAPA command
<no id> fix support for Properties objects with default Properties objects
<no id> integrate NTLM support, no longer needs jcifs.jar


CHANGES IN THE 1.4.3 RELEASE
@@ -3,15 +3,10 @@

Thanks to the efforts of Luis Serralheiro, JavaMail now suports the use
of Microsoft's proprietary NTLM authentication mechanism. This support
within JavaMail builds on the base NTLM support provided by the JCIFS
project. To use this NTLM support in JavaMail, you'll also need to
include the jcifs jar file in your CLASSPATH. You can download the
latest jcifs jar file from the JCIFS site: http://jcifs.samba.org
JCIFS is available under the LGPL license.
within JavaMail is now derived from the NTLM support in the JDK and
included directly in JavaMail, with no external dependencies.

This release of JavaMail was tested with the 1.3.12 version of JCIFS
and Microsoft Exchange 5.5 and 2007. Note that the 1.2.x versions of
JCIFS won't work as the API has changed incompatibly.
This release of JavaMail was tested with Microsoft Exchange 5.5 and 2007.

The SMTP and IMAP providers support the use of NTLM authentication.
The following properties can be used to configure the NTLM support:
@@ -20,7 +15,7 @@ mail.<protocol>.auth.ntlm.domain
The NTLM authentication domain.

mail.<protocol>.auth.ntlm.flags
NTLM protocol-specific flags.
NTLM protocol-specific flags. (not currently used)
See http://curl.haxx.se/rfc/ntlm.html#theNtlmFlags for details.


@@ -0,0 +1,291 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2005-2009 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/*
* Copied from OpenJDK with permission.
*/

package com.sun.mail.auth;

import java.security.*;

//import static sun.security.provider.ByteArrayAccess.*;

/**
* The MD4 class is used to compute an MD4 message digest over a given
* buffer of bytes. It is an implementation of the RSA Data Security Inc
* MD4 algorithim as described in internet RFC 1320.
*
* @author Andreas Sterbenz
* @author Bill Shannon (adapted for JavaMail)
*/
public final class MD4 {

// state of this object
private final int[] state;
// temporary buffer, used by implCompress()
private final int[] x;

// size of the input to the compression function in bytes
private final int blockSize = 64;

// buffer to store partial blocks, blockSize bytes large
private final byte[] buffer = new byte[blockSize];
// offset into buffer
private int bufOfs;

// number of bytes processed so far.
// also used as a flag to indicate reset status
// -1: need to call engineReset() before next call to update()
// 0: is already reset
private long bytesProcessed;

// rotation constants
private static final int S11 = 3;
private static final int S12 = 7;
private static final int S13 = 11;
private static final int S14 = 19;
private static final int S21 = 3;
private static final int S22 = 5;
private static final int S23 = 9;
private static final int S24 = 13;
private static final int S31 = 3;
private static final int S32 = 9;
private static final int S33 = 11;
private static final int S34 = 15;

private static final byte[] padding;

static {
padding = new byte[136];
padding[0] = (byte)0x80;
}

// Standard constructor, creates a new MD4 instance.
public MD4() {
state = new int[4];
x = new int[16];
implReset();
}

/**
* Compute and return the message digest of the input byte array.
*/
public byte[] digest(byte[] in) {
implReset();
engineUpdate(in, 0, in.length);
byte[] out = new byte[16];
implDigest(out, 0);
return out;
}

/**
* Reset the state of this object.
*/
private void implReset() {
// Load magic initialization constants.
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
bufOfs = 0;
bytesProcessed = 0;
}

/**
* Perform the final computations, any buffered bytes are added
* to the digest, the count is added to the digest, and the resulting
* digest is stored.
*/
private void implDigest(byte[] out, int ofs) {
long bitsProcessed = bytesProcessed << 3;

int index = (int)bytesProcessed & 0x3f;
int padLen = (index < 56) ? (56 - index) : (120 - index);
engineUpdate(padding, 0, padLen);

//i2bLittle4((int)bitsProcessed, buffer, 56);
//i2bLittle4((int)(bitsProcessed >>> 32), buffer, 60);
buffer[56] = (byte)bitsProcessed;
buffer[57] = (byte)(bitsProcessed>>8);
buffer[58] = (byte)(bitsProcessed>>16);
buffer[59] = (byte)(bitsProcessed>>24);
buffer[60] = (byte)(bitsProcessed>>32);
buffer[61] = (byte)(bitsProcessed>>40);
buffer[62] = (byte)(bitsProcessed>>48);
buffer[63] = (byte)(bitsProcessed>>56);
implCompress(buffer, 0);

//i2bLittle(state, 0, out, ofs, 16);
for (int i = 0; i < state.length; i++) {
int x = state[i];
out[ofs++] = (byte)x;
out[ofs++] = (byte)(x>>8);
out[ofs++] = (byte)(x>>16);
out[ofs++] = (byte)(x>>24);
}
}

private void engineUpdate(byte[] b, int ofs, int len) {
if (len == 0) {
return;
}
if ((ofs < 0) || (len < 0) || (ofs > b.length - len)) {
throw new ArrayIndexOutOfBoundsException();
}
if (bytesProcessed < 0) {
implReset();
}
bytesProcessed += len;
// if buffer is not empty, we need to fill it before proceeding
if (bufOfs != 0) {
int n = Math.min(len, blockSize - bufOfs);
System.arraycopy(b, ofs, buffer, bufOfs, n);
bufOfs += n;
ofs += n;
len -= n;
if (bufOfs >= blockSize) {
// compress completed block now
implCompress(buffer, 0);
bufOfs = 0;
}
}
// compress complete blocks
while (len >= blockSize) {
implCompress(b, ofs);
len -= blockSize;
ofs += blockSize;
}
// copy remainder to buffer
if (len > 0) {
System.arraycopy(b, ofs, buffer, 0, len);
bufOfs = len;
}
}

private static int FF(int a, int b, int c, int d, int x, int s) {
a += ((b & c) | ((~b) & d)) + x;
return ((a << s) | (a >>> (32 - s)));
}

private static int GG(int a, int b, int c, int d, int x, int s) {
a += ((b & c) | (b & d) | (c & d)) + x + 0x5a827999;
return ((a << s) | (a >>> (32 - s)));
}

private static int HH(int a, int b, int c, int d, int x, int s) {
a += ((b ^ c) ^ d) + x + 0x6ed9eba1;
return ((a << s) | (a >>> (32 - s)));
}

/**
* This is where the functions come together as the generic MD4
* transformation operation. It consumes 64
* bytes from the buffer, beginning at the specified offset.
*/
private void implCompress(byte[] buf, int ofs) {
//b2iLittle64(buf, ofs, x);
for (int xfs = 0; xfs < x.length; xfs++) {
x[xfs] = (buf[ofs] & 0xff) | ((buf[ofs+1] & 0xff) << 8) |
((buf[ofs+2] & 0xff) << 16) | ((buf[ofs+3] & 0xff) << 24);
ofs += 4;
}

int a = state[0];
int b = state[1];
int c = state[2];
int d = state[3];

/* Round 1 */
a = FF (a, b, c, d, x[ 0], S11); /* 1 */
d = FF (d, a, b, c, x[ 1], S12); /* 2 */
c = FF (c, d, a, b, x[ 2], S13); /* 3 */
b = FF (b, c, d, a, x[ 3], S14); /* 4 */
a = FF (a, b, c, d, x[ 4], S11); /* 5 */
d = FF (d, a, b, c, x[ 5], S12); /* 6 */
c = FF (c, d, a, b, x[ 6], S13); /* 7 */
b = FF (b, c, d, a, x[ 7], S14); /* 8 */
a = FF (a, b, c, d, x[ 8], S11); /* 9 */
d = FF (d, a, b, c, x[ 9], S12); /* 10 */
c = FF (c, d, a, b, x[10], S13); /* 11 */
b = FF (b, c, d, a, x[11], S14); /* 12 */
a = FF (a, b, c, d, x[12], S11); /* 13 */
d = FF (d, a, b, c, x[13], S12); /* 14 */
c = FF (c, d, a, b, x[14], S13); /* 15 */
b = FF (b, c, d, a, x[15], S14); /* 16 */

/* Round 2 */
a = GG (a, b, c, d, x[ 0], S21); /* 17 */
d = GG (d, a, b, c, x[ 4], S22); /* 18 */
c = GG (c, d, a, b, x[ 8], S23); /* 19 */
b = GG (b, c, d, a, x[12], S24); /* 20 */
a = GG (a, b, c, d, x[ 1], S21); /* 21 */
d = GG (d, a, b, c, x[ 5], S22); /* 22 */
c = GG (c, d, a, b, x[ 9], S23); /* 23 */
b = GG (b, c, d, a, x[13], S24); /* 24 */
a = GG (a, b, c, d, x[ 2], S21); /* 25 */
d = GG (d, a, b, c, x[ 6], S22); /* 26 */
c = GG (c, d, a, b, x[10], S23); /* 27 */
b = GG (b, c, d, a, x[14], S24); /* 28 */
a = GG (a, b, c, d, x[ 3], S21); /* 29 */
d = GG (d, a, b, c, x[ 7], S22); /* 30 */
c = GG (c, d, a, b, x[11], S23); /* 31 */
b = GG (b, c, d, a, x[15], S24); /* 32 */

/* Round 3 */
a = HH (a, b, c, d, x[ 0], S31); /* 33 */
d = HH (d, a, b, c, x[ 8], S32); /* 34 */
c = HH (c, d, a, b, x[ 4], S33); /* 35 */
b = HH (b, c, d, a, x[12], S34); /* 36 */
a = HH (a, b, c, d, x[ 2], S31); /* 37 */
d = HH (d, a, b, c, x[10], S32); /* 38 */
c = HH (c, d, a, b, x[ 6], S33); /* 39 */
b = HH (b, c, d, a, x[14], S34); /* 40 */
a = HH (a, b, c, d, x[ 1], S31); /* 41 */
d = HH (d, a, b, c, x[ 9], S32); /* 42 */
c = HH (c, d, a, b, x[ 5], S33); /* 43 */
b = HH (b, c, d, a, x[13], S34); /* 44 */
a = HH (a, b, c, d, x[ 3], S31); /* 45 */
d = HH (d, a, b, c, x[11], S32); /* 46 */
c = HH (c, d, a, b, x[ 7], S33); /* 47 */
b = HH (b, c, d, a, x[15], S34); /* 48 */

state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
}

0 comments on commit 081f632

Please sign in to comment.
You can’t perform that action at this time.