r10656: BIG merge from trunk. Features not copied over
[gd/samba/.git] / source / libsmb / ntlmssp_sign.c
index b8105970762f4ce2617f3189879c48fa638204aa..51023ca35652562365a73d1daceb19bb5d1b6024 100644 (file)
@@ -2,8 +2,7 @@
  *  Unix SMB/CIFS implementation.
  *  Version 3.0
  *  NTLMSSP Signing routines
- *  Copyright (C) Luke Kenneth Casson Leighton 1996-2001
- *  Copyright (C) Andrew Bartlett 2003
+ *  Copyright (C) Andrew Bartlett 2003-2005
  *  
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #define SRV_SIGN "session key to server-to-client signing key magic constant"
 #define SRV_SEAL "session key to server-to-client sealing key magic constant"
 
-static void NTLMSSPcalc_ap( unsigned char *hash, unsigned char *data, int len)
-{
-    unsigned char index_i = hash[256];
-    unsigned char index_j = hash[257];
-    int ind;
-
-    for (ind = 0; ind < len; ind++)
-    {
-        unsigned char tc;
-        unsigned char t;
-
-        index_i++;
-        index_j += hash[index_i];
-
-        tc = hash[index_i];
-        hash[index_i] = hash[index_j];
-        hash[index_j] = tc;
-
-        t = hash[index_i] + hash[index_j];
-        data[ind] = data[ind] ^ hash[t];
-    }
-
-    hash[256] = index_i;
-    hash[257] = index_j;
-}
-
-static void calc_hash(unsigned char hash[258], unsigned char *k2, int k2l)
-{
-       unsigned char j = 0;
-       int ind;
-
-       for (ind = 0; ind < 256; ind++)
-       {
-               hash[ind] = (unsigned char)ind;
-       }
-
-       for (ind = 0; ind < 256; ind++)
-       {
-               unsigned char tc;
-
-               j += (hash[ind] + k2[ind%k2l]);
-
-               tc = hash[ind];
-               hash[ind] = hash[j];
-               hash[j] = tc;
-       }
-
-       hash[256] = 0;
-       hash[257] = 0;
-}
+/**
+ * Some notes on then NTLM2 code:
+ *
+ * NTLM2 is a AEAD system.  This means that the data encrypted is not
+ * all the data that is signed.  In DCE-RPC case, the headers of the
+ * DCE-RPC packets are also signed.  This prevents some of the
+ * fun-and-games one might have by changing them.
+ *
+ */
 
-static void calc_ntlmv2_hash(unsigned char hash[258], unsigned char digest[16],
-                            DATA_BLOB session_key, 
-                            const char *constant)
+static void calc_ntlmv2_key(unsigned char subkey[16],
+                               DATA_BLOB session_key,
+                               const char *constant)
 {
        struct MD5Context ctx3;
-
-       /* NOTE:  This code is currently complate fantasy - it's
-          got more in common with reality than the previous code
-          (the LM session key is not the right thing to use) but
-          it still needs work */
-
        MD5Init(&ctx3);
        MD5Update(&ctx3, session_key.data, session_key.length);
-       MD5Update(&ctx3, (const unsigned char *)constant, strlen(constant)+1);
-       MD5Final(digest, &ctx3);
-
-       calc_hash(hash, digest, 16);
+       MD5Update(&ctx3, constant, strlen(constant)+1);
+       MD5Final(subkey, &ctx3);
 }
 
 enum ntlmssp_direction {
@@ -103,64 +53,107 @@ enum ntlmssp_direction {
 };
 
 static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state,
-                                             const uchar *data, size_t length, 
-                                             enum ntlmssp_direction direction,
-                                             DATA_BLOB *sig) 
+                                               const uchar *data, size_t length, 
+                                               const uchar *whole_pdu, size_t pdu_length,
+                                               enum ntlmssp_direction direction,
+                                               DATA_BLOB *sig,
+                                               BOOL encrypt_sig)
 {
        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
                HMACMD5Context ctx;
                uchar seq_num[4];
                uchar digest[16];
-               SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
-
-               hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
-               hmac_md5_update(seq_num, 4, &ctx);
-               hmac_md5_update(data, length, &ctx);
-               hmac_md5_final(digest, &ctx);
 
-               if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
-                              , ntlmssp_state->ntlmssp_seq_num)) {
+               *sig = data_blob(NULL, NTLMSSP_SIG_SIZE);
+               if (!sig->data) {
                        return NT_STATUS_NO_MEMORY;
                }
 
-               if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+               switch (direction) {
+                       case NTLMSSP_SEND:
+                               DEBUG(100,("ntlmssp_make_packet_signature: SEND seq = %u, len = %u, pdu_len = %u\n",
+                                       ntlmssp_state->ntlm2_send_seq_num,
+                                       (unsigned int)length,
+                                       (unsigned int)pdu_length));
+
+                               SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num);
+                               ntlmssp_state->ntlm2_send_seq_num++;
+                               hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key, 16, &ctx);
+                               break;
+                       case NTLMSSP_RECEIVE:
+
+                               DEBUG(100,("ntlmssp_make_packet_signature: RECV seq = %u, len = %u, pdu_len = %u\n",
+                                       ntlmssp_state->ntlm2_recv_seq_num,
+                                       (unsigned int)length,
+                                       (unsigned int)pdu_length));
+
+                               SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num);
+                               ntlmssp_state->ntlm2_recv_seq_num++;
+                               hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key, 16, &ctx);
+                               break;
+                }
+
+               dump_data_pw("pdu data ", whole_pdu, pdu_length);
+
+               hmac_md5_update(seq_num, 4, &ctx);
+               hmac_md5_update(whole_pdu, pdu_length, &ctx);
+               hmac_md5_final(digest, &ctx);
+
+               if (encrypt_sig && (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
                        switch (direction) {
                        case NTLMSSP_SEND:
-                               NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash,  sig->data+4, sig->length-4);
+                               smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state,  digest, 8);
                                break;
                        case NTLMSSP_RECEIVE:
-                               NTLMSSPcalc_ap(ntlmssp_state->recv_sign_hash,  sig->data+4, sig->length-4);
+                               smb_arc4_crypt(ntlmssp_state->recv_seal_arc4_state,  digest, 8);
                                break;
                        }
                }
