001: package com.knowgate.jcifs.smb;
002:
003: import java.security.MessageDigest;
004: import java.security.NoSuchAlgorithmException;
005: import java.io.IOException;
006:
007: import com.knowgate.debug.*;
008: import com.knowgate.misc.Gadgets;
009: import com.knowgate.jcifs.Config;
010:
011: /**
012: * To filter 0 len updates and for debugging
013: */
014:
015: public class SigningDigest {
016:
017: private static final int LM_COMPATIBILITY = Config.getInt(
018: "jcifs.smb.lmCompatibility", 0);
019:
020: private MessageDigest digest;
021: private byte[] macSigningKey;
022: private int updates;
023: private int signSequence;
024:
025: public SigningDigest(SmbTransport transport,
026: NtlmPasswordAuthentication auth) throws SmbException {
027: try {
028: digest = MessageDigest.getInstance("MD5");
029: } catch (NoSuchAlgorithmException ex) {
030: if (DebugFile.trace)
031: new ErrorHandler(ex);
032: throw new SmbException("MD5", ex);
033: }
034:
035: try {
036: switch (LM_COMPATIBILITY) {
037: case 0:
038: case 1:
039: case 2:
040: macSigningKey = new byte[40];
041: auth.getUserSessionKey(transport.server.encryptionKey,
042: macSigningKey, 0);
043: System
044: .arraycopy(
045: auth
046: .getUnicodeHash(transport.server.encryptionKey),
047: 0, macSigningKey, 16, 24);
048: break;
049: case 3:
050: case 4:
051: case 5:
052: macSigningKey = new byte[16];
053: auth.getUserSessionKey(transport.server.encryptionKey,
054: macSigningKey, 0);
055: break;
056: default:
057: macSigningKey = new byte[40];
058: auth.getUserSessionKey(transport.server.encryptionKey,
059: macSigningKey, 0);
060: System
061: .arraycopy(
062: auth
063: .getUnicodeHash(transport.server.encryptionKey),
064: 0, macSigningKey, 16, 24);
065: break;
066: }
067: } catch (Exception ex) {
068: throw new SmbException("", ex);
069: }
070: if (DebugFile.trace) {
071: DebugFile.writeln("LM_COMPATIBILITY=" + LM_COMPATIBILITY);
072: }
073: }
074:
075: public void update(byte[] input, int offset, int len) {
076: if (DebugFile.trace) {
077: DebugFile.writeln("update: " + updates + " " + offset + ":"
078: + len);
079: }
080: if (len == 0) {
081: return; /* CRITICAL */
082: }
083: digest.update(input, offset, len);
084: updates++;
085: }
086:
087: public byte[] digest() {
088: byte[] b;
089:
090: b = digest.digest();
091:
092: if (DebugFile.trace) {
093: DebugFile.writeln("digest: ");
094: }
095: updates = 0;
096:
097: return b;
098: }
099:
100: /**
101: * Performs MAC signing of the SMB. This is done as follows.
102: * The signature field of the SMB is overwritted with the sequence number;
103: * The MD5 digest of the MAC signing key + the entire SMB is taken;
104: * The first 8 bytes of this are placed in the signature field.
105: *
106: * @param data The data.
107: * @param offset The starting offset at which the SMB header begins.
108: * @param length The length of the SMB data starting at offset.
109: */
110: void sign(byte[] data, int offset, int length,
111: ServerMessageBlock request, ServerMessageBlock response) {
112: request.signSeq = signSequence;
113: if (response != null) {
114: response.signSeq = signSequence + 1;
115: response.verifyFailed = false;
116: }
117:
118: try {
119: update(macSigningKey, 0, macSigningKey.length);
120: int index = offset + ServerMessageBlock.SIGNATURE_OFFSET;
121: for (int i = 0; i < 8; i++)
122: data[index + i] = 0;
123: ServerMessageBlock.writeInt4(signSequence, data, index);
124: update(data, offset, length);
125: System.arraycopy(digest(), 0, data, index, 8);
126: } catch (Exception ex) {
127: if (DebugFile.trace)
128: new ErrorHandler(ex);
129: } finally {
130: signSequence += 2;
131: }
132: }
133:
134: /**
135: * Performs MAC signature verification. This calculates the signature
136: * of the SMB and compares it to the signature field on the SMB itself.
137: *
138: * @param data The data.
139: * @param offset The starting offset at which the SMB header begins.
140: * @param length The length of the SMB data starting at offset.
141: */
142: boolean verify(byte[] data, int offset, ServerMessageBlock response) {
143: update(macSigningKey, 0, macSigningKey.length);
144: int index = offset;
145: update(data, index, ServerMessageBlock.SIGNATURE_OFFSET);
146: index += ServerMessageBlock.SIGNATURE_OFFSET;
147: byte[] sequence = new byte[8];
148: ServerMessageBlock.writeInt4(response.signSeq, sequence, 0);
149: update(sequence, 0, sequence.length);
150: index += 8;
151: if (response.command == ServerMessageBlock.SMB_COM_READ_ANDX) {
152: /* SmbComReadAndXResponse reads directly from the stream into separate byte[] b.
153: */
154: SmbComReadAndXResponse raxr = (SmbComReadAndXResponse) response;
155: int length = response.length - raxr.dataLength;
156: update(data, index, length
157: - ServerMessageBlock.SIGNATURE_OFFSET - 8);
158: update(raxr.b, raxr.off, raxr.dataLength);
159: } else {
160: update(data, index, response.length
161: - ServerMessageBlock.SIGNATURE_OFFSET - 8);
162: }
163: byte[] signature = digest();
164: for (int i = 0; i < 8; i++) {
165: if (signature[i] != data[offset
166: + ServerMessageBlock.SIGNATURE_OFFSET + i]) {
167: if (DebugFile.trace) {
168: DebugFile.writeln("signature verification failure");
169: }
170: return response.verifyFailed = true;
171: }
172: }
173:
174: return response.verifyFailed = false;
175: }
176: }
|