Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
jcifs.internal.smb1.SMB1SigningDigest Maven / Gradle / Ivy
/*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcifs.internal.smb1;
import java.security.MessageDigest;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jcifs.Configuration;
import jcifs.SmbConstants;
import jcifs.internal.CommonServerMessageBlock;
import jcifs.internal.SMBSigningDigest;
import jcifs.internal.smb1.com.SmbComReadAndXResponse;
import jcifs.internal.smb1.trans.nt.SmbComNtCancel;
import jcifs.internal.util.SMBUtil;
import jcifs.smb.NtlmPasswordAuthenticator;
import jcifs.smb.SmbException;
import jcifs.smb.SmbTransportInternal;
import jcifs.util.Crypto;
import jcifs.util.Hexdump;
/**
*
* @internal
*/
public class SMB1SigningDigest implements SMBSigningDigest {
private static final Logger log = LoggerFactory.getLogger(SMB1SigningDigest.class);
private MessageDigest digest;
private byte[] macSigningKey;
private boolean bypass = false;
private int updates;
private int signSequence;
/**
*
* @param macSigningKey
* @param bypass
*/
public SMB1SigningDigest ( byte[] macSigningKey, boolean bypass ) {
this(macSigningKey, bypass, 0);
}
/**
*
* @param macSigningKey
* @param bypass
* @param initialSequence
*/
public SMB1SigningDigest ( byte[] macSigningKey, boolean bypass, int initialSequence ) {
this.digest = Crypto.getMD5();
this.macSigningKey = macSigningKey;
this.signSequence = initialSequence;
this.bypass = bypass;
if ( log.isTraceEnabled() ) {
log.trace("macSigningKey:");
log.trace(Hexdump.toHexString(macSigningKey, 0, macSigningKey.length));
}
}
/**
* This constructor used to instance a SigningDigest object for
* signing/verifying SMB using kerberos session key.
* The MAC Key = concat(Session Key, Digest of Challenge);
* Because of Kerberos Authentication don't have challenge,
* The MAC Key = Session Key
*
* @param macSigningKey
* The MAC key used to sign or verify SMB.
*/
public SMB1SigningDigest ( byte[] macSigningKey ) {
this.digest = Crypto.getMD5();
this.macSigningKey = macSigningKey;
}
/**
* Construct a digest with a non-zero starting sequence number
*
* @param macSigningKey
* @param initialSequence
*/
public SMB1SigningDigest ( byte[] macSigningKey, int initialSequence ) {
this.digest = Crypto.getMD5();
this.macSigningKey = macSigningKey;
this.signSequence = initialSequence;
}
/**
*
* @param transport
* @param auth
* @throws SmbException
*/
public SMB1SigningDigest ( SmbTransportInternal transport, NtlmPasswordAuthenticator auth ) throws SmbException {
this.digest = Crypto.getMD5();
try {
byte[] serverEncryptionKey = transport.getServerEncryptionKey();
switch ( transport.getContext().getConfig().getLanManCompatibility() ) {
case 0:
case 1:
case 2:
this.macSigningKey = new byte[40];
auth.getUserSessionKey(transport.getContext(), serverEncryptionKey, this.macSigningKey, 0);
System.arraycopy(auth.getUnicodeHash(transport.getContext(), serverEncryptionKey), 0, this.macSigningKey, 16, 24);
break;
case 3:
case 4:
case 5:
this.macSigningKey = new byte[16];
auth.getUserSessionKey(transport.getContext(), serverEncryptionKey, this.macSigningKey, 0);
break;
default:
this.macSigningKey = new byte[40];
auth.getUserSessionKey(transport.getContext(), serverEncryptionKey, this.macSigningKey, 0);
System.arraycopy(auth.getUnicodeHash(transport.getContext(), serverEncryptionKey), 0, this.macSigningKey, 16, 24);
break;
}
}
catch ( Exception ex ) {
throw new SmbException("", ex);
}
if ( log.isTraceEnabled() ) {
log.trace("LM_COMPATIBILITY=" + transport.getContext().getConfig().getLanManCompatibility());
log.trace(Hexdump.toHexString(this.macSigningKey, 0, this.macSigningKey.length));
}
}
/**
* Update digest with data
*
* @param input
* @param offset
* @param len
*/
public void update ( byte[] input, int offset, int len ) {
if ( log.isTraceEnabled() ) {
log.trace("update: " + this.updates + " " + offset + ":" + len);
log.trace(Hexdump.toHexString(input, offset, Math.min(len, 256)));
}
if ( len == 0 ) {
return; /* CRITICAL */
}
this.digest.update(input, offset, len);
this.updates++;
}
/**
* @return calculated digest
*/
public byte[] digest () {
byte[] b;
b = this.digest.digest();
if ( log.isTraceEnabled() ) {
log.trace("digest: ");
log.trace(Hexdump.toHexString(b, 0, b.length));
}
this.updates = 0;
return b;
}
/**
* {@inheritDoc}
*
* @see jcifs.internal.SMBSigningDigest#sign(byte[], int, int, jcifs.internal.CommonServerMessageBlock,
* jcifs.internal.CommonServerMessageBlock)
*/
@Override
public void sign ( byte[] data, int offset, int length, CommonServerMessageBlock request, CommonServerMessageBlock response ) {
if ( log.isTraceEnabled() ) {
log.trace("Signing with seq " + this.signSequence);
}
( (ServerMessageBlock) request ).setSignSeq(this.signSequence);
if ( response != null ) {
( (ServerMessageBlock) response ).setSignSeq(this.signSequence + 1);
}
try {
update(this.macSigningKey, 0, this.macSigningKey.length);
int index = offset + SmbConstants.SIGNATURE_OFFSET;
for ( int i = 0; i < 8; i++ )
data[ index + i ] = 0;
SMBUtil.writeInt4(this.signSequence, data, index);
update(data, offset, length);
System.arraycopy(digest(), 0, data, index, 8);
if ( this.bypass ) {
this.bypass = false;
System.arraycopy("BSRSPYL ".getBytes(), 0, data, index, 8);
}
}
catch ( Exception ex ) {
log.error("Signature failed", ex);
}
finally {
if ( request instanceof SmbComNtCancel ) {
this.signSequence++;
}
else {
this.signSequence += 2;
}
}
}
/**
*
* {@inheritDoc}
*
* @see jcifs.internal.SMBSigningDigest#verify(byte[], int, int, int, jcifs.internal.CommonServerMessageBlock)
*/
@Override
public boolean verify ( byte[] data, int offset, int l, int extraPad, CommonServerMessageBlock m ) {
ServerMessageBlock msg = (ServerMessageBlock) m;
if ( ( msg.getFlags2() & SmbConstants.FLAGS2_SECURITY_SIGNATURES ) == 0 ) {
// signature requirements need to be checked somewhere else
log.warn("Expected signed response, but is not signed");
return false;
}
update(this.macSigningKey, 0, this.macSigningKey.length);
int index = offset;
update(data, index, SmbConstants.SIGNATURE_OFFSET);
index += SmbConstants.SIGNATURE_OFFSET;
byte[] sequence = new byte[8];
SMBUtil.writeInt4(msg.getSignSeq(), sequence, 0);
update(sequence, 0, sequence.length);
index += 8;
if ( msg.getCommand() == ServerMessageBlock.SMB_COM_READ_ANDX ) {
/*
* SmbComReadAndXResponse reads directly from the stream into separate byte[] b.
*/
SmbComReadAndXResponse raxr = (SmbComReadAndXResponse) msg;
int length = msg.getLength() - raxr.getDataLength();
update(data, index, length - SmbConstants.SIGNATURE_OFFSET - 8);
update(raxr.getData(), raxr.getOffset(), raxr.getDataLength());
}
else {
update(data, index, msg.getLength() - SmbConstants.SIGNATURE_OFFSET - 8);
}
byte[] signature = digest();
for ( int i = 0; i < 8; i++ ) {
if ( signature[ i ] != data[ offset + SmbConstants.SIGNATURE_OFFSET + i ] ) {
if ( log.isDebugEnabled() ) {
log.debug("signature verification failure"); //$NON-NLS-1$
log.debug("Expect: " + Hexdump.toHexString(signature, 0, 8));
log.debug("Have: " + Hexdump.toHexString(data, offset + SmbConstants.SIGNATURE_OFFSET, 8));
}
return true;
}
}
return false;
}
@Override
public String toString () {
return "MacSigningKey=" + Hexdump.toHexString(this.macSigningKey, 0, this.macSigningKey.length);
}
/**
*
* @param cfg
* @param t
* @param dst
* @param dstIndex
*/
public static void writeUTime ( Configuration cfg, long t, byte[] dst, int dstIndex ) {
if ( t == 0L || t == 0xFFFFFFFFFFFFFFFFL ) {
SMBUtil.writeInt4(0xFFFFFFFF, dst, dstIndex);
return;
}
if ( cfg.getLocalTimezone().inDaylightTime(new Date()) ) {
// in DST
if ( cfg.getLocalTimezone().inDaylightTime(new Date(t)) ) {
// t also in DST so no correction
}
else {
// t not in DST so subtract 1 hour
t -= 3600000;
}
}
else {
// not in DST
if ( cfg.getLocalTimezone().inDaylightTime(new Date(t)) ) {
// t is in DST so add 1 hour
t += 3600000;
}
else {
// t isn't in DST either
}
}
SMBUtil.writeInt4((int) ( t / 1000L ), dst, dstIndex);
}
}