+
+               SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION);
+               memcpy(sig->data + 4, digest, 8);
+               memcpy(sig->data + 12, seq_num, 4);
+
+               dump_data_pw("ntlmssp v2 sig ", sig->data, sig->length);
+
        } else {
                uint32 crc;
                crc = crc32_calc_buffer((const char *)data, length);
-               if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+               if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) {
                        return NT_STATUS_NO_MEMORY;
                }
                
-               dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
-                            sizeof(ntlmssp_state->ntlmssp_hash));
-               NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+               ntlmssp_state->ntlmv1_seq_num++;
+
+               dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmv1_arc4_state,
+                            sizeof(ntlmssp_state->ntlmv1_arc4_state));
+               smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4);
        }
        return NT_STATUS_OK;
 }
 
 NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
                                    const uchar *data, size_t length, 
+                                   const uchar *whole_pdu, size_t pdu_length, 
                                    DATA_BLOB *sig) 
 {
        NTSTATUS nt_status;
+
+       if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
+               DEBUG(3, ("NTLMSSP Signing not negotiated - cannot sign packet!\n"));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
        if (!ntlmssp_state->session_key.length) {
                DEBUG(3, ("NO session key, cannot check sign packet\n"));
                return NT_STATUS_NO_USER_SESSION_KEY;
        }
 
-       nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+       nt_status = ntlmssp_make_packet_signature(ntlmssp_state,
+                                               data, length,
+                                               whole_pdu, pdu_length,
+                                               NTLMSSP_SEND, sig, True);
 
-       /* increment counter on send */
-       ntlmssp_state->ntlmssp_seq_num++;
        return nt_status;
 }
 
@@ -171,8 +164,9 @@ NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
  */
 
 NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
-                             const uchar *data, size_t length, 
-                             const DATA_BLOB *sig) 
+                               const uchar *data, size_t length, 
+                               const uchar *whole_pdu, size_t pdu_length, 
+                               const DATA_BLOB *sig) 
 {
        DATA_BLOB local_sig;
        NTSTATUS nt_status;
@@ -187,32 +181,51 @@ NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
                          (unsigned long)sig->length));
        }
 
-       nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data, 
-                                                 length, NTLMSSP_RECEIVE, &local_sig);
+       nt_status = ntlmssp_make_packet_signature(ntlmssp_state,
+                                               data, length,
+                                               whole_pdu, pdu_length,
+                                               NTLMSSP_RECEIVE, &local_sig, True);
        
        if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status)));
+               data_blob_free(&local_sig);
                return nt_status;
        }
        
