;;; ntlm.el --- NTLM (NT LanManager) authentication support
-;; Copyright (C) 2001 Taro Kawagishi
+;; Copyright (C) 2001, 2007-2015 Free Software Foundation, Inc.
+
;; Author: Taro Kawagishi <tarok@transpulse.org>
;; Keywords: NTLM, SASL
;; Version: 1.00
;; Created: February 2001
-;; This program is free software; you can redistribute it and/or modify
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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 for more details.
-;;
+
;; You should have received a copy of the GNU General Public License
-;; along with this program; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This library is a direct translation of the Samba release 2.2.0
;; implementation of Windows NT and LanManager compatible password
;; encryption.
-;;
+;;
;; Interface functions:
-;;
+;;
;; ntlm-build-auth-request
;; This will return a binary string, which should be used in the
;; base64 encoded form and it is the caller's responsibility to encode
;; (which will be a binary string) as the first argument and to
;; encode the returned string with base64. The second argument user
;; should be given in user@domain format.
-;;
+;;
;; ntlm-get-password-hashes
;;
;;
(request-msgType (concat (make-string 1 1) (make-string 3 0)))
;0x01 0x00 0x00 0x00
(request-flags (concat (make-string 1 7) (make-string 1 178)
- (make-string 2 0)))
- ;0x07 0xb2 0x00 0x00
+ (make-string 1 8) (make-string 1 0)))
+ ;0x07 0xb2 0x08 0x00
lu ld off-d off-u)
(when (string-match "@" user)
(unless domain
(md4-pack-int16 ld) ;domain field, count field
(md4-pack-int16 ld) ;domain field, max count field
(md4-pack-int32 (cons 0 off-d)) ;domain field, offset field
- user ;bufer field
- domain ;bufer field
+ user ;buffer field
+ domain ;buffer field
)))
(eval-when-compile
(defmacro ntlm-string-as-unibyte (string)
(if (fboundp 'string-as-unibyte)
`(string-as-unibyte ,string)
+ string))
+ (defmacro ntlm-string-make-unibyte (string)
+ (if (fboundp 'string-make-unibyte)
+ `(string-make-unibyte ,string)
string)))
+(eval-and-compile
+ (autoload 'sha1 "sha1")
+ (if (fboundp 'secure-hash)
+ (defalias 'ntlm-secure-hash 'secure-hash)
+ (defun ntlm-secure-hash (algorithm object &optional start end binary)
+ "Return the secure hash of OBJECT, a buffer or string.
+ALGORITHM is a symbol specifying the hash to use: md5, sha1.
+
+The two optional arguments START and END are positions specifying for
+which part of OBJECT to compute the hash. If nil or omitted, uses the
+whole OBJECT.
+
+If BINARY is non-nil, returns a string in binary form."
+ (cond ((eq algorithm 'md5)
+ (if binary
+ (let* ((hex (md5 object start end))
+ (len (length hex))
+ (beg 0)
+ rest)
+ (while (< beg len)
+ (push (ntlm-string-make-unibyte
+ (char-to-string
+ (string-to-number
+ (substring hex beg (setq beg (+ beg 2)))
+ 16)))
+ rest))
+ (apply #'concat (nreverse rest)))
+ (md5 object start end)))
+ ((eq algorithm 'sha1)
+ (sha1 object start end binary))
+ (t
+ (error "(ntlm-secure-hash) Unsupported algorithm: %s"
+ algorithm))))))
+
(defun ntlm-build-auth-response (challenge user password-hashes)
"Return the response string to a challenge string CHALLENGE given by
the NTLM based server for the user USER and the password hash list
(setq domain (substring user (1+ (match-beginning 0))))
(setq user (substring user 0 (match-beginning 0))))
- ;; generate response data
- (setq lmRespData
- (ntlm-smb-owf-encrypt (car password-hashes) challengeData))
- (setq ntRespData
- (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData))
+ ;; check if "negotiate NTLM2 key" flag is set in type 2 message
+ (if (not (zerop (logand (aref flags 2) 8)))
+ (let (randomString
+ sessionHash)
+ ;; generate NTLM2 session response data
+ (setq randomString (ntlm-string-make-unibyte
+ (concat
+ (make-string 1 (random 256))
+ (make-string 1 (random 256))
+ (make-string 1 (random 256))
+ (make-string 1 (random 256))
+ (make-string 1 (random 256))
+ (make-string 1 (random 256))
+ (make-string 1 (random 256))
+ (make-string 1 (random 256)))))
+ (setq sessionHash (ntlm-secure-hash
+ 'md5 (concat challengeData randomString)
+ nil nil t))
+ (setq sessionHash (substring sessionHash 0 8))
+
+ (setq lmRespData (concat randomString (make-string 16 0)))
+ (setq ntRespData (ntlm-smb-owf-encrypt
+ (cadr password-hashes) sessionHash)))
+ (progn
+ ;; generate response data
+ (setq lmRespData
+ (ntlm-smb-owf-encrypt (car password-hashes) challengeData))
+ (setq ntRespData
+ (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData))))
;; get offsets to fields to pack the response struct in a string
(setq lu (length user))
;; buffer field
lmRespData ;lmResponse, 24 bytes
ntRespData ;ntResponse, 24 bytes
- (ntlm-ascii2unicode domain ;unicode domain string, 2*ld bytes
+ (ntlm-ascii2unicode domain ;Unicode domain string, 2*ld bytes
(length domain)) ;
- (ntlm-ascii2unicode user ;unicode user string, 2*lu bytes
+ (ntlm-ascii2unicode user ;Unicode user string, 2*lu bytes
(length user)) ;
- (ntlm-ascii2unicode user ;unicode user string, 2*lu bytes
+ (ntlm-ascii2unicode user ;Unicode user string, 2*lu bytes
(length user)) ;
)))
(defun ntlm-get-password-hashes (password)
- "Return a pair of SMB hash and NT MD4 hash of the given password PASSWORD"
+ "Return a pair of SMB hash and NT MD4 hash of the given password PASSWORD."
(list (ntlm-smb-passwd-hash password)
(ntlm-md4hash password)))
(defun ntlm-smb-dohash (in key forw)
"Return the hash value for a string IN and a string KEY.
-Length of IN and KEY are 64. FORW non nill means forward, nil means
+Length of IN and KEY are 64. FORW non-nil means forward, nil means
backward."
(let (pk1 ;string of length 56
c ;string of length 28
(setq len (length passwd))
(if (> len 128)
(setq len 128))
- ;; Password must be converted to NT unicode
+ ;; Password must be converted to NT Unicode
(setq wpwd (ntlm-ascii2unicode passwd len))
;; Calculate length in bytes
(setq len (* len 2))