Commits

Anonymous committed b09b905

Add rijndael.el.

  • Participants
  • Parent commits 3abf951

Comments (0)

Files changed (3)

 
 ELCS = ascii-armor.elc blowfish.elc des.elc idea.elc paranoid.elc rander.elc \
 	rc16.elc sha1.elc sha1-el.elc sha1-dl.elc md4.elc md5.elc md5-el.elc \
-	md5-dl.elc hex-util.elc
+	md5-dl.elc hex-util.elc rijndael.elc
 
 include ../../XEmacs.rules
 
-all:: $(ELCS) auto-autoloads.elc
+all:: $(ELCS) auto-autoloads.elc custom-load.elc
 
 srckit: srckit-std
 

File package-info.in

    filename FILENAME
    md5sum MD5SUM
    size SIZE
-   provides (ascii-armor blowfish des hex-util idea md4 md5-dl md5-el md5 paranoid rander rc16 sha1-dl sha1-el sha1)
+   provides (ascii-armor blowfish des hex-util idea md4 md5-dl md5-el md5 paranoid rander rc16 rijndael sha1-dl sha1-el sha1)
    requires (REQUIRES)
    type regular
 ))
+;;; rijndael.el --- Rijndael (AES) block cipher implementation
+;; Copyright (C) 2001 Simon Josefsson
+
+;; Author: Simon Josefsson <jas@pdc.kth.se>
+;; Keywords: rijndael aes block cipher symmetric encryption cryptography
+
+;; This software is provided as-is, without express or implied
+;; warranty.  Permission to use, copy, modify, distribute or sell this
+;; software, without fee, for any purpose and by any individual or
+;; organization, is hereby granted, provided that the above copyright
+;; notice and this paragraph appear in all copies.
+
+;;; Commentary:
+
+;; This is a implementation of the Rijndael block cipher algorithm in
+;; Emacs Lisp.  Rijndael has been chosen as the Advanced Encryption
+;; Standard (AES) by NIST.
+;;
+;; This package also have functionality to generate (some of) NIST's
+;; Rijndael test vectors.  However, they will take a very long time to
+;; generate in elisp.  You can customize `rijndael-monte-carlo-limit'
+;; from the default of 10,000 into something more sensible as, say, 1
+;; to make it faster.  It is also possible to customize the loop
+;; length defined by `rijndael-monte-carlo-loop' from the default 400.
+;; Of course, you need to modify the reference implementation as well
+;; if you want to make useful comparisons of the test vectors.
+;;
+;; Rijndael home page is at:
+;; http://www.esat.kuleuven.ac.be/~rijmen/rijndael/
+;;
+;; Any updated releases of this file will be located at:
+;; http://josefsson.org/aes/
+
+;;; Instructions:
+
+;; Call functions in Emacs Lisp programs, or use this package
+;; interactively in the *scratch* buffer in emacs.
+;;
+;; Here's how you could do a simple encryption interactively (press
+;; C-j to evaluate each line):
+;;
+;; (setq key (rijndael-make-key 128 (rijndael-hexstring-to-bitstring
+;;                                   "00000000000000000000000000000000")))
+;;
+;; (setq data (rijndael-hexstring-to-bitstring
+;;	       "00000000000000000000000000000000"))
+;;
+;; (rijndael-bitstring-to-hexstring
+;;  (rijndael-block-encrypt data key 'ecb 128))
+;;
+;; Or more compact as:
+;;
+;; (rijndael-bitstring-to-hexstring
+;;  (rijndael-block-encrypt 
+;;   (rijndael-hexstring-to-bitstring "00000000000000000000000000000000")
+;;   (rijndael-make-key 128 (rijndael-hexstring-to-bitstring
+;;                           "00000000000000000000000000000000"))
+;;   'ecb 128))
+;;
+;; For reference, correct output is "66e94bd4ef8a2c3b884cfa59ca342b2e".
+;;
+;; NB! `data' will be destructively modified.
+
+;;; Todo:
+
+;; Other modes than ECB.
+
+;;; Revision history:
+
+;; 2001-03-31  Posted to gnu.emacs.sources.
+;; 2001-04-04  Ported to (X)Emacs 19.
+;; 2001-05-10  Supports 160 and 224 key and block sizes.
+;; 2001-09-27  Posted to gnu.emacs.sources.
+
+
+;;; Code:
+
+;; User variables:
+
+(eval-and-compile
+  ;; Provide dummy customize functions for emacsen that doesn't have them.
+  (if (not (and (or (featurep 'custom) (load "custom" t))
+		(fboundp 'defcustom) (fboundp 'defgroup)))
+      (progn
+	(if (not (fboundp 'defcustom))
+	    (defmacro defcustom (var value doc &rest args)
+	      (list 'defvar var value doc)))
+	(if (not (fboundp 'defgroup))
+	    (defmacro defgroup (&rest args))))))
+
+(defgroup rijndael nil
+  "Rijndael cryptographic functions")
+
+(defcustom rijndael-monte-carlo-limit 10000
+  "How many iterations to do in the Monte-Carlo tests.
+NIST uses 10000 (the default), but this will be very slow, so you may
+change this to a lower value (like, say, 1).  Of course, you must
+modify the Rijndael reference implementation to be able to compare the
+output."
+  :group 'rijndael
+  :type 'integer)
+
+(defcustom rijndael-monte-carlo-loop 400
+  "How many iterations to do in the Monte-Carlo tests.
+NIST uses 400 (the default), but this will be very slow, so you may
+change this to a lower value (like, say, 1).  Of course, you must
+modify the Rijndael reference implementation to be able to compare the
+output."
+  :group 'rijndael
+  :type 'integer)
+
+
+;; Internal constants:
+
+(defconst rijndael-Logtable
+  [  0   0  25   1  50   2  26 198  75 199  27 104  51 238 223   3
+   100   4 224  14  52 141 129 239  76 113   8 200 248 105  28 193
+   125 194  29 181 249 185  39 106  77 228 166 114 154 201   9 120
+   101  47 138   5  33  15 225  36  18 240 130  69  53 147 218 142
+   150 143 219 189  54 208 206 148  19  92 210 241  64  70 131  56
+   102 221 253  48 191   6 139  98 179  37 226 152  34 136 145  16
+   126 110  72 195 163 182  30  66  58 107  40  84 250 133  61 186
+    43 121  10  21 155 159  94 202  78 212 172 229 243 115 167  87
+   175  88 168  80 244 234 214 116  79 174 233 213 231 230 173 232
+    44 215 117 122 235  22  11 245  89 203  95 176 156 169  81 160
+   127  12 246 111  23 196  73 236 216  67  31  45 164 118 123 183
+   204 187  62  90 251  96 177 134  59  82 161 108 170  85  41 157
+   151 178 135 144  97 190 220 252 188 149 207 205  55  63  91 209
+    83  57 132  60  65 162 109  71  20  42 158  93  86 242 211 171
+    68  17 146 217  35  32  46 137 180 124 184  38 119 153 227 165
+   103  74 237 222 197  49 254  24  13  99 140 128 192 247 112   7]
+  "Multiplication in GF(2^8) lookup table.")
+
+(defconst rijndael-Alogtable
+  [  1   3   5  15  17  51  85 255  26  46 114 150 161 248  19  53
+    95 225  56  72 216 115 149 164 247   2   6  10  30  34 102 170
+   229  52  92 228  55  89 235  38 106 190 217 112 144 171 230  49
+    83 245   4  12  20  60  68 204  79 209 104 184 211 110 178 205
+    76 212 103 169 224  59  77 215  98 166 241   8  24  40 120 136
+   131 158 185 208 107 189 220 127 129 152 179 206  73 219 118 154
+   181 196  87 249  16  48  80 240  11  29  39 105 187 214  97 163
+   254  25  43 125 135 146 173 236  47 113 147 174 233  32  96 160
+   251  22  58  78 210 109 183 194  93 231  50  86 250  21  63  65
+   195  94 226  61  71 201  64 192  91 237  44 116 156 191 218 117
+   159 186 213 100 172 239  42 126 130 157 188 223 122 142 137 128
+   155 182 193  88 232  35 101 175 234  37 111 177 200  67 197  84
+   252  31  33  99 165 244   7   9  27  45 119 153 176 203  70 202
+    69 207  74 222 121 139 134 145 168 227  62  66 198  81 243  14
+    18  54  90 238  41 123 141 140 143 138 133 148 167 242  13  23
+    57  75 221 124 132 151 162 253  28  36 108 180 199  82 246   1]
+  "Multiplication in GF(2^8) lookup table.")
+
+(defconst rijndael-S
+  [ 99 124 119 123 242 107 111 197  48   1 103  43 254 215 171 118
+   202 130 201 125 250  89  71 240 173 212 162 175 156 164 114 192
+   183 253 147  38  54  63 247 204  52 165 229 241 113 216  49  21
+     4 199  35 195  24 150   5 154   7  18 128 226 235  39 178 117
+     9 131  44  26  27 110  90 160  82  59 214 179  41 227  47 132
+    83 209   0 237  32 252 177  91 106 203 190  57  74  76  88 207
+   208 239 170 251  67  77  51 133  69 249   2 127  80  60 159 168
+    81 163  64 143 146 157  56 245 188 182 218  33  16 255 243 210
+   205  12  19 236  95 151  68  23 196 167 126  61 100  93  25 115
+    96 129  79 220  34  42 144 136  70 238 184  20 222  94  11 219
+   224  50  58  10  73   6  36  92 194 211 172  98 145 149 228 121
+   231 200  55 109 141 213  78 169 108  86 244 234 101 122 174   8
+   186 120  37  46  28 166 180 198 232 221 116  31  75 189 139 138
+   112  62 181 102  72   3 246  14  97  53  87 185 134 193  29 158
+   225 248 152  17 105 217 142 148 155  30 135 233 206  85  40 223
+   140 161 137  13 191 230  66 104  65 153  45  15 176  84 187  22]
+  "Rijndael S-box.")
+
+(defconst rijndael-Si
+  [ 82   9 106 213  48  54 165  56 191  64 163 158 129 243 215 251
+   124 227  57 130 155  47 255 135  52 142  67  68 196 222 233 203
+    84 123 148  50 166 194  35  61 238  76 149  11  66 250 195  78
+     8  46 161 102  40 217  36 178 118  91 162  73 109 139 209  37
+   114 248 246 100 134 104 152  22 212 164  92 204  93 101 182 146
+   108 112  72  80 253 237 185 218  94  21  70  87 167 141 157 132
+   144 216 171   0 140 188 211  10 247 228  88   5 184 179  69   6
+   208  44  30 143 202  63  15   2 193 175 189   3   1  19 138 107
+    58 145  17  65  79 103 220 234 151 242 207 206 240 180 230 115
+   150 172 116  34 231 173  53 133 226 249  55 232  28 117 223 110
+    71 241  26 113  29  41 197 137 111 183  98  14 170  24 190  27
+   252  86  62  75 198 210 121  32 154 219 192 254 120 205  90 244
+    31 221 168  51 136   7 199  49 177  18  16  89  39 128 236  95
+    96  81 127 169  25 181  74  13  45 229 122 159 147 201 156 239
+   160 224  59  77 174  42 245 176 200 235 187  60 131  83 153  97
+    23  43   4 126 186 119 214  38 225 105  20  99  85  33  12 125]
+  "Rijndael inverted S-box.")
+
+(defconst rijndael-rcon [ ?\x01 ?\x02 ?\x04 ?\x08 ?\x10 ?\x20 ?\x40 ?\x80
+			  ?\x1b ?\x36 ?\x6c ?\xd8 ?\xab ?\x4d ?\x9a ?\x2f
+			  ?\x5e ?\xbc ?\x63 ?\xc6 ?\x97 ?\x35 ?\x6a ?\xd4
+			  ?\xb3 ?\x7d ?\xfa ?\xef ?\xc5 ?\x91]
+  "Rijndael round constants used in key scheduling.")
+
+(defconst rijndael-shifts [[[0 0]
+			    [1 3]
+			    [2 2]
+			    [3 1]]
+
+			   [[0 0]
+			    [1 4]
+			    [2 3]
+			    [3 2]]
+		     
+			   [[0 0]
+			    [1 5]
+			    [2 4]
+			    [3 3]]
+
+			   [[0 0]
+			    [1 6]
+			    [2 5]
+			    [4 3]]
+			   
+			   [[0 0]
+			    [1 7]
+			    [3 5]
+			    [4 4]]]
+  "Rijndael shift offsets.
+Element M is used when blocksizes match M=Nb-4.
+Element N inside a shift amount for each blocksize corresponds with
+the row to shift.
+The first element O1 of each row corresponds with encryption offset,
+the second element O2 to decryption offset. (O2 inverse of O1 under mod Nb.)")
+
+(defconst rijndael-maxbc (/ 256 32)
+  "Rijndael maximum size of data blocks.")
+
+(defconst rijndael-maxkc (/ 256 32)
+  "Rijndael maximum size of key blocks.")
+
+(defconst rijndael-maxrounds 14
+  "Rijndael maximum number of rounds.")
+
+(defconst rijndael-hex-alist 
+  '((?0 . 0)	      (?a . 10)	      (?A . 10)
+    (?1 . 1)	      (?b . 11)	      (?B . 11)
+    (?2 . 2)	      (?c . 12)	      (?C . 12)
+    (?3 . 3)	      (?d . 13)	      (?D . 13)
+    (?4 . 4)	      (?e . 14)	      (?E . 14)
+    (?5 . 5)	      (?f . 15)	      (?F . 15)
+    (?6 . 6)
+    (?7 . 7)
+    (?8 . 8)
+    (?9 . 9))
+  "Hex table for use in base conversions.")
+
+
+;; Basic low-level cryptograhic primitives:
+
+(defsubst rijndael-mul (a b)
+  "Rijndael MUL primitive.
+Multiply two elements of GF(2^m).
+needed for MixColumn and InvMixColumn."
+  (if (and (not (= a 0))
+	   (not (= b 0)))
+      (aref rijndael-Alogtable (% (+ (aref rijndael-Logtable a)
+				     (aref rijndael-Logtable b))
+				  255))
+    0))
+
+(defsubst rijndael-key-addition (a rk bc)
+  "Rijndael keyAddition primitive.
+Exor corresponding text input and round key input bytes."
+  (let ((i 0) j)
+    (while (< i 4)
+      (setq j 0)
+      (while (< j bc)
+	(aset (aref a i) j
+	      (logxor (aref (aref a i) j)
+		      (aref (aref rk i) j)))
+	(setq j (1+ j)))
+      (setq i (1+ i)))))
+
+(defsubst rijndael-shift-row (a d bc)
+  "Rijndael ShiftRow primitive.
+Row 0 remains unchanged.
+The other three rows are shifted a variable amount."
+  (let (i j (tmp (make-vector rijndael-maxbc 0)))
+    (setq i 1)
+    (while (< i 4)
+      (setq j 0)
+      (while (< j bc)
+	(aset tmp j
+	      (aref (aref a i)
+		    (% (+ j (aref (aref (aref rijndael-shifts
+					      (- bc 4))
+					i)
+				  d))
+		       bc)))
+	(setq j (1+ j)))
+      (setq j 0)
+      (while (< j bc)
+	(aset (aref a i) j (aref tmp j))
+	(setq j (1+ j)))
+      (setq i (1+ i)))))
+
+(defsubst rijndael-substitution (a box bc)
+  "Rijndael substitution primitive.
+Replace every byte of the input by the byte at that place
+in the nonlinear S-box."
+  (let ((i 0) j)
+    (while (< i 4)
+      (setq j 0)
+      (while (< j bc)
+	(aset (aref a i) j (aref box (aref (aref a i) j)))
+	(setq j (1+ j)))
+      (setq i (1+ i)))))
+
+(defsubst rijndael-mix-column (a bc)
+  "Rijndael MixColumn primitive.
+Mix the four bytes of every column in a linear way."
+  (let ((b (make-vector 4 0)) i j)
+    ;; init b
+    (setq i 0)
+    (while (< i 4)
+      (aset b i (make-vector rijndael-maxbc 0))
+      (setq i (1+ i)))
+    ;; do it
+    (setq j 0)
+    (while (< j bc)
+      (setq i 0)
+      (while (< i 4)
+	(aset (aref b i)
+	      j
+	      (logxor (rijndael-mul 2 (aref (aref a i) j))
+		      (rijndael-mul 3 (aref (aref a (% (+ i 1) 4)) j))
+		      (aref (aref a (% (+ i 2) 4)) j)
+		      (aref (aref a (% (+ i 3) 4)) j)))
+	(setq i (1+ i)))
+      (setq j (1+ j)))
+    ;; copy b back into a
+    (setq i 0)
+    (while (< i 4)
+      (setq j 0)
+      (while (< j bc)
+	(aset (aref a i) j (aref (aref b i) j))
+	(setq j (1+ j)))
+      (setq i (1+ i)))))
+
+(defsubst rijndael-inv-mix-column (a bc)
+  "Rijndael inverted MixColumn primitive.
+Mix the four bytes of every column in a linear way.
+This is the opposite operation of Mixcolumn."
+  (let ((b (make-vector 4 0)) i j)
+    ;; init b
+    (setq i 0)
+    (while (< i 4)
+      (aset b i (make-vector rijndael-maxbc 0))
+      (setq i (1+ i)))
+    ;; do it
+    (setq j 0)
+    (while (< j bc)
+      (setq i 0)
+      (while (< i 4)
+	(aset (aref b i)
+	      j
+	      (logxor (rijndael-mul ?\x0E (aref (aref a i) j))
+		      (rijndael-mul ?\x0B (aref (aref a (% (+ i 1) 4)) j))
+		      (rijndael-mul ?\x0D (aref (aref a (% (+ i 2) 4)) j))
+		      (rijndael-mul ?\x09 (aref (aref a (% (+ i 3) 4)) j))))
+	(setq i (1+ i)))
+      (setq j (1+ j)))
+    ;; copy b back into a
+    (setq i 0)
+    (while (< i 4)
+      (setq j 0)
+      (while (< j bc)
+	(aset (aref a i) j (aref (aref b i) j))
+	(setq j (1+ j)))
+      (setq i (1+ i)))))
+
+
+;; Internal functions:
+
+(defun rijndael-bc (blockBits)
+  "Determine BC given block size."
+  (if (or (< blockBits 128) (> blockBits 256))
+      (error "Invalid block size %d bits" blockBits)
+    (/ blockBits 32)))
+
+(defun rijndael-rounds (keyBits blockBits)
+  "Determine Rijndael rounds given key and block sizes."
+  (if (or (< keyBits 128) (> keyBits 256) (< blockBits 128) (> blockBits 256))
+      (error "Invalid key/block size combination (key size %d block size %d)"
+	     keyBits blockBits)
+    (+ (/ (max keyBits blockBits) 32) 6)))
+
+(defun rijndael-print-key-schedule (key-schedule)
+  (let (i j k str)
+    (setq i 0)
+    (while (< i (1+ rijndael-maxrounds))
+      (setq j 0)
+      (while (< j 4)
+	(setq k 0)
+	(while (< k rijndael-maxbc)
+	  (setq str (concat str (format "%3d "
+					(aref (aref (aref key-schedule i)
+						    j)
+					      k))))
+	  (setq k (1+ k)))
+	(setq str (concat str "\n"))
+	(setq j (1+ j)))
+      (setq str (concat str "\n"))
+      (setq i (1+ i)))
+    (setq str (concat str "\n"))))
+
+(defun rijndael-key-schedule (k keyBits blockBits)
+  "Rijndael KeySchedule function (internal).
+Calculate the necessary round keys.
+The number of calculations depends on keyBits and blockBits."
+  (let ((rconpointer 0) i j T
+	(kc (rijndael-bc keyBits))
+	(bc (rijndael-bc blockBits))
+	(rounds (rijndael-rounds keyBits blockBits))
+	(tk (make-vector 4 0))
+	(W (make-vector (1+ rijndael-maxrounds) 0))
+	(mid 4))
+    ;; init tk
+    (setq i 0)
+    (while (< i 4)
+      (aset tk i (make-vector rijndael-maxkc 0))
+      (setq i (1+ i)))
+    ;; init W
+    (setq i 0)
+    (while (< i (1+ rijndael-maxrounds))
+      (aset W i (make-vector 4 0))
+      (setq j 0)
+      (while (< j 4)
+	(aset (aref W i) j (make-vector rijndael-maxbc 0))
+	(setq j (1+ j)))
+      (setq i (1+ i)))
+    ;; start
+    (setq j 0)
+    (while (< j kc)
+      (setq i 0)
+      (while (< i 4)
+	(aset (aref tk i) j
+	      (aref (aref k i) j))
+	(setq i (1+ i)))
+      (setq j (1+ j)))
+    ;; copy values into round key array
+    (setq j 0
+	  T 0)
+    (while (and (< j kc) (< T (* (1+ rounds) bc)))
+      (setq i 0)
+      (while (< i 4)
+	(aset (aref (aref W (/ T bc)) i) (% T bc)
+	      (aref (aref tk i) j))
+	(setq i (1+ i)))
+      (setq j (1+ j))
+      (setq T (1+ T)))
+    ;; while not enough round key material calculated
+    (while (< T (* (1+ rounds) bc))
+      ;; calculate new values
+      (setq i 0)
+      (while (< i 4)
+	(aset (aref tk i) 0
+	      (logxor (aref (aref tk i) 0)
+		      (aref rijndael-S
+			    (aref (aref tk (% (1+ i) 4)) (1- kc)))))
+	(setq i (1+ i)))
+      (aset (aref tk 0) 0
+	    (logxor (aref (aref tk 0) 0)
+		    (aref rijndael-rcon rconpointer)))
+      (setq rconpointer (1+ rconpointer))
+      (setq j 1)
+      (if (<= kc 6)
+	  (while (< j kc)
+	    (setq i 0)
+	    (while (< i mid)
+	      (aset (aref tk i) j
+		    (logxor (aref (aref tk i) j)
+			    (aref (aref tk i) (1- j))))
+	      (setq i (1+ i)))
+	    (setq j (1+ j)))
+	(while (< j mid)
+	  (setq i 0)
+	  (while (< i 4)
+	    (aset (aref tk i) j
+		  (logxor (aref (aref tk i) j)
+			  (aref (aref tk i) (1- j))))
+	    (setq i (1+ i)))
+	  (setq j (1+ j)))
+	(setq i 0)
+	(while (< i 4)
+	  (aset (aref tk i) mid
+		(logxor (aref (aref tk i) mid)
+			(aref rijndael-S (aref (aref tk i) (1- mid)))))
+	  (setq i (1+ i)))
+	(setq j (1+ mid) i 0)
+	(while (< j kc)
+	  (setq i 0)
+	  (while (< i mid)
+	    (aset (aref tk i) j
+		  (logxor (aref (aref tk i) j)
+			  (aref (aref tk i) (1- j))))
+	    (setq i (1+ i)))
+	  (setq j (1+ j))))
+      ;; copy values into round key array
+      (setq j 0)
+      (while (and (< j kc) (< T (* (1+ rounds) bc)))
+	(setq i 0)
+	(while (< i 4)
+	  (aset (aref (aref W (/ T bc)) i) (% T bc)
+		(aref (aref tk i) j))
+	  (setq i (1+ i)))
+	(setq j (1+ j))
+	(setq T (1+ T))))
+    W))
+
+(defun rijndael-encrypt (a keyBits blockBits rk &optional rounds)
+  "Rijndael block encryption (internal).
+Encryption of one block.  If optional argument rounds is non-null,
+encrypt only a certain number of rounds (for debugging only)."
+  (let ((r 1)
+	(bc (rijndael-bc blockBits))
+	(ROUNDS (rijndael-rounds keyBits blockBits)))
+    ;; make number of rounds sane
+    (if (or (null rounds) (> rounds ROUNDS))
+	(setq rounds ROUNDS))
+    ;; begin with a key addition
+    (rijndael-key-addition a (aref rk 0) bc)
+    ;; ROUNDS-1 ordinary rounds
+    (while (and (<= r rounds) (< r ROUNDS))
+      (rijndael-substitution a rijndael-S bc)
+      (rijndael-shift-row a 0 bc)
+      (rijndael-mix-column a bc)
+      (rijndael-key-addition a (aref rk r) bc)
+      (setq r (1+ r)))
+    ;; Last round is special: there is no MixColumn
+    (if (= rounds ROUNDS)
+	(progn
+	  (rijndael-substitution a rijndael-S bc)
+	  (rijndael-shift-row a 0 bc)
+	  (rijndael-key-addition a (aref rk rounds) bc)))))
+
+(defun rijndael-decrypt (a keyBits blockBits rk &optional rounds)
+  "Rijndael block decryption (internal).
+Decryption of one block.  If optional argument rounds is non-null,
+decrypt only a certain number of rounds (for debugging only)."
+  (let* ((bc (rijndael-bc blockBits))
+	(ROUNDS (rijndael-rounds keyBits blockBits))
+	(r (1- ROUNDS)))
+    ;; make number of rounds sane
+    (if (or (null rounds) (> rounds ROUNDS))
+	(setq rounds 0))
+    ;; First the special round:
+    ;;   without InvMixColumn
+    ;;   with extra KeyAddition
+    (rijndael-key-addition a (aref rk ROUNDS) bc)
+    (rijndael-substitution a rijndael-Si bc)
+    (rijndael-shift-row a 1 bc)
+    (while (> r rounds)
+      (rijndael-key-addition a (aref rk r) bc)
+      (rijndael-inv-mix-column a bc)
+      (rijndael-substitution a rijndael-Si bc)
+      (rijndael-shift-row a 1 bc)
+      (setq r (1- r)))
+    ;; End with the extra key addition
+    (if (= rounds 0)
+	(rijndael-key-addition a (aref rk 0) bc))))
+
+
+;; Rijndael API functions:
+
+(defun rijndael-make-key (blockbits keymaterial)
+  "Generate Key Schedule given keying material KEYMATERIAL.
+KEYMATERIAL must be of length multiple of 32 bits.
+BLOCKBITS is size of blocks in bits (valid values 128, 160, 192, 224 and 256)."
+  (let ((k (make-vector 4 0)) i
+	(keybits (* (length keymaterial) 8)))
+    ;; init k
+    (setq i 0)
+    (while (< i 4)
+      (aset k i (make-vector rijndael-maxkc 0))
+      (setq i (1+ i)))
+    (setq i 0)
+    (while (< i (/ keybits 8))
+      (aset (aref k (% i 4)) (/ i 4) (aref (vconcat keymaterial) i))
+      (setq i (1+ i)))
+    (list keybits keymaterial (rijndael-key-schedule k keybits blockbits))))
+
+(defun rijndael-block-encrypt (data key mode blockbits &optional iv)
+  "Perform Rijndael encryption of DATA with key KEY.
+DATA is a vector with data to encrypt (the block).
+KEY is a Rijndael Key Schedule (see `rijndael-make-key').
+MODE is a symbol, `ecb', `cbc' or `cfb1', for the encryption mode to use.
+BLOCKBITS is size of blocks in bits (valid values 128, 160, 192, 224 and 256).
+Optional variable IV is a string containing initialization vectors."
+  (let ((numBlocks (/ (length data) (/ blockbits 8)))
+	(blk (make-vector 4 0))
+	i j l)
+    ;; init blk
+    (setq i 0)
+    (while (< i 4)
+      (aset blk i (make-vector rijndael-maxbc 0))
+      (setq i (1+ i)))
+    (cond ((eq mode 'ecb)
+	   (setq i 0)
+	   (while (< i numBlocks)
+	     (setq j 0)
+	     (while (< j (/ blockbits 32))
+	       (setq l 0)
+	       (while (< l 4)
+		 (aset (aref blk l) j (aref data (+ (* (/ blockbits 8) i)
+						    (* 4 j)
+						    l)))
+		 (setq l (1+ l)))
+	       (setq j (1+ j)))
+	     (rijndael-encrypt blk (nth 0 key) blockbits (nth 2 key))
+	     (setq j 0)
+	     (while (< j (/ blockbits 32))
+	       (setq l 0)
+	       (while (< l 4)
+		 (aset data (+ (* (/ blockbits 8) i)
+			       (* 4 j)
+			       l)
+		       (aref (aref blk l) j))
+		 (setq l (1+ l)))
+	       (setq j (1+ j)))
+	     (setq i (1+ i))))
+	  (t
+	   (error "Unknown encryption mode: %s" mode)))
+    data))
+
+(defun rijndael-block-decrypt (data key mode blockbits &optional iv)
+  "Perform Rijndael encryption of DATA with key KEY.
+DATA is a vector with data to encrypt (the block).
+KEY is a Rijndael Key Schedule (see `rijndael-make-key').
+MODE is a symbol, `ecb', `cbc' or `cfb1', for the decryption mode to use.
+BLOCKBITS is size of block in bits (valid values 128, 160, 192, 224 and 256).
+Optional variable IV is a string containing initialization vectors."
+  (let ((numBlocks (/ (length data) (/ blockbits 8)))
+	(blk (make-vector 4 0))
+	i j l)
+    ;; init blk
+    (setq i 0)
+    (while (< i 4)
+      (aset blk i (make-vector rijndael-maxbc 0))
+      (setq i (1+ i)))
+    (cond ((eq mode 'ecb)
+	   (setq i 0)
+	   (while (< i numBlocks)
+	     (setq j 0)
+	     (while (< j (/ blockbits 32))
+	       (setq l 0)
+	       (while (< l 4)
+		 (aset (aref blk l) j (aref data (+ (* (/ blockbits 8) i)
+						    (* 4 j)
+						    l)))
+		 (setq l (1+ l)))
+	       (setq j (1+ j)))
+	     (rijndael-decrypt blk (nth 0 key) blockbits (nth 2 key))
+	     (setq j 0)
+	     (while (< j (/ blockbits 32))
+	       (setq l 0)
+	       (while (< l 4)
+		 (aset data (+ (* (/ blockbits 8) i)
+			       (* 4 j)
+			       l)
+		       (aref (aref blk l) j))
+		 (setq l (1+ l)))
+	       (setq j (1+ j)))
+	     (setq i (1+ i))))
+	  (t
+	   (error "Unknown decryption mode: %s" mode)))
+    data))
+
+
+;; Conversion functions:
+
+(defun rijndael-hex-to-int (str)
+  (if str
+      (if (listp str)
+	  (+ (* 16 (rijndael-hex-to-int (cdr str)))
+	     (cdr (assoc (car str) rijndael-hex-alist)))
+	(rijndael-hex-to-int (reverse (append str nil))))
+    0))
+
+(defun rijndael-hexstring-to-bitstring (str)
+  (let (out)
+    (while (< 0 (length str))
+      (setq out (cons (rijndael-hex-to-int (substring str -2)) out))
+      (setq str (substring str 0 -2)))
+    (concat out)))
+
+(defun rijndael-vector-to-hexstring (vec)
+  (mapconcat (lambda (el)
+	       (format "%02x" el))
+	     vec
+	     ""))
+
+(defun rijndael-vector-to-bitstring (vec)
+  (rijndael-hexstring-to-bitstring (rijndael-vector-to-hexstring vec)))
+
+(defun rijndael-bitstring-to-vector (str)
+  (let ((out (make-vector (length str) 0))
+	(i (1- (length str))))
+    (while (< 0 (length str))
+      (aset out i (string-to-char (substring str -1)))
+      (setq i (1- i))
+      (setq str (substring str 0 -1)))
+    out))
+
+(defun rijndael-bitstring-to-hexstring (str)
+  (let ((out ""))
+    (while (< 0 (length str))
+      (setq out (format "%02x%s" (string-to-char (substring str -1)) out))
+      (setq str (substring str 0 -1)))
+    out))
+
+
+;; NIST test value generator
+
+(defun rijndael-nist ()
+  "Generate NIST test values.
+The output is to be compared with the NIST tabulated values."
+  (interactive)
+  (switch-to-buffer (generate-new-buffer "*NIST Rijndael test values"))
+  (erase-buffer)
+  (insert "\n\n\nElectronic Codebook (ECB) Mode - ENCRYPTION\n")
+  ;; ECB encrypt keysize 128
+  (rijndael-nist-ecb-mct
+   "00000000000000000000000000000000" 128
+   "00000000000000000000000000000000" 128 'encrypt)
+  ;; ECB encrypt keysize 160
+  (rijndael-nist-ecb-mct
+   "0000000000000000000000000000000000000000" 160
+   "00000000000000000000000000000000" 128 'encrypt)
+  ;; ECB encrypt keysize 192
+  (rijndael-nist-ecb-mct
+   "000000000000000000000000000000000000000000000000" 192
+   "00000000000000000000000000000000" 128 'encrypt)
+  ;; ECB encrypt keysize 224
+  (rijndael-nist-ecb-mct
+   "00000000000000000000000000000000000000000000000000000000" 224
+   "00000000000000000000000000000000" 128 'encrypt)
+  ;; ECB encrypt keysize 256
+  (rijndael-nist-ecb-mct
+   "0000000000000000000000000000000000000000000000000000000000000000" 256
+   "00000000000000000000000000000000" 128 'encrypt)
+  (insert "\n\n\nElectronic Codebook (ECB) Mode - DECRYPTION\n")
+  ;; ECB decrypt keysize 128
+  (rijndael-nist-ecb-mct
+   "00000000000000000000000000000000" 128
+   "00000000000000000000000000000000" 128 'decrypt)
+  ;; ECB decrypt keysize 160
+  (rijndael-nist-ecb-mct
+   "0000000000000000000000000000000000000000" 160
+   "00000000000000000000000000000000" 128 'decrypt)
+  ;; ECB decrypt keysize 192
+  (rijndael-nist-ecb-mct
+   "000000000000000000000000000000000000000000000000" 192
+   "00000000000000000000000000000000" 128 'decrypt)
+  ;; ECB decrypt keysize 224
+  (rijndael-nist-ecb-mct
+   "00000000000000000000000000000000000000000000000000000000" 224
+   "00000000000000000000000000000000" 128 'decrypt)
+  ;; ECB decrypt keysize 256
+  (rijndael-nist-ecb-mct
+   "0000000000000000000000000000000000000000000000000000000000000000" 256
+   "00000000000000000000000000000000" 128 'decrypt)
+  (message "NIST Rijndael tables generation...done"))
+
+(defun rijndael-nist-ecb-mct (initKey keyLength initBlock blockLength dir)
+  (let ((binKey (rijndael-bitstring-to-vector
+		 (rijndael-hexstring-to-bitstring initKey)))
+	(outBlock (rijndael-hexstring-to-bitstring initBlock))
+	(i 0) j keyInst inBlock)
+    (insert "\n=========================\n\n")
+    (insert (format "KEYSIZE=%d\n" keyLength))
+    (while (< i rijndael-monte-carlo-loop)
+      (sit-for 0)
+      (insert (format "\nI=%d\n" i))
+      (insert "KEY=" (rijndael-vector-to-hexstring binKey) "\n")
+      (setq keyInst (rijndael-make-key blockLength 
+				       (rijndael-vector-to-bitstring binKey)))
+      (insert (if (eq dir 'encrypt) "PT=" "CT=")
+	      (rijndael-bitstring-to-hexstring outBlock) "\n")
+      (setq j 0)
+      (while (< j rijndael-monte-carlo-limit)
+	(if (eq (% j 100) 0)
+	    (message (concat "Rijndael NIST ECB MCT %sion (%db keys, "
+			     "%db blocks) loop %d of %d%s")
+		     dir keyLength blockLength i 
+		     rijndael-monte-carlo-loop
+		     (if (> rijndael-monte-carlo-limit 1)
+			 (format " iteration %d of %d" j
+				 rijndael-monte-carlo-limit)
+		       "")))
+	(setq inBlock (copy-sequence outBlock))
+	(if (eq dir 'encrypt)
+	    (rijndael-block-encrypt outBlock keyInst 'ecb blockLength)
+	  (rijndael-block-decrypt outBlock keyInst 'ecb blockLength))
+	(setq j (1+ j)))
+      (insert (if (eq dir 'encrypt) "CT=" "PT=")
+	      (rijndael-bitstring-to-hexstring outBlock) "\n")
+      (cond ((eq keyLength 128)
+	     (setq j 0)
+	     (while (< j (/ 128 8))
+	       (aset binKey j (logxor (aref binKey j)
+				      (aref
+				       (rijndael-bitstring-to-vector outBlock)
+				       j)))
+	       (setq j (1+ j))))
+	    ((eq keyLength 192)
+	     (setq j 0)
+	     (while (< j (/ 64 8))
+	       (aset binKey j (logxor (aref binKey j)
+				      (aref
+				       (rijndael-bitstring-to-vector inBlock)
+				       (+ j (/ 64 8)))))
+	       (setq j (1+ j)))
+	     (setq j 0)
+	     (while (< j (/ 128 8))
+	       (aset binKey (+ j (/ 64 8))
+		     (logxor (aref binKey (+ j (/ 64 8)))
+			     (aref (rijndael-bitstring-to-vector outBlock) j)))
+	       (setq j (1+ j))))
+	    ((eq keyLength 256)
+	     (setq j 0)
+	     (while (< j (/ 128 8))
+	       (aset binKey j (logxor (aref binKey j)
+				      (aref
+				       (rijndael-bitstring-to-vector inBlock)
+				       j)))
+	       (setq j (1+ j)))
+	     (setq j 0)
+	     (while (< j (/ 128 8))
+	       (aset binKey (+ j (/ 128 8))
+		     (logxor (aref binKey j)
+			     (aref
+			      (rijndael-bitstring-to-vector outBlock)
+			      j)))
+	       (setq j (1+ j)))))
+      (setq i (1+ i)))))
+
+(provide 'rijndael)
+
+;; rijndael.el ends here