-       if (memcmp(sig->data+sig->length - 8, local_sig.data+local_sig.length - 8, 8) != 0) {
-               DEBUG(5, ("BAD SIG: wanted signature of\n"));
-               dump_data(5, (const char *)local_sig.data, local_sig.length);
-               
-               DEBUG(5, ("BAD SIG: got signature of\n"));
-               dump_data(5, (const char *)(sig->data), sig->length);
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+               if (local_sig.length != sig->length ||
+                               memcmp(local_sig.data, sig->data, sig->length) != 0) {
+                       DEBUG(5, ("BAD SIG NTLM2: wanted signature of\n"));
+                       dump_data(5, local_sig.data, local_sig.length);
 
-               DEBUG(0, ("NTLMSSP packet check failed due to invalid signature!\n"));
-               return NT_STATUS_ACCESS_DENIED;
-       }
+                       DEBUG(5, ("BAD SIG: got signature of\n"));
+                       dump_data(5, sig->data, sig->length);
+
+                       DEBUG(0, ("NTLMSSP NTLM2 packet check failed due to invalid signature!\n"));
+                       data_blob_free(&local_sig);
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+       } else {
+               if (local_sig.length != sig->length ||
+                               memcmp(local_sig.data + 8, sig->data + 8, sig->length - 8) != 0) {
+                       DEBUG(5, ("BAD SIG NTLM1: wanted signature of\n"));
+                       dump_data(5, local_sig.data, local_sig.length);
+
+                       DEBUG(5, ("BAD SIG: got signature of\n"));
+                       dump_data(5, sig->data, sig->length);
 
-       /* increment counter on recieive */
-       ntlmssp_state->ntlmssp_seq_num++;
+                       DEBUG(0, ("NTLMSSP NTLM1 packet check failed due to invalid signature!\n"));
+                       data_blob_free(&local_sig);
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+       }
+       dump_data_pw("checked ntlmssp signature\n", sig->data, sig->length);
+       DEBUG(10,("ntlmssp_check_packet: NTLMSSP signature OK !\n"));
 
+       data_blob_free(&local_sig);
        return NT_STATUS_OK;
 }
 
-
 /**
  * Seal data with the NTLMSSP algorithm
  *
@@ -220,8 +233,16 @@ NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
 
 NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
                             uchar *data, size_t length,
+                            uchar *whole_pdu, size_t pdu_length,
                             DATA_BLOB *sig)
 {      
+       NTSTATUS nt_status;
+
+       if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
+               DEBUG(3, ("NTLMSSP Sealing not negotiated - cannot seal packet!\n"));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
        if (!ntlmssp_state->session_key.length) {
                DEBUG(3, ("NO session key, cannot seal packet\n"));
                return NT_STATUS_NO_USER_SESSION_KEY;
@@ -230,53 +251,44 @@ NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
        DEBUG(10,("ntlmssp_seal_data: seal\n"));
        dump_data_pw("ntlmssp clear data\n", data, length);
        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
-               HMACMD5Context ctx;
-               char seq_num[4];
-               uchar digest[16];
-               SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
-
-               hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
-               hmac_md5_update((const unsigned char *)seq_num, 4, &ctx);
-               hmac_md5_update(data, length, &ctx);
-               hmac_md5_final(digest, &ctx);
-
-               if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
-                              , ntlmssp_state->ntlmssp_seq_num)) {
-                       return NT_STATUS_NO_MEMORY;
+               /* The order of these two operations matters - we must first seal the packet,
+                  then seal the sequence number - this is becouse the send_seal_hash is not
+                  constant, but is is rather updated with each iteration */
+               nt_status = ntlmssp_make_packet_signature(ntlmssp_state,
+                                                       data, length,
+                                                       whole_pdu, pdu_length,
+                                                       NTLMSSP_SEND, sig, False);
+               smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, data, length);
+               if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+                       smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, sig->data+4, 8);
                }
-
-               dump_data_pw("ntlmssp client sealing hash:\n", 
-                            ntlmssp_state->send_seal_hash,
-                            sizeof(ntlmssp_state->send_seal_hash));
-               NTLMSSPcalc_ap(ntlmssp_state->send_seal_hash, data, length);
-               dump_data_pw("ntlmssp client signing hash:\n", 
-                            ntlmssp_state->send_sign_hash,
-                            sizeof(ntlmssp_state->send_sign_hash));
-               NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash,  sig->data+4, sig->length-4);
        } else {
                uint32 crc;
                crc = crc32_calc_buffer((const char *)data, length);
-               if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+               if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) {
                        return NT_STATUS_NO_MEMORY;
                }
 
                /* The order of these two operations matters - we must first seal the packet,
-                  then seal the sequence number - this is becouse the ntlmssp_hash is not
+                  then seal the sequence number - this is becouse the ntlmv1_arc4_state is not
                   constant, but is is rather updated with each iteration */
                
