1;;;; -*- mode: lisp; indent-tabs-mode: nil -*-
2;;;; skein-mac.lisp -- implementation of the Skein MAC
3
4(in-package :crypto)
5
6
7(defclass skein-mac (mac)
8  ((value :accessor skein-value :initarg :value)
9   (tweak :accessor skein-tweak :initarg :tweak)
10   (cfg :accessor skein-cfg :initarg :cfg)
11   (buffer :accessor skein-buffer :initarg :buffer)
12   (buffer-length :accessor skein-buffer-length :initarg :buffer-length)
13   (cipher :accessor skein-cipher :initarg :cipher)
14   (block-length :accessor block-length :initarg :block-length)
15   (digest-length :accessor digest-length :initarg :digest-length)))
16
17(defun make-skein-mac (key &key (block-length 64) (digest-length 64))
18  (unless (or (= block-length 32)
19              (= block-length 64)
20              (= block-length 128))
21    (error 'invalid-mac-parameter
22           :mac-name 'skein-mac
23           :message "The block length must be 32, 64 or 128 bytes"))
24
25  (make-instance 'skein-mac
26                 :key key
27                 :block-length block-length
28                 :digest-length digest-length))
29
30(defmethod copy-skein-mac ((mac skein-mac) &optional copy)
31  (declare (type (or null skein-mac) copy))
32  (let ((copy (if copy
33                  copy
34                  (make-instance 'skein-mac
35                                 :key (skein-value mac)
36                                 :block-length (block-length mac)
37                                 :digest-length (digest-length mac)))))
38    (declare (type skein-mac copy))
39    (replace (skein-value copy) (skein-value mac))
40    (replace (skein-tweak copy) (skein-tweak mac))
41    (replace (skein-cfg copy) (skein-cfg mac))
42    (replace (skein-buffer copy) (skein-buffer mac))
43    (setf (skein-buffer-length copy) (skein-buffer-length mac))
44    (setf (skein-cipher copy) (skein-copy-cipher (skein-cipher mac)))
45    copy))
46
47(defmethod shared-initialize :after ((mac skein-mac) slot-names
48                                     &rest initargs
49                                     &key key &allow-other-keys)
50  (declare (ignore slot-names initargs)
51           (type (simple-array (unsigned-byte 8) (*)) key))
52  (let* ((block-length (block-length mac))
53         (digest-length (digest-length mac))
54         (value (make-array block-length
55                            :element-type '(unsigned-byte 8)
56                            :initial-element 0))
57         (tweak (skein-make-tweak t nil +skein-key+ 0))
58         (cfg (skein-make-configuration-string (* 8 digest-length)))
59         (cipher (ecase block-length
60                   (32 (make-cipher :threefish256
61                                    :key value
62                                    :mode :ecb))
63                   (64 (make-cipher :threefish512
64                                    :key value
65                                    :mode :ecb))
66                   (128 (make-cipher :threefish1024
67                                     :key value
68                                     :mode :ecb)))))
69    (setf (skein-cipher mac) cipher
70          (skein-value mac) value
71          (skein-cfg mac) cfg
72          (skein-tweak mac) tweak
73          (skein-buffer mac) (make-array block-length
74                                         :element-type '(unsigned-byte 8))
75          (skein-buffer-length mac) 0)
76
77    ;; Process key
78    (when (plusp (length key))
79      (skein-ubi mac key 0 (length key))
80      (let* ((padding-length (- block-length (skein-buffer-length mac)))
81             (padding (make-array padding-length
82                                  :element-type '(unsigned-byte 8)
83                                  :initial-element 0)))
84        (skein-update-tweak tweak
85                            :final t
86                            :position-increment (skein-buffer-length mac))
87        (skein-ubi mac padding 0 padding-length t)))
88
89    ;; Process configuration string
90    (let ((padded-cfg (make-array block-length
91                                  :element-type '(unsigned-byte 8)
92                                  :initial-element 0)))
93      (replace padded-cfg cfg :end2 32)
94      (skein-update-tweak tweak
95                          :first t
96                          :final t
97                          :type +skein-cfg+
98                          :position 32)
99      (skein-ubi mac padded-cfg 0 block-length t))
100
101    ;; Prepare message processing
102    (skein-update-tweak tweak
103                        :first t
104                        :final nil
105                        :type +skein-msg+
106                        :position 0)))
107
108(defun update-skein-mac (mac sequence &key (start 0) end)
109  (skein-ubi mac sequence start (or end (length sequence)))
110  mac)
111
112(defun skein-mac-digest (mac)
113  (let ((digest (make-array (digest-length mac)
114                            :element-type '(unsigned-byte 8)))
115        (mac-copy (copy-skein-mac mac)))
116    (skein-finalize mac-copy digest 0)
117    digest))
118
119(defmac skein-mac
120        make-skein-mac
121        update-skein-mac
122        skein-mac-digest)
123