summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Hlavaty <tomas.hlavaty@knowledgetools.de>2021-02-15 14:54:30 +0100
committerGuillaume Le Vaillant <glv@posteo.net>2021-02-16 18:15:30 +0100
commitd100b9cdd3be1628cff1838d1f3b35cb94d535e9 (patch)
treef17476550f1bceba159503620ec5f71dc461dc33
parent20586e19376195fdcdc816e2cf70290640b8102c (diff)
allow gcm/gmac iv length other than 12
https://github.com/sharplispers/ironclad/issues/40
-rw-r--r--src/aead/gcm.lisp12
-rw-r--r--src/macs/gmac.lisp78
2 files changed, 73 insertions, 17 deletions
diff --git a/src/aead/gcm.lisp b/src/aead/gcm.lisp
index 334f259..9a851fd 100644
--- a/src/aead/gcm.lisp
+++ b/src/aead/gcm.lisp
@@ -1,6 +1,8 @@
;;;; -*- mode: lisp; indent-tabs-mode: nil -*-
;;;; gcm.lisp -- Galois counter mode
+;; See nistspecialpublication800-38d.pdf about GCM and GMAC.
+
(in-package :crypto)
@@ -16,6 +18,14 @@
:initform 0
:type (integer 0 *))))
+(defun inc32 (x)
+ (assert (= 16 (length x)))
+ (concatenate
+ '(simple-array (unsigned-byte 8) (16))
+ (subseq x 0 12)
+ (integer-to-octets (1+ (octets-to-integer x :n-bits 32 :start 12))
+ :n-bits 32)))
+
(defmethod shared-initialize :after ((mode gcm) slot-names &rest initargs &key key cipher-name initialization-vector &allow-other-keys)
(declare (ignore slot-names initargs)
(type simple-octet-vector key initialization-vector))
@@ -24,7 +34,7 @@
(reinitialize-instance (gcm-mac mode)
:key key
:initialization-vector initialization-vector)))
- (iv (concatenate 'simple-octet-vector initialization-vector #(0 0 0 2)))
+ (iv (inc32 (gmac-j0 mac)))
(cipher (if (or (null (gcm-cipher mode)) cipher-name)
(make-cipher cipher-name
:key key
diff --git a/src/macs/gmac.lisp b/src/macs/gmac.lisp
index 59e070f..8ae8b5f 100644
--- a/src/macs/gmac.lisp
+++ b/src/macs/gmac.lisp
@@ -1,6 +1,7 @@
;;;; -*- mode: lisp; indent-tabs-mode: nil -*-
;;;; gmac.lisp -- GMAC message authentication code
+;; See nistspecialpublication800-38d.pdf about GCM and GMAC.
(in-package :crypto)
@@ -18,6 +19,8 @@
:type (unsigned-byte 64))
(cipher :accessor gmac-cipher
:initform nil)
+ (j0 :accessor gmac-j0
+ :type (simple-array (unsigned-byte 8) (16)))
(iv :accessor gmac-iv
:initform (make-array 16 :element-type '(unsigned-byte 8))
:type (simple-array (unsigned-byte 8) (16)))
@@ -37,10 +40,6 @@
(error 'invalid-mac-parameter
:mac-name 'gmac
:message "GMAC only supports 128-bit block ciphers"))
- (unless (= (length initialization-vector) 12)
- (error 'invalid-mac-parameter
- :mac-name 'gmac
- :message "The initialization vector length must be 12 bytes"))
(make-instance 'gmac
:key key
:cipher-name cipher-name
@@ -56,6 +55,57 @@
(ub64ref/le data 0) x))
(values))
+(defun vec (n)
+ (make-array n :element-type '(unsigned-byte 8) :initial-element 0))
+
+(defun pad (n)
+ (vec (- (* 16 (ceiling n 16)) n)))
+
+(defun ac (a c)
+ (let ((an (length a))
+ (cn (length c)))
+ (concatenate '(simple-array (unsigned-byte 8) (*))
+ a
+ (pad an)
+ c
+ (pad cn)
+ (integer-to-octets (* 8 an) :n-bits 64)
+ (integer-to-octets (* 8 cn) :n-bits 64))))
+
+(defun ghash (h x)
+ (multiple-value-bind (q r) (floor (length x) 16)
+ (assert (zerop r))
+ (let ((z (vec 16))
+ (i 0))
+ (if #+(and sbcl x86-64 ironclad-assembly) (pclmulqdq-supported-p)
+ #-(and sbcl x86-64 ironclad-assembly) nil
+ (let ((y (vec 16)))
+ (dotimes (j q)
+ (replace y x :start2 i)
+ (ironclad::gmac-swap-16 y)
+ (ironclad::xor-block 16 z 0 y 0 z 0)
+ (ironclad::gmac-mul z h)
+ (incf i 16))
+ (ironclad::gmac-swap-16 z))
+ (dotimes (j q)
+ (ironclad::xor-block 16 z 0 x i z 0)
+ (ironclad::gmac-mul z h)
+ (incf i 16)))
+ z)))
+
+(defun j0 (h iv)
+ (let* ((n (length iv))
+ (n*8 (* 8 n)))
+ (cond
+ ((= 12 n)
+ (concatenate '(simple-array (unsigned-byte 8) (16)) iv #(0 0 0 1)))
+ ((< 0 n*8 #.(expt 2 64))
+ (ghash h (ac nil iv)))
+ (t
+ (error 'invalid-mac-parameter
+ :mac-name 'gmac
+ :message "iv size not in range 0<|iv|<2^64 bits")))))
+
(defmethod shared-initialize :after ((mac gmac) slot-names &rest initargs &key key cipher-name initialization-vector &allow-other-keys)
(declare (ignore slot-names initargs)
(type (simple-array (unsigned-byte 8) (*)) key))
@@ -63,10 +113,6 @@
(error 'invalid-mac-parameter
:mac-name 'gmac
:message "GMAC only supports 128-bit block ciphers"))
- (unless (= (length initialization-vector) 12)
- (error 'invalid-mac-parameter
- :mac-name 'gmac
- :message "The initialization vector length must be 12 bytes"))
(if #+(and sbcl x86-64 ironclad-assembly) (pclmulqdq-supported-p)
#-(and sbcl x86-64 ironclad-assembly) nil
(let ((cipher (if (or cipher-name (null (gmac-cipher mac)))
@@ -80,13 +126,13 @@
(gmac-buffer-length mac) 0
(gmac-cipher mac) cipher)
(fill (gmac-accumulator mac) 0)
- (replace iv initialization-vector)
- (fill iv 0 :start 12 :end 15)
- (setf (aref iv 15) 1)
- (encrypt-in-place cipher iv)
(fill hkey 0)
(encrypt-in-place cipher hkey)
(gmac-swap-16 hkey)
+ (let ((j0 (j0 hkey initialization-vector)))
+ (setf (gmac-j0 mac) j0)
+ (replace iv j0))
+ (encrypt-in-place cipher iv)
mac)
(let ((table (make-array '(128 2 2) :element-type '(unsigned-byte 64)
:initial-element 0))
@@ -104,10 +150,6 @@
(gmac-buffer-length mac) 0
(gmac-cipher mac) cipher)
(fill (gmac-accumulator mac) 0)
- (replace iv initialization-vector)
- (fill iv 0 :start 12 :end 15)
- (setf (aref iv 15) 1)
- (encrypt-in-place cipher iv)
(encrypt-in-place cipher hkey)
(setf (aref table 0 1 0) (ub64ref/be hkey 0)
@@ -118,6 +160,10 @@
(setf (aref table (1+ i) 1 1) (logior (mod64ash (aref table i 1 1) -1)
(mod64ash (aref table i 1 0) 63))
(aref table (1+ i) 1 0) (logxor (mod64ash (aref table i 1 0) -1) c))))
+ (let ((j0 (j0 table initialization-vector)))
+ (setf (gmac-j0 mac) j0)
+ (replace iv j0))
+ (encrypt-in-place cipher iv)
mac)))
(defun gmac-mul (accumulator key)