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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
|
;;; 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
|