mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
430
src/java.base/share/classes/com/sun/security/ntlm/NTLM.java
Normal file
430
src/java.base/share/classes/com/sun/security/ntlm/NTLM.java
Normal file
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.security.ntlm;
|
||||
|
||||
import static com.sun.security.ntlm.Version.*;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.DESKeySpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* NTLM authentication implemented according to MS-NLMP, version 12.1
|
||||
* @since 1.7
|
||||
*/
|
||||
class NTLM {
|
||||
|
||||
private final SecretKeyFactory fac;
|
||||
private final Cipher cipher;
|
||||
private final MessageDigest md4;
|
||||
private final Mac hmac;
|
||||
private final MessageDigest md5;
|
||||
private static final boolean DEBUG =
|
||||
java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetBooleanAction("ntlm.debug"))
|
||||
.booleanValue();
|
||||
|
||||
final Version v;
|
||||
|
||||
final boolean writeLM;
|
||||
final boolean writeNTLM;
|
||||
|
||||
protected NTLM(String version) throws NTLMException {
|
||||
if (version == null) version = "LMv2/NTLMv2";
|
||||
switch (version) {
|
||||
case "LM": v = NTLM; writeLM = true; writeNTLM = false; break;
|
||||
case "NTLM": v = NTLM; writeLM = false; writeNTLM = true; break;
|
||||
case "LM/NTLM": v = NTLM; writeLM = writeNTLM = true; break;
|
||||
case "NTLM2": v = NTLM2; writeLM = writeNTLM = true; break;
|
||||
case "LMv2": v = NTLMv2; writeLM = true; writeNTLM = false; break;
|
||||
case "NTLMv2": v = NTLMv2; writeLM = false; writeNTLM = true; break;
|
||||
case "LMv2/NTLMv2": v = NTLMv2; writeLM = writeNTLM = true; break;
|
||||
default: throw new NTLMException(NTLMException.BAD_VERSION,
|
||||
"Unknown version " + version);
|
||||
}
|
||||
try {
|
||||
fac = SecretKeyFactory.getInstance ("DES");
|
||||
cipher = Cipher.getInstance ("DES/ECB/NoPadding");
|
||||
md4 = sun.security.provider.MD4.getInstance();
|
||||
hmac = Mac.getInstance("HmacMD5");
|
||||
md5 = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchPaddingException e) {
|
||||
throw new AssertionError();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints out a formatted string, called in various places inside then NTLM
|
||||
* implementation for debugging/logging purposes. When the system property
|
||||
* "ntlm.debug" is set, <code>System.out.printf(format, args)</code> is
|
||||
* called. This method is designed to be overridden by child classes to
|
||||
* match their own debugging/logging mechanisms.
|
||||
* @param format a format string
|
||||
* @param args the arguments referenced by <code>format</code>
|
||||
* @see java.io.PrintStream#printf(java.lang.String, java.lang.Object[])
|
||||
*/
|
||||
public void debug(String format, Object... args) {
|
||||
if (DEBUG) {
|
||||
System.out.printf(format, args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints out the content of a byte array, called in various places inside
|
||||
* the NTLM implementation for debugging/logging purposes. When the system
|
||||
* property "ntlm.debug" is set, the hexdump of the array is printed into
|
||||
* System.out. This method is designed to be overridden by child classes to
|
||||
* match their own debugging/logging mechanisms.
|
||||
* @param bytes the byte array to print out
|
||||
*/
|
||||
public void debug(byte[] bytes) {
|
||||
if (DEBUG) {
|
||||
try {
|
||||
new sun.security.util.HexDumpEncoder().encodeBuffer(bytes, System.out);
|
||||
} catch (IOException ioe) {
|
||||
// Impossible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading an NTLM packet
|
||||
*/
|
||||
static class Reader {
|
||||
|
||||
private final byte[] internal;
|
||||
|
||||
Reader(byte[] data) {
|
||||
internal = data;
|
||||
}
|
||||
|
||||
int readInt(int offset) throws NTLMException {
|
||||
try {
|
||||
return (internal[offset] & 0xff) +
|
||||
((internal[offset+1] & 0xff) << 8) +
|
||||
((internal[offset+2] & 0xff) << 16) +
|
||||
((internal[offset+3] & 0xff) << 24);
|
||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
|
||||
"Input message incorrect size");
|
||||
}
|
||||
}
|
||||
|
||||
int readShort(int offset) throws NTLMException {
|
||||
try {
|
||||
return (internal[offset] & 0xff) +
|
||||
((internal[offset+1] & 0xff << 8));
|
||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
|
||||
"Input message incorrect size");
|
||||
}
|
||||
}
|
||||
|
||||
byte[] readBytes(int offset, int len) throws NTLMException {
|
||||
try {
|
||||
return Arrays.copyOfRange(internal, offset, offset + len);
|
||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
|
||||
"Input message incorrect size");
|
||||
}
|
||||
}
|
||||
|
||||
byte[] readSecurityBuffer(int offset) throws NTLMException {
|
||||
int pos = readInt(offset+4);
|
||||
if (pos == 0) return new byte[0];
|
||||
try {
|
||||
return Arrays.copyOfRange(
|
||||
internal, pos, pos + readShort(offset));
|
||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
|
||||
"Input message incorrect size");
|
||||
}
|
||||
}
|
||||
|
||||
String readSecurityBuffer(int offset, boolean unicode)
|
||||
throws NTLMException {
|
||||
byte[] raw = readSecurityBuffer(offset);
|
||||
try {
|
||||
return raw == null ? null : new String(
|
||||
raw, unicode ? "UnicodeLittleUnmarked" : "ISO8859_1");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
|
||||
"Invalid input encoding");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writing an NTLM packet
|
||||
*/
|
||||
static class Writer {
|
||||
|
||||
private byte[] internal; // buffer
|
||||
private int current; // current written content interface buffer
|
||||
|
||||
/**
|
||||
* Starts writing a NTLM packet
|
||||
* @param type NEGOTIATE || CHALLENGE || AUTHENTICATE
|
||||
* @param len the base length, without security buffers
|
||||
*/
|
||||
Writer(int type, int len) {
|
||||
assert len < 256;
|
||||
internal = new byte[256];
|
||||
current = len;
|
||||
System.arraycopy (
|
||||
new byte[] {'N','T','L','M','S','S','P',0,(byte)type},
|
||||
0, internal, 0, 9);
|
||||
}
|
||||
|
||||
void writeShort(int offset, int number) {
|
||||
internal[offset] = (byte)(number);
|
||||
internal[offset+1] = (byte)(number >> 8);
|
||||
}
|
||||
|
||||
void writeInt(int offset, int number) {
|
||||
internal[offset] = (byte)(number);
|
||||
internal[offset+1] = (byte)(number >> 8);
|
||||
internal[offset+2] = (byte)(number >> 16);
|
||||
internal[offset+3] = (byte)(number >> 24);
|
||||
}
|
||||
|
||||
void writeBytes(int offset, byte[] data) {
|
||||
System.arraycopy(data, 0, internal, offset, data.length);
|
||||
}
|
||||
|
||||
void writeSecurityBuffer(int offset, byte[] data) {
|
||||
if (data == null) {
|
||||
writeShort(offset+4, current);
|
||||
} else {
|
||||
int len = data.length;
|
||||
if (current + len > internal.length) {
|
||||
internal = Arrays.copyOf(internal, current + len + 256);
|
||||
}
|
||||
writeShort(offset, len);
|
||||
writeShort(offset+2, len);
|
||||
writeShort(offset+4, current);
|
||||
System.arraycopy(data, 0, internal, current, len);
|
||||
current += len;
|
||||
}
|
||||
}
|
||||
|
||||
void writeSecurityBuffer(int offset, String str, boolean unicode) {
|
||||
try {
|
||||
writeSecurityBuffer(offset, str == null ? null : str.getBytes(
|
||||
unicode ? "UnicodeLittleUnmarked" : "ISO8859_1"));
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] getBytes() {
|
||||
return Arrays.copyOf(internal, current);
|
||||
}
|
||||
}
|
||||
|
||||
// LM/NTLM
|
||||
|
||||
/* Convert a 7 byte array to an 8 byte array (for a des key with parity)
|
||||
* input starts at offset off
|
||||
*/
|
||||
byte[] makeDesKey (byte[] input, int off) {
|
||||
int[] in = new int [input.length];
|
||||
for (int i=0; i<in.length; i++ ) {
|
||||
in[i] = input[i]<0 ? input[i]+256: input[i];
|
||||
}
|
||||
byte[] out = new byte[8];
|
||||
out[0] = (byte)in[off+0];
|
||||
out[1] = (byte)(((in[off+0] << 7) & 0xFF) | (in[off+1] >> 1));
|
||||
out[2] = (byte)(((in[off+1] << 6) & 0xFF) | (in[off+2] >> 2));
|
||||
out[3] = (byte)(((in[off+2] << 5) & 0xFF) | (in[off+3] >> 3));
|
||||
out[4] = (byte)(((in[off+3] << 4) & 0xFF) | (in[off+4] >> 4));
|
||||
out[5] = (byte)(((in[off+4] << 3) & 0xFF) | (in[off+5] >> 5));
|
||||
out[6] = (byte)(((in[off+5] << 2) & 0xFF) | (in[off+6] >> 6));
|
||||
out[7] = (byte)((in[off+6] << 1) & 0xFF);
|
||||
return out;
|
||||
}
|
||||
|
||||
byte[] calcLMHash (byte[] pwb) {
|
||||
byte[] magic = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
|
||||
byte[] pwb1 = new byte [14];
|
||||
int len = pwb.length;
|
||||
if (len > 14)
|
||||
len = 14;
|
||||
System.arraycopy (pwb, 0, pwb1, 0, len); /* Zero padded */
|
||||
|
||||
try {
|
||||
DESKeySpec dks1 = new DESKeySpec (makeDesKey (pwb1, 0));
|
||||
DESKeySpec dks2 = new DESKeySpec (makeDesKey (pwb1, 7));
|
||||
|
||||
SecretKey key1 = fac.generateSecret (dks1);
|
||||
SecretKey key2 = fac.generateSecret (dks2);
|
||||
cipher.init (Cipher.ENCRYPT_MODE, key1);
|
||||
byte[] out1 = cipher.doFinal (magic, 0, 8);
|
||||
cipher.init (Cipher.ENCRYPT_MODE, key2);
|
||||
byte[] out2 = cipher.doFinal (magic, 0, 8);
|
||||
byte[] result = new byte [21];
|
||||
System.arraycopy (out1, 0, result, 0, 8);
|
||||
System.arraycopy (out2, 0, result, 8, 8);
|
||||
return result;
|
||||
} catch (InvalidKeyException ive) {
|
||||
// Will not happen, all key material are 8 bytes
|
||||
assert false;
|
||||
} catch (InvalidKeySpecException ikse) {
|
||||
// Will not happen, we only feed DESKeySpec to DES factory
|
||||
assert false;
|
||||
} catch (IllegalBlockSizeException ibse) {
|
||||
// Will not happen, we encrypt 8 bytes
|
||||
assert false;
|
||||
} catch (BadPaddingException bpe) {
|
||||
// Will not happen, this is encryption
|
||||
assert false;
|
||||
}
|
||||
return null; // will not happen, we returned already
|
||||
}
|
||||
|
||||
byte[] calcNTHash (byte[] pw) {
|
||||
byte[] out = md4.digest (pw);
|
||||
byte[] result = new byte [21];
|
||||
System.arraycopy (out, 0, result, 0, 16);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* key is a 21 byte array. Split it into 3 7 byte chunks,
|
||||
* Convert each to 8 byte DES keys, encrypt the text arg with
|
||||
* each key and return the three results in a sequential []
|
||||
*/
|
||||
byte[] calcResponse (byte[] key, byte[] text) {
|
||||
try {
|
||||
assert key.length == 21;
|
||||
DESKeySpec dks1 = new DESKeySpec(makeDesKey(key, 0));
|
||||
DESKeySpec dks2 = new DESKeySpec(makeDesKey(key, 7));
|
||||
DESKeySpec dks3 = new DESKeySpec(makeDesKey(key, 14));
|
||||
SecretKey key1 = fac.generateSecret(dks1);
|
||||
SecretKey key2 = fac.generateSecret(dks2);
|
||||
SecretKey key3 = fac.generateSecret(dks3);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key1);
|
||||
byte[] out1 = cipher.doFinal(text, 0, 8);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key2);
|
||||
byte[] out2 = cipher.doFinal(text, 0, 8);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key3);
|
||||
byte[] out3 = cipher.doFinal(text, 0, 8);
|
||||
byte[] result = new byte[24];
|
||||
System.arraycopy(out1, 0, result, 0, 8);
|
||||
System.arraycopy(out2, 0, result, 8, 8);
|
||||
System.arraycopy(out3, 0, result, 16, 8);
|
||||
return result;
|
||||
} catch (IllegalBlockSizeException ex) { // None will happen
|
||||
assert false;
|
||||
} catch (BadPaddingException ex) {
|
||||
assert false;
|
||||
} catch (InvalidKeySpecException ex) {
|
||||
assert false;
|
||||
} catch (InvalidKeyException ex) {
|
||||
assert false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// LMv2/NTLMv2
|
||||
|
||||
byte[] hmacMD5(byte[] key, byte[] text) {
|
||||
try {
|
||||
SecretKeySpec skey =
|
||||
new SecretKeySpec(Arrays.copyOf(key, 16), "HmacMD5");
|
||||
hmac.init(skey);
|
||||
return hmac.doFinal(text);
|
||||
} catch (InvalidKeyException ex) {
|
||||
assert false;
|
||||
} catch (RuntimeException e) {
|
||||
assert false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] calcV2(byte[] nthash, String text, byte[] blob, byte[] challenge) {
|
||||
try {
|
||||
byte[] ntlmv2hash = hmacMD5(nthash,
|
||||
text.getBytes("UnicodeLittleUnmarked"));
|
||||
byte[] cn = new byte[blob.length+8];
|
||||
System.arraycopy(challenge, 0, cn, 0, 8);
|
||||
System.arraycopy(blob, 0, cn, 8, blob.length);
|
||||
byte[] result = new byte[16+blob.length];
|
||||
System.arraycopy(hmacMD5(ntlmv2hash, cn), 0, result, 0, 16);
|
||||
System.arraycopy(blob, 0, result, 16, blob.length);
|
||||
return result;
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
assert false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// NTLM2 LM/NTLM
|
||||
|
||||
static byte[] ntlm2LM(byte[] nonce) {
|
||||
return Arrays.copyOf(nonce, 24);
|
||||
}
|
||||
|
||||
byte[] ntlm2NTLM(byte[] ntlmHash, byte[] nonce, byte[] challenge) {
|
||||
byte[] b = Arrays.copyOf(challenge, 16);
|
||||
System.arraycopy(nonce, 0, b, 8, 8);
|
||||
byte[] sesshash = Arrays.copyOf(md5.digest(b), 8);
|
||||
return calcResponse(ntlmHash, sesshash);
|
||||
}
|
||||
|
||||
// Password in ASCII and UNICODE
|
||||
|
||||
static byte[] getP1(char[] password) {
|
||||
try {
|
||||
return new String(password).toUpperCase(
|
||||
Locale.ENGLISH).getBytes("ISO8859_1");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] getP2(char[] password) {
|
||||
try {
|
||||
return new String(password).getBytes("UnicodeLittleUnmarked");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue