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