emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] scratch/tzz/nettle ba3da72: WIP: GnuTLS: add iv-auto capab


From: Teodor Zlatanov
Subject: [Emacs-diffs] scratch/tzz/nettle ba3da72: WIP: GnuTLS: add iv-auto capability.1
Date: Wed, 31 May 2017 13:25:58 -0400 (EDT)

branch: scratch/tzz/nettle
commit ba3da72997df9ee37f8402698e5d0d1f12844336
Author: Ted Zlatanov <address@hidden>
Commit: Ted Zlatanov <address@hidden>

    WIP: GnuTLS: add iv-auto capability.1
---
 doc/lispref/text.texi         | 24 +++++++++++++------
 src/fns.c                     | 55 ++++---------------------------------------
 src/gnutls.c                  |  7 ++++--
 test/lisp/net/gnutls-tests.el | 33 +++++++++++++++++++-------
 4 files changed, 51 insertions(+), 68 deletions(-)

diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index cad6d0f..2ed7369d 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -4564,6 +4564,10 @@ the text can't be encoded using the specified or chosen 
coding system.
 When @var{noerror} is address@hidden, this function silently uses
 @code{raw-text} coding instead.
 
address@hidden (@code{iv-auto} @var{length})
+This will generate an IV of the specified length using the GnuTLS
+GNUTLS_RND_NONCE generator.
+
 @end table
 
 @node GnuTLS Cryptographic Functions
@@ -4593,7 +4597,7 @@ ways (@xref{Format of GnuTLS Cryptography Inputs}).
 
 This function returns nil on error, and signals a Lisp error if the
 @var{digest-method} or @var{input} are invalid.  On success, it returns
-a binary string.
+a list of a binary string (the output) and the IV used.
 @end defun
 
 @defun gnutls-macs
@@ -4625,8 +4629,10 @@ The @var{input} can be specified as a buffer or string 
or in other
 ways (@xref{Format of GnuTLS Cryptography Inputs}).
 
 This function returns nil on error, and signals a Lisp error if the
address@hidden or @var{key} or @var{input} are invalid.  On
-success, it returns a binary string.
address@hidden or @var{key} or @var{input} are invalid.
+
+On success, it returns a list of a binary string (the output) and the
+IV used.
 @end defun
 
 @defun gnutls-ciphers
@@ -4660,8 +4666,10 @@ plist has @code{:cipher-aead-capable t}.  Otherwise it's 
ignored.
 
 This function returns nil on error, and signals a Lisp error if the
 @var{cipher} or @var{key}, @var{iv}, or @var{input} are invalid, or if
address@hidden was specified with an AEAD cipher and was invalid.  On
-success, it returns an encrypted binary string.
address@hidden was specified with an AEAD cipher and was invalid.
+
+On success, it returns a list of a binary string (the output) and the
+IV used.
 @end defun
 
 @defun gnutls-symmetric-decrypt cipher key iv input &optional aead_auth
@@ -4683,8 +4691,10 @@ plist has @code{:cipher-aead-capable t}.  Otherwise it's 
ignored.
 This function returns nil on decryption error, and signals a Lisp
 error if the @var{cipher} or @var{key}, @var{iv}, or @var{input} are
 invalid, or if @var{aead_auth} was specified with an AEAD cipher and
-was invalid.  On success, it returns the original string that was
-passed to @code{gnutls-symmetric-encrypt}.
+was invalid.
+
+On success, it returns a list of a binary string (the output) and the
+IV used.
 @end defun
 
 @node Parsing HTML/XML
