diff options
| author | Mattias EngdegÄrd | 2020-10-27 11:52:38 +0100 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2020-10-27 12:25:57 +0100 |
| commit | f971a612a92eea4c8aab6b002d7998bb0b6f5ca1 (patch) | |
| tree | 0c75fdf49e5073e9f5c6c51fcd0beb562afce854 | |
| parent | 990c0620cb9fee3f4779468662d8447c2b301156 (diff) | |
| download | emacs-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.el | 88 | ||||
| -rw-r--r-- | test/lisp/net/ntlm-tests.el | 52 |
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. |
| 137 | Return a unibyte string representing the number of tenths of a | 199 | Return a unibyte string representing the number of tenths of a |
| 138 | microsecond since January 1, 1601 as a 64-bit little-endian | 200 | microsecond since January 1, 1601 as a 64-bit little-endian |
| 139 | signed integer. TIME must be on the form (HIGH LOW USEC PSEC)." | 201 | signed 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. | ||
| 27 | Return a unibyte string representing the number of tenths of a | ||
| 28 | microsecond since January 1, 1601 as a 64-bit little-endian | ||
| 29 | signed 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) | ||