aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2020-10-27 11:52:38 +0100
committerMattias EngdegÄrd2020-10-27 12:25:57 +0100
commitf971a612a92eea4c8aab6b002d7998bb0b6f5ca1 (patch)
tree0c75fdf49e5073e9f5c6c51fcd0beb562afce854
parent990c0620cb9fee3f4779468662d8447c2b301156 (diff)
downloademacs-f971a612a92eea4c8aab6b002d7998bb0b6f5ca1.tar.gz
emacs-f971a612a92eea4c8aab6b002d7998bb0b6f5ca1.zip
Don't rely on bignums in ntlm.el
Since ntlm.el is distributed as a separate package in GNU ELPA and should be able to run on older Emacs versions without bignums, we cannot make use of them here. See discussion at https://lists.gnu.org/archive/html/emacs-devel/2020-10/msg01665.html. Instead, we add a small poor man's bignum implementation. * lisp/net/ntlm.el (ntlm--bignat-of-int, ntlm--bignat-add) (ntlm--bignat-shift-left, ntlm--bignat-mul-byte, ntlm--bignat-mul) (ntlm--bignat-of-string, ntlm--bignat-of-digits) (ntlm--bignat-to-int64): New. (ntlm--time-to-timestamp): Use the ntlm--bignat- functions instead of Lisp integers. * test/lisp/net/ntlm-tests.el: New file.
-rw-r--r--lisp/net/ntlm.el88
-rw-r--r--test/lisp/net/ntlm-tests.el52
2 files changed, 129 insertions, 11 deletions
diff --git a/lisp/net/ntlm.el b/lisp/net/ntlm.el
index 9401430799c..6d1cf2da71f 100644
--- a/lisp/net/ntlm.el
+++ b/lisp/net/ntlm.el
@@ -132,23 +132,89 @@ is not given."
132 domain ;buffer field 132 domain ;buffer field
133 )))) 133 ))))
134 134
135;; Poor man's bignums: natural numbers represented as lists of bytes
136;; in little-endian order.
137;; When this code no longer needs to run on Emacs 26 or older, all this
138;; silliness should be simplified to use ordinary Lisp integers.
139
140(eval-and-compile ; for compile-time simplification
141 (defun ntlm--bignat-of-int (x)
142 "Convert the natural number X into a bignat."
143 (declare (pure t))
144 (and (not (zerop x))
145 (cons (logand x #xff) (ntlm--bignat-of-int (ash x -8)))))
146
147 (defun ntlm--bignat-add (a b &optional carry)
148 "Add the bignats A and B and the natural number CARRY."
149 (declare (pure t))
150 (and (or a b (and carry (not (zerop carry))))
151 (let ((s (+ (if a (car a) 0)
152 (if b (car b) 0)
153 (or carry 0))))
154 (cons (logand s #xff)
155 (ntlm--bignat-add (cdr a) (cdr b) (ash s -8))))))
156
157 (defun ntlm--bignat-shift-left (x n)
158 "Multiply the bignat X by 2^{8N}."
159 (declare (pure t))
160 (if (zerop n) x (ntlm--bignat-shift-left (cons 0 x) (1- n))))
161
162 (defun ntlm--bignat-mul-byte (a b)
163 "Multiply the bignat A with the byte B."
164 (declare (pure t))
165 (let ((p (mapcar (lambda (x) (* x b)) a)))
166 (ntlm--bignat-add
167 (mapcar (lambda (x) (logand x #xff)) p)
168 (cons 0 (mapcar (lambda (x) (ash x -8)) p)))))
169
170 (defun ntlm--bignat-mul (a b)
171 "Multiply the bignats A and B."
172 (declare (pure t))
173 (and a b (ntlm--bignat-add (ntlm--bignat-mul-byte a (car b))
174 (cons 0 (ntlm--bignat-mul a (cdr b))))))
175
176 (defun ntlm--bignat-of-string (s)
177 "Convert the string S (in decimal) to a bignat."
178 (declare (pure t))
179 (ntlm--bignat-of-digits (reverse (string-to-list s))))
180
181 (defun ntlm--bignat-of-digits (digits)
182 "Convert the little-endian list DIGITS of decimal digits to a bignat."
183 (declare (pure t))
184 (and digits
185 (ntlm--bignat-add
186 nil
187 (ntlm--bignat-mul-byte (ntlm--bignat-of-digits (cdr digits)) 10)
188 (- (car digits) ?0))))
189
190 (defun ntlm--bignat-to-int64 (x)
191 "Convert the bignat X to a 64-bit little-endian number as a string."
192 (declare (pure t))
193 (apply #'unibyte-string (mapcar (lambda (n) (or (nth n x) 0))
194 (number-sequence 0 7))))
195 )
196
135(defun ntlm--time-to-timestamp (time) 197(defun ntlm--time-to-timestamp (time)
136 "Convert TIME to an NTLMv2 timestamp. 198 "Convert TIME to an NTLMv2 timestamp.
137Return a unibyte string representing the number of tenths of a 199Return a unibyte string representing the number of tenths of a
138microsecond since January 1, 1601 as a 64-bit little-endian 200microsecond since January 1, 1601 as a 64-bit little-endian
139signed integer. TIME must be on the form (HIGH LOW USEC PSEC)." 201signed integer. TIME must be on the form (HIGH LOW USEC PSEC)."
140 (let* ((s (+ (ash (nth 0 time) 16) (nth 1 time))) 202 (let* ((s-hi (ntlm--bignat-of-int (nth 0 time)))
141 (us (nth 2 time)) 203 (s-lo (ntlm--bignat-of-int (nth 1 time)))
142 (ps (nth 3 time)) 204 (s (ntlm--bignat-add (ntlm--bignat-shift-left s-hi 2) s-lo))
205 (us*10 (ntlm--bignat-of-int (* (nth 2 time) 10)))
206 (ps/1e5 (ntlm--bignat-of-int (/ (nth 3 time) 100000)))
207 ;; tenths of microseconds between 1601-01-01 and 1970-01-01
208 (to-unix-epoch (ntlm--bignat-of-string "116444736000000000"))
143 (tenths-of-us-since-jan-1-1601 209 (tenths-of-us-since-jan-1-1601
144 (+ (* s 10000000) (* us 10) (/ ps 100000) 210 (ntlm--bignat-add
145 ;; tenths of microseconds between 1601-01-01 and 1970-01-01 211 (ntlm--bignat-add
146 116444736000000000))) 212 (ntlm--bignat-add
147 (apply #'unibyte-string 213 (ntlm--bignat-mul s (ntlm--bignat-of-int 10000000))
148 (mapcar (lambda (i) 214 us*10)
149 (logand (ash tenths-of-us-since-jan-1-1601 (* i -8)) 215 ps/1e5)
150 #xff)) 216 to-unix-epoch)))
151 (number-sequence 0 7))))) 217 (ntlm--bignat-to-int64 tenths-of-us-since-jan-1-1601)))
152 218
153(defun ntlm-compute-timestamp () 219(defun ntlm-compute-timestamp ()
154 "Current time as an NTLMv2 timestamp, as a unibyte string." 220 "Current time as an NTLMv2 timestamp, as a unibyte string."
diff --git a/test/lisp/net/ntlm-tests.el b/test/lisp/net/ntlm-tests.el
new file mode 100644
index 00000000000..e515ebe2635
--- /dev/null
+++ b/test/lisp/net/ntlm-tests.el
@@ -0,0 +1,52 @@
1;;; ntlm-tests.el --- tests for ntlm.el -*- lexical-binding: t -*-
2
3;; Copyright (C) 2020 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software: you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation, either version 3 of the License, or
10;; (at your option) any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
19
20(require 'ert)
21(require 'ntlm)
22
23;; This is the Lisp bignum implementation of `ntlm--time-to-timestamp',
24;; for reference.
25(defun ntlm-tests--time-to-timestamp (time)
26 "Convert TIME to an NTLMv2 timestamp.
27Return a unibyte string representing the number of tenths of a
28microsecond since January 1, 1601 as a 64-bit little-endian
29signed integer. TIME must be on the form (HIGH LOW USEC PSEC)."
30 (let* ((s (+ (ash (nth 0 time) 16) (nth 1 time)))
31 (us (nth 2 time))
32 (ps (nth 3 time))
33 (tenths-of-us-since-jan-1-1601
34 (+ (* s 10000000) (* us 10) (/ ps 100000)
35 ;; tenths of microseconds between 1601-01-01 and 1970-01-01
36 116444736000000000)))
37 (apply #'unibyte-string
38 (mapcar (lambda (i)
39 (logand (ash tenths-of-us-since-jan-1-1601 (* i -8))
40 #xff))
41 (number-sequence 0 7)))))
42
43(ert-deftest ntlm-time-to-timestamp ()
44 ;; Verify poor man's bignums in implementation that can run on Emacs < 27.1.
45 (let ((time '(24471 63910 412962 0)))
46 (should (equal (ntlm--time-to-timestamp time)
47 (ntlm-tests--time-to-timestamp time))))
48 (let ((time '(397431 65535 999999 999999)))
49 (should (equal (ntlm--time-to-timestamp time)
50 (ntlm-tests--time-to-timestamp time)))))
51
52(provide 'ntlm-tests)