diff --git a/src/fns.c b/src/fns.c
index 9249c37..6948ee4 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -4919,10 +4919,7 @@ extract_data_from_object (Lisp_Object spec,
   else if (EQ (object, Qiv_auto))
     {
 #ifdef HAVE_GNUTLS3
-      // Format: (iv-auto LENGTH KEY)
-      // Following https://tools.ietf.org/html/rfc5116#section-3.1 to
-      // implement a fixed + variable (counter) nonce generator. If
-      // the key is not given, we use gnutls_rnd with GNUTLS_RND_NONCE.
+      // Format: (iv-auto REQUIRED-LENGTH)
 
       if (! INTEGERP (start))
         {
@@ -4932,54 +4929,12 @@ extract_data_from_object (Lisp_Object spec,
       else
         {
           /* Make sure the value of "start" doesn't change.  */
-          size_t start_hold = XINT (start);
+          size_t start_hold = XUINT (start);
           object = make_uninit_string (start_hold);
+          gnutls_rnd (GNUTLS_RND_NONCE, SSDATA (object), start_hold);
 
-          int length_of_key_hash = 8;
-          Lisp_Object key_hash = Qnil;
-          // If the key was passed to us, use it to form the nonce.
-          if (! NILP (end))
-            {
-              Lisp_Object key_spec = list5 (end, Qnil, Qnil, Qnil, Qt);
-              ptrdiff_t start_key_byte, end_key_byte;
-              const char* key_input = extract_data_from_object (key_spec,
-                                                                
&start_key_byte,
-                                                                &end_key_byte);
-
-              if (key_input != NULL)
-                {
-                  // This will produce more than length_of_key_hash
-                  // bytes, but we'll use just length_of_key_hash.
-                  Lisp_Object k = make_string (key_input, end_key_byte - 
start_key_byte);
-                  Lisp_Object full = secure_hash (Qsha384, k,
-                                                  Qnil, Qnil, Qnil, Qt, Qt);
-                  key_hash = make_string (SSDATA (full), length_of_key_hash);
-                }
-            }
-
-          // For any reason we don't have a key: make one with 
GNUTLS_RND_NONCE.
-          if (NILP (key_hash))
-            {
-              key_hash = make_uninit_string (length_of_key_hash);
-              gnutls_rnd (GNUTLS_RND_NONCE,
-                          SSDATA (key_hash),
-                          length_of_key_hash);
-            }
-
-          uint64_t counter_value = 0;
-          Lisp_Object counter = call3 (intern ("gethash"), key_hash, 
iv_auto_hashtable,
-                                       make_number (counter_value));
-          if (INTEGERP (counter))
-            {
-              counter_value = XUINT (counter);
-              counter_value++;
-              counter = make_number (counter_value);
-            }
-
-          call3 (intern ("puthash"), key_hash, counter, iv_auto_hashtable);
-          memcpy (SSDATA (key_hash), SSDATA (object), length_of_key_hash);
-          memcpy (SSDATA (counter), SSDATA (object) + length_of_key_hash,
-                  min (start_hold - length_of_key_hash, 4));
+          *start_byte = 0;
+          *end_byte = start_hold;
         }
 #else
       error ("GnuTLS integration is not available, so 'iv-auto can't be 
used.");
diff --git a/src/gnutls.c b/src/gnutls.c
index 5387075..cd4ed91 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -1755,6 +1755,7 @@ gnutls_symmetric_aead (bool encrypting, 
gnutls_cipher_algorithm_t gca,
 
   const char* desc = (encrypting ? "encrypt" : "decrypt");
   int ret = GNUTLS_E_SUCCESS;
+  Lisp_Object actual_iv = make_unibyte_string (vdata, vsize);
 
   gnutls_aead_cipher_hd_t acipher;
   gnutls_datum_t key_datum = { (unsigned char*) kdata, ksize };
@@ -1851,7 +1852,7 @@ gnutls_symmetric_aead (bool encrypting, 
gnutls_cipher_algorithm_t gca,
   Lisp_Object output = make_unibyte_string ((const char *)storage, 
storage_length);
   memset (storage, 0, storage_length);
   SAFE_FREE ();
-  return output;
+  return list2 (output, actual_iv);
 #else
   error ("GnuTLS AEAD cipher %ld was invalid or not found", (long) gca);
   return Qnil;
@@ -1955,6 +1956,8 @@ gnutls_symmetric (bool encrypting, Lisp_Object cipher,
       return Qnil;
     }
 
+  Lisp_Object actual_iv = make_unibyte_string (vdata, vend_byte - vstart_byte);
+
   ptrdiff_t istart_byte, iend_byte;
   const char* idata = extract_data_from_object (input, &istart_byte, 
&iend_byte);
 
@@ -2039,7 +2042,7 @@ gnutls_symmetric (bool encrypting, Lisp_Object cipher,
 
   gnutls_cipher_deinit (hcipher);
 
-  return storage;
+  return list2 (storage, actual_iv);
 }
 
 DEFUN ("gnutls-symmetric-encrypt", Fgnutls_symmetric_encrypt, 
Sgnutls_symmetric_encrypt, 4, 5, 0,
diff --git a/test/lisp/net/gnutls-tests.el b/test/lisp/net/gnutls-tests.el
index f0fd25f..a4e7bb7 100644
--- a/test/lisp/net/gnutls-tests.el
+++ b/test/lisp/net/gnutls-tests.el
@@ -184,8 +184,10 @@
 
 (defun gnutls-tests-pad-or-trim (s exact)
   "Pad or trim string S to EXACT numeric size."
-  (let ((e (number-to-string exact)))
-    (format (concat "%" e "." e "s") s)))
+  (if (and (consp s) (eq 'iv-auto (nth 0 s)))
+      s
+    (let ((e (number-to-string exact)))
+      (format (concat "%" e "." e "s") s))))
 
 (defun gnutls-tests-pad-to-multiple (s blocksize)
   "Pad string S to BLOCKSIZE numeric size."
@@ -221,8 +223,11 @@
                    (key (gnutls-tests-pad-or-trim key (plist-get cplist 
:cipher-keysize)))
                    (input (gnutls-tests-pad-to-multiple input (plist-get 
cplist :cipher-blocksize)))
                    (iv (gnutls-tests-pad-or-trim iv (plist-get cplist 
:cipher-ivsize)))
-                   (data (gnutls-symmetric-encrypt cplist (copy-sequence key) 
iv input))
-                   (reverse (gnutls-symmetric-decrypt cplist (copy-sequence 
key) iv data)))
+                   (output (gnutls-symmetric-encrypt cplist (copy-sequence 
key) iv input))
+                   (data (nth 0 output))
+                   (actual-iv (nth 1 output))
+                   (reverse-output (gnutls-symmetric-decrypt cplist 
(copy-sequence key) actual-iv data))
+                   (reverse (nth 0 reverse-output)))
               (gnutls-tests-message "%s %S" cipher cplist)
               (gnutls-tests-message "key %S IV %S input %S => hexdata %S and 
reverse %S" key iv input (encode-hex-string data) reverse)
               (should-not (gnutls-tests-hexstring-equal input data))
@@ -245,7 +250,8 @@
         (ciphers (remove-if
                   (lambda (c) (or (null (plist-get (cdr (assq c 
(gnutls-ciphers)))
                                               :cipher-aead-capable))))
-                  gnutls-tests-tested-ciphers)))
+                  gnutls-tests-tested-ciphers))
+        actual-ivlist)
 
     (dolist (cipher ciphers)
       (dolist (input inputs)
@@ -255,13 +261,22 @@
                    (key (gnutls-tests-pad-or-trim key (plist-get cplist 
:cipher-keysize)))
                    (input (gnutls-tests-pad-to-multiple input (plist-get 
cplist :cipher-blocksize)))
                    (ivsize (plist-get cplist :cipher-ivsize)))
-              (dolist (iv (append ivs (list (list 'iv-auto ivsize key)
-                                            (list 'iv-auto ivsize))))
+              (should (>= ivsize 12))   ; as per the RFC
+              (dolist (iv (append ivs (list (list 'iv-auto ivsize))))
 
                 (gnutls-tests-message "%S, starting key %S IV %S input %S auth 
%S" (assq cipher (gnutls-ciphers)) key iv input auth)
                 (let* ((iv (gnutls-tests-pad-or-trim iv (plist-get cplist 
:cipher-ivsize)))
-                       (data (gnutls-symmetric-encrypt cplist (copy-sequence 
key) iv input (copy-sequence auth)))
-                       (reverse (gnutls-symmetric-decrypt cplist 
(copy-sequence key) iv data auth)))
+                       (output (gnutls-symmetric-encrypt cplist (copy-sequence 
key) iv input (copy-sequence auth)))
+                       (data (nth 0 output))
+                       (actual-iv (nth 1 output))
+                       (reverse-output (gnutls-symmetric-decrypt cplist 
(copy-sequence key) actual-iv data auth))
+                       (reverse (nth 0 reverse-output)))
+                  ;; GNUTLS_RND_NONCE should be good enough to ensure this.
+                  (should-not (member (secure-hash 'sha384 actual-iv 0 ivsize) 
actual-ivlist))
+                  (when (consp iv)
+                    (push (secure-hash 'sha384 actual-iv 0 ivsize) 
actual-ivlist)
+                    (gnutls-tests-message "IV list length: %d" (length 
actual-ivlist)))
+
                   (gnutls-tests-message "%s %S" cipher cplist)
                   (gnutls-tests-message "key %S IV %S input %S auth %S => 
hexdata %S and reverse %S" key iv input auth (encode-hex-string data) reverse)
                   (should-not (gnutls-tests-hexstring-equal input data))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]