Coverage report: /home/ellis/comp/ext/ironclad/src/util.lisp

KindCoveredAll%
expression83125 66.4
branch14 25.0
Key
Not instrumented
Conditionalized out
Executed
Not executed
 
Both branches taken
One branch taken
Neither branch taken
1
 ;;;; util.lisp -- functions that come in handy in crypto applications
2
 (in-package :crypto)
3
 
4
 (defun byte-array-to-hex-string (vector &key (start 0) end (element-type 'base-char))
5
   "Return a string containing the hexadecimal representation of the
6
 subsequence of VECTOR between START and END.  ELEMENT-TYPE controls
7
 the element-type of the returned string."
8
   (declare (type (vector (unsigned-byte 8)) vector)
9
            (type fixnum start)
10
            (type (or null fixnum) end)
11
            (optimize (speed 3) (safety 1)))
12
   (let* ((end (or end (length vector)))
13
          (length (- end start))
14
          (hexdigits (load-time-value (coerce "0123456789abcdef" 'simple-base-string) t)))
15
     (loop with string = (ecase element-type
16
                           ;; so that the compiler optimization can jump in
17
                           (base-char (make-string (* length 2)
18
                                                   :element-type 'base-char))
19
                           (character (make-string (* length 2)
20
                                                   :element-type 'character)))
21
        for i from start below end
22
        for j from 0 below (* length 2) by 2
23
        do (let ((byte (aref vector i)))
24
             (setf (aref string j)
25
                   (aref hexdigits (ldb (byte 4 4) byte))
26
                   (aref string (1+ j))
27
                   (aref hexdigits (ldb (byte 4 0) byte))))
28
        finally (return string))))
29
 
30
 (defun hex-string-to-byte-array (string &key (start 0) (end nil))
31
   "Parses a substring of STRING delimited by START and END of
32
 hexadecimal digits into a byte array."
33
   (declare (type string string))
34
   (let* ((end (or end (length string)))
35
          (length (/ (- end start) 2))
36
          (key (make-array length :element-type '(unsigned-byte 8))))
37
     (declare (type (simple-array (unsigned-byte 8) (*)) key))
38
     (flet ((char-to-digit (char)
39
              (or (digit-char-p char 16)
40
                  (error 'ironclad-error
41
                         :format-control "~A is not a hex digit"
42
                         :format-arguments (list char)))))
43
       (loop for i from 0
44
             for j from start below end by 2
45
             do (setf (aref key i)
46
                      (+ (* (char-to-digit (char string j)) 16)
47
                         (char-to-digit (char string (1+ j)))))
48
          finally (return key)))))
49
 
50
 (defun ascii-string-to-byte-array (string &key (start 0) end)
51
   "Convert STRING to a (VECTOR (UNSIGNED-BYTE 8)).  It is an error if
52
 STRING contains any character whose CHAR-CODE is greater than 255."
53
   (declare (type string string)
54
            (type fixnum start)
55
            (type (or null fixnum) end)
56
            (optimize (speed 3) (safety 1)))
57
   (let* ((length (length string))
58
          (vec (make-array length :element-type '(unsigned-byte 8)))
59
          (end (or end length)))
60
     (loop for i from start below end do
61
           (let ((byte (char-code (char string i))))
62
             (unless (< byte 256)
63
               (error 'ironclad-error
64
                      :format-control "~A is not an ASCII character"
65
                      :format-arguments (list (char string i))))
66
             (setf (aref vec i) byte))
67
           finally (return vec))))
68
 
69
 (defun constant-time-equal (data1 data2)
70
   "Returns T if the elements in DATA1 and DATA2 are identical, NIL otherwise.
71
 All the elements of DATA1 and DATA2 are compared to prevent timing attacks."
72
   (declare (type (simple-array (unsigned-byte 8) (*)) data1 data2)
73
            (optimize (speed 3)))
74
   (let ((res (if (= (length data1) (length data2)) 0 1)))
75
     (declare (type (unsigned-byte 8) res))
76
     (loop for d1 across data1
77
           for d2 across data2
78
           do (setf res (logior res (logxor d1 d2))))
79
     (zerop res)))