-               dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
-                            sizeof(ntlmssp_state->ntlmssp_hash));
-               NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+               dump_data_pw("ntlmv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state,
+                            sizeof(ntlmssp_state->ntlmv1_arc4_state));
+               smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, data, length);
+
+               dump_data_pw("ntlmv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state,
+                            sizeof(ntlmssp_state->ntlmv1_arc4_state));
+
+               smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4);
 
-               dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
-                            sizeof(ntlmssp_state->ntlmssp_hash));
-               NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+               ntlmssp_state->ntlmv1_seq_num++;
+
+               nt_status = NT_STATUS_OK;
        }
+       dump_data_pw("ntlmssp signature\n", sig->data, sig->length);
        dump_data_pw("ntlmssp sealed data\n", data, length);
 
-       /* increment counter on send */
-       ntlmssp_state->ntlmssp_seq_num++;
-
        return NT_STATUS_OK;
 }
 
@@ -286,26 +298,27 @@ NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
  */
 
 NTSTATUS ntlmssp_unseal_packet(NTLMSSP_STATE *ntlmssp_state,
-                                     uchar *data, size_t length,
-                                     DATA_BLOB *sig)
+                               uchar *data, size_t length,
+                               uchar *whole_pdu, size_t pdu_length,
+                               DATA_BLOB *sig)
 {
        if (!ntlmssp_state->session_key.length) {
                DEBUG(3, ("NO session key, cannot unseal packet\n"));
                return NT_STATUS_NO_USER_SESSION_KEY;
        }
 
-       DEBUG(10,("ntlmssp__unseal_data: seal\n"));
+       DEBUG(10,("ntlmssp_unseal_data: seal\n"));
        dump_data_pw("ntlmssp sealed data\n", data, length);
+
        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
-               NTLMSSPcalc_ap(ntlmssp_state->recv_seal_hash, data, length);
+               /* First unseal the data. */
+               smb_arc4_crypt(ntlmssp_state->recv_seal_arc4_state, data, length);
+               dump_data_pw("ntlmv2 clear data\n", data, length);
        } else {
-               dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
-                            sizeof(ntlmssp_state->ntlmssp_hash));
-               NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+               smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, data, length);
+               dump_data_pw("ntlmv1 clear data\n", data, length);
        }
-       dump_data_pw("ntlmssp clear data\n", data, length);
-
-       return ntlmssp_check_packet(ntlmssp_state, data, length, sig);
+       return ntlmssp_check_packet(ntlmssp_state, data, length, whole_pdu, pdu_length, sig);
 }
 
 /**
@@ -326,6 +339,7 @@ NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state)
 
        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
        {
+               DATA_BLOB weak_session_key = ntlmssp_state->session_key;
                const char *send_sign_const;
                const char *send_seal_const;
                const char *recv_sign_const;
@@ -352,62 +366,96 @@ NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state)
                        break;
                }
 
-               calc_ntlmv2_hash(ntlmssp_state->send_sign_hash, 
-                                ntlmssp_state->send_sign_const, 
-                                ntlmssp_state->session_key, send_sign_const);
-               dump_data_pw("NTLMSSP send sign hash:\n", 
-                            ntlmssp_state->send_sign_hash, 
-                            sizeof(ntlmssp_state->send_sign_hash));
-
-               calc_ntlmv2_hash(ntlmssp_state->send_seal_hash, 
-                                ntlmssp_state->send_seal_const, 
-                                ntlmssp_state->session_key, send_seal_const);
-               dump_data_pw("NTLMSSP send sesl hash:\n", 
-                            ntlmssp_state->send_seal_hash, 
-                            sizeof(ntlmssp_state->send_seal_hash));
-
-               calc_ntlmv2_hash(ntlmssp_state->recv_sign_hash, 
-                                ntlmssp_state->recv_sign_const, 
-                                ntlmssp_state->session_key, recv_sign_const);
-               dump_data_pw("NTLMSSP receive sign hash:\n", 
-                            ntlmssp_state->recv_sign_hash, 
-                            sizeof(ntlmssp_state->recv_sign_hash));
-
-               calc_ntlmv2_hash(ntlmssp_state->recv_seal_hash, 
-                                ntlmssp_state->recv_seal_const, 
-                                ntlmssp_state->session_key, recv_seal_const);
-               dump_data_pw("NTLMSSP receive seal hash:\n", 
-                            ntlmssp_state->recv_sign_hash, 
-                            sizeof(ntlmssp_state->recv_sign_hash));
-
-       } 
-       else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
-               if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 8) {
-                       /* can't sign or check signatures yet */ 
-                       DEBUG(5, ("NTLMSSP Sign/Seal - cannot use LM KEY yet\n"));      
-                       return NT_STATUS_UNSUCCESSFUL;
+               /**
+                 Weaken NTLMSSP keys to cope with down-level clients, servers and export restrictions.
+                 We probably should have some parameters to control this, once we get NTLM2 working.
+               */
+
+               if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) {
+                       ;
+               } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) {
+                       weak_session_key.length = 6;
+               } else { /* forty bits */
+                       weak_session_key.length = 5;
                }
+
+               dump_data_pw("NTLMSSP weakend master key:\n",
+                               weak_session_key.data,
+                               weak_session_key.length);
+
+               /* SEND */
+               calc_ntlmv2_key(ntlmssp_state->send_sign_key,
+                               ntlmssp_state->session_key, send_sign_const);
+               dump_data_pw("NTLMSSP send sign key:\n",
+                               ntlmssp_state->send_sign_key, 16);
+
+               calc_ntlmv2_key(ntlmssp_state->send_seal_key,
+                               weak_session_key, send_seal_const);
+               dump_data_pw("NTLMSSP send seal key:\n",
+                               ntlmssp_state->send_seal_key, 16);
+
+               smb_arc4_init(ntlmssp_state->send_seal_arc4_state,
+                               ntlmssp_state->send_seal_key, 16);
+
+               dump_data_pw("NTLMSSP send seal arc4 state:\n", 
+                            ntlmssp_state->send_seal_arc4_state, 
+                            sizeof(ntlmssp_state->send_seal_arc4_state));
+
+               /* RECV */
+               calc_ntlmv2_key(ntlmssp_state->recv_sign_key,
+                               ntlmssp_state->session_key, recv_sign_const);
+               dump_data_pw("NTLMSSP recv send sign key:\n",
+                               ntlmssp_state->recv_sign_key, 16);
+
+               calc_ntlmv2_key(ntlmssp_state->recv_seal_key,
+                               weak_session_key, recv_seal_const);
                
-               DEBUG(5, ("NTLMSSP Sign/Seal - using LM KEY\n"));
+               dump_data_pw("NTLMSSP recv seal key:\n",
+                               ntlmssp_state->recv_seal_key, 16);
+                               
+               smb_arc4_init(ntlmssp_state->recv_seal_arc4_state,
+                               ntlmssp_state->recv_seal_key, 16);
+
+               dump_data_pw("NTLMSSP recv seal arc4 state:\n", 
+                            ntlmssp_state->recv_seal_arc4_state, 
+                            sizeof(ntlmssp_state->recv_seal_arc4_state));
+
+               ntlmssp_state->ntlm2_send_seq_num = 0;
+               ntlmssp_state->ntlm2_recv_seq_num = 0;
+
 
-               calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 8);
-               dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
-                            sizeof(ntlmssp_state->ntlmssp_hash));
        } else {
-               if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 16) {
-                       /* can't sign or check signatures yet */ 
-                       DEBUG(5, ("NTLMSSP Sign/Seal - cannot use NT KEY yet\n"));
-                       return NT_STATUS_UNSUCCESSFUL;
+#if 0
+               /* Hmmm. Shouldn't we also weaken keys for ntlmv1 ? JRA. */
+
+               DATA_BLOB weak_session_key = ntlmssp_state->session_key;
+               /**
+                 Weaken NTLMSSP keys to cope with down-level clients, servers and export restrictions.
+                 We probably should have some parameters to control this, once we get NTLM2 working.
+               */
+
+               if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) {
+                       ;
+               } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) {
+                       weak_session_key.length = 6;
+               } else { /* forty bits */
+                       weak_session_key.length = 5;
                }
-               
-               DEBUG(5, ("NTLMSSP Sign/Seal - using NT KEY\n"));
+               dump_data_pw("NTLMSSP weakend master key:\n",
+                               weak_session_key.data,
+                               weak_session_key.length);
+#endif
 
-               calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 16);
-               dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
-                            sizeof(ntlmssp_state->ntlmssp_hash));
-       }
+               DEBUG(5, ("NTLMSSP Sign/Seal - using NTLM1\n"));
+
+               smb_arc4_init(ntlmssp_state->ntlmv1_arc4_state,
+                             ntlmssp_state->session_key.data, ntlmssp_state->session_key.length);
 
-       ntlmssp_state->ntlmssp_seq_num = 0;
+                dump_data_pw("NTLMv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state,
+                               sizeof(ntlmssp_state->ntlmv1_arc4_state));
+
+               ntlmssp_state->ntlmv1_seq_num = 0;
+       }
 
        return NT_STATUS_OK;
 }