summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/aes
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
commitea28451286d3ea4a772fa174483f9a7a66bb1ab3 (patch)
tree6ee9d8a7848333a7ceeee3b13d492e40225f8b86 /tcllib/modules/aes
parentb5ca09bae0d6a1edce939eea03594dd56383f2c8 (diff)
parent7c621da28f07e449ad90c387344f07a453927569 (diff)
downloadblt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.zip
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.gz
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.bz2
Merge commit '7c621da28f07e449ad90c387344f07a453927569' as 'tcllib'
Diffstat (limited to 'tcllib/modules/aes')
-rw-r--r--tcllib/modules/aes/ChangeLog146
-rw-r--r--tcllib/modules/aes/aes.bench75
-rw-r--r--tcllib/modules/aes/aes.man168
-rw-r--r--tcllib/modules/aes/aes.pcx99
-rw-r--r--tcllib/modules/aes/aes.tcl625
-rw-r--r--tcllib/modules/aes/aes.test358
-rw-r--r--tcllib/modules/aes/pkgIndex.tcl5
7 files changed, 1476 insertions, 0 deletions
diff --git a/tcllib/modules/aes/ChangeLog b/tcllib/modules/aes/ChangeLog
new file mode 100644
index 0000000..2c7b5ee
--- /dev/null
+++ b/tcllib/modules/aes/ChangeLog
@@ -0,0 +1,146 @@
+2013-05-30 Andreas Kupries <andreask@activestate.com>
+
+ * aes.tcl (::aes::Chunk): [Bug 3612645][Allura 1366]: Fix handling
+ * aes.test: of last block read, it may be empty. In that case we
+ * aes.man: must not pad, nor try to decrypt it into garbage.
+ * pkgIndex.tcl: Extended testsuite with cases for this. Version
+ bumped to 1.1.1.
+
+2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.15 ========================
+ *
+
+2013-01-08 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * aes.man: [Bug 3574004]: Documented the -- option stopping
+ * aes.tcl: option processing to protect data starting with
+ * aes.test: a dash. Additionally auto-stop if only one argument
+ * pkgIndex.tcl: is left, treating it as data. Bumped to
+ version 1.1.
+
+2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.14 ========================
+ *
+
+2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.13 ========================
+ *
+
+2010-07-06 Andreas Kupries <andreask@activestate.com>
+
+ * aes.tcl (DecryptBlock, EncryptBlock): [Bug 2993029]: More code
+ * aes.man: limiting the values to int32 range. Extended the
+ * aes.test: testsuite. Bumped version to 1.0.2. See also the
+ * pkgIndex.tcl: changelog entry of 2008-05-12.
+
+2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.12 ========================
+ *
+
+2009-01-19 Elchonon Edelson <eee@users.sourceforge.net>
+
+ * aes.man: Minor enhancement.
+
+2008-12-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11.1 ========================
+ *
+
+2008-10-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11 ========================
+ *
+
+2008-06-06 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * aes.pcx: New file. Syntax definitions for the public commands of
+ the aes package.
+
+2008-05-13 Andreas Kupries <andreask@activestate.com>
+
+ * pkgIndex.tcl: Version bump missed the index :(
+
+2008-05-12 Andreas Kupries <andreask@activestate.com>
+
+ * aes.tcl (DecryptBlock, EncryptBlock): Added code limiting the
+ * aes.man: values to int32 range, to prevent going out of range
+ * aes.test: when run by Tcl 8.5 and its bignums. Extended
+ * pkgIndex.tcl: testsuite to catch a problematic case which fails
+ without the change. Bumped version to 1.0.1.
+
+ * aes.tcl (::aes::Pop, ::aes::aes): Also, cleaned up upvar command
+ without explicit level information.
+
+2007-09-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.10 ========================
+ *
+
+2007-03-19 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * aes.man: Fixed all warnings due to use of now deprecated
+ commands. Added a section about how to give feedback.
+
+2006-10-03 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.9 ========================
+ *
+
+2006-01-22 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * aes.test: More boilerplate simplified via use of test support.
+
+2006-01-19 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * aes.test: Hooked into the new common test support code.
+
+2005-10-18 Andreas Kupries <andreask@activestate.com>
+
+ * aes.bench: Extended with benchmarks for the keyschedule.
+
+2005-10-06 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.8 ========================
+ *
+
+2005-09-04 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * aes.tcl: Frink warning suppression
+ * aes.man: Added a description of cipher modes of operation.
+
+2005-09-01 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * aes.tcl: Re-written to support CBC mode AES and to allow for
+ * aes.test: the tcllib-style programming API (as per blowfish, RC4 and
+ * aes.man: the hash implementations). Converted from an array based
+ * pkgIndex.tcl: implementation to a list based implementation and
+ gained a 4x speedup. Set to 1.0.0 for now the API is fixed.
+
+2005-08-30 Andreas Kupries <andreask@activestate.com>
+
+ * pkgIndex.tcl: **New file**. Added the missing package index
+ without which the package cannot be used.
+
+2005-08-29 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * aes.tcl: Added a number of performance improvements
+ * aes.test:
+
+2005-08-29 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * aes.tcl: Initial import of a Tcl implementation of
+ * aes.test: the Advanced Encryption Standard contributed
+ * aes.man: by Thorsten Schloermann <fattobi@users.sourceforge.net>
diff --git a/tcllib/modules/aes/aes.bench b/tcllib/modules/aes/aes.bench
new file mode 100644
index 0000000..9ab598f
--- /dev/null
+++ b/tcllib/modules/aes/aes.bench
@@ -0,0 +1,75 @@
+# -*- tcl -*-
+# Tcl Benchmark File
+#
+# This file contains a number of benchmarks for the 'aes' module.
+# This allow developers to monitor/gauge/track package performance.
+#
+# (c) 2005 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+# We need at least version 8.2 for the package and thus the
+# benchmarks.
+
+if {![package vsatisfies [package provide Tcl] 8.2]} {
+ return
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Setting up the environment ...
+
+package forget aes
+catch {namespace delete ::aes}
+source [file join [file dirname [info script]] aes.tcl]
+
+set i [binary format H* 00000000000000000000000000000000]
+set p [binary format H* 00112233445566778899aabbccddeeff]
+
+# ### ### ### ######### ######### ######### ###########################
+## Benchmarks.
+
+foreach {len k c} [list \
+ 128 \
+ [binary format H* 000102030405060708090a0b0c0d0e0f] \
+ [binary format H* 69c4e0d86a7b0430d8cdb78070b4c55a] \
+ 192 \
+ [binary format H* 000102030405060708090a0b0c0d0e0f1011121314151617] \
+ [binary format H* dda97ca4864cdfe06eaf70a0ec0d7191] \
+ 256 \
+ [binary format H* 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f] \
+ [binary format H* 8ea2b7ca516745bfeafc49904b496089] \
+ ] {
+
+ bench -desc "AES-${len} ECB encryption" -body {
+ aes::aes -mode ecb -dir enc -key $k -iv $i $p
+ }
+
+ bench -desc "AES-${len} ECB decryption" -body {
+ aes::aes -mode ecb -dir dec -key $k -iv $i $c
+ }
+
+ bench -desc "AES-${len} ECB encryption core" -pre {
+ set key [aes::Init ecb $k $i]
+ } -body {
+ aes::Encrypt $key $p
+ } -post {
+ aes::Final $key
+ }
+
+ bench -desc "AES-${len} ECB decryption core" -pre {
+ set key [aes::Init ecb $k $i]
+ } -body {
+ aes::Decrypt $key $c
+ } -post {
+ aes::Final $key
+ }
+
+ bench -desc "AES-${len} ECB keyschedule" -body {
+ aes::Final [aes::Init ecb $k $i]
+ }
+
+ bench -desc "AES-${len} CBC keyschedule" -body {
+ aes::Final [aes::Init cbc $k $i]
+ }
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Complete
diff --git a/tcllib/modules/aes/aes.man b/tcllib/modules/aes/aes.man
new file mode 100644
index 0000000..93a73c1
--- /dev/null
+++ b/tcllib/modules/aes/aes.man
@@ -0,0 +1,168 @@
+[comment {-*- tcl -*- doctools manpage}]
+[vset AES_VERSION 1.2.1]
+[manpage_begin aes n [vset AES_VERSION]]
+[see_also blowfish(n)]
+[see_also des(n)]
+[see_also md5(n)]
+[see_also sha1(n)]
+[keywords aes]
+[keywords {block cipher}]
+[keywords {data integrity}]
+[keywords encryption]
+[keywords security]
+[copyright {2005, Pat Thoyts <patthoyts@users.sourceforge.net>}]
+[copyright {2012-2014, Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[moddesc {Advanced Encryption Standard (AES)}]
+[titledesc {Implementation of the AES block cipher}]
+[category {Hashes, checksums, and encryption}]
+[require Tcl 8.5]
+[require aes [opt [vset AES_VERSION]]]
+[description]
+[para]
+
+This is an implementation in Tcl of the Advanced Encryption Standard
+(AES) as published by the U.S. National Institute of Standards and
+Technology [lb]1[rb]. AES is a 128-bit block cipher with a variable
+key size of 128, 192 or 256 bits. This implementation supports ECB and
+CBC modes.
+
+[section {COMMANDS}]
+
+[list_begin definitions]
+
+[call [cmd "::aes::aes"] \
+ [opt [arg "-mode [lb]ecb|cbc[rb]"]] \
+ [opt [arg "-dir [lb]encrypt|decrypt[rb]"]] \
+ [arg "-key keydata"] \
+ [opt [arg "-iv vector"]] \
+ [opt [arg "-hex"]] \
+ [opt [arg "-out channel"]] \
+ [opt [arg "-chunksize size"]] \
+ [lb] [arg "-in channel"] | \
+ [opt [option --]] [arg "data"] [rb]]
+
+Perform the [package aes] algorithm on either the data provided
+by the argument or on the data read from the [arg "-in"] channel. If
+an [arg "-out"] channel is given then the result will be written to
+this channel.
+
+[para]
+
+The [arg -key] option must be given. This parameter takes a binary
+string of either 16, 24 or 32 bytes in length and is used to generate the
+key schedule.
+
+[para]
+
+The [arg -mode] and [arg -dir] options are optional and default to cbc
+mode and encrypt respectively. The initialization vector [arg -iv]
+takes a 16 byte binary argument which defaults to all zeros.
+See [sectref "MODES OF OPERATION"] for more about available modes and
+their uses.
+
+[para]
+
+AES is a 128-bit block cipher. This means that the data must be
+provided in units that are a multiple of 16 bytes.
+
+[list_end]
+
+[section "PROGRAMMING INTERFACE"]
+
+Internal state is maintained in an opaque structure that is returned
+from the [cmd Init] function. In ECB mode the state is not affected by
+the input but for CBC mode some input dependent state is maintained
+and may be reset by calling the [cmd Reset] function with a new
+initialization vector value.
+
+[list_begin definitions]
+
+[call [cmd "::aes::Init"] [arg "mode"] [arg "keydata"] [arg "iv"]]
+
+Construct a new AES key schedule using the specified key data and the
+given initialization vector. The initialization vector is not used
+with ECB mode but is important for CBC mode.
+See [sectref "MODES OF OPERATION"] for details about cipher modes.
+
+[call [cmd "::aes::Encrypt"] [arg "Key"] [arg "data"]]
+
+Use a prepared key acquired by calling [cmd Init] to encrypt the
+provided data. The data argument should be a binary array that is a
+multiple of the AES block size of 16 bytes. The result is a binary
+array the same size as the input of encrypted data.
+
+[call [cmd "::aes::Decrypt"] [arg "Key"] [arg "data"]]
+
+Decipher data using the key. Note that the same key may be used to
+encrypt and decrypt data provided that the initialization vector is
+reset appropriately for CBC mode.
+
+[call [cmd "::aes::Reset"] [arg "Key"] [arg "iv"]]
+
+Reset the initialization vector. This permits the programmer to re-use
+a key and avoid the cost of re-generating the key schedule where the
+same key data is being used multiple times.
+
+[call [cmd "::aes::Final"] [arg "Key"]]
+
+This should be called to clean up resources associated with [arg Key].
+Once this function has been called the key may not be used again.
+
+[list_end]
+
+[section "MODES OF OPERATION"]
+
+[list_begin definitions]
+
+[def "Electronic Code Book (ECB)"]
+ECB is the basic mode of all block ciphers. Each block is encrypted
+independently and so identical plain text will produce identical
+output when encrypted with the same key. Any encryption errors will
+only affect a single block however this is vulnerable to known
+plaintext attacks.
+
+[def "Cipher Block Chaining (CBC)"]
+
+CBC mode uses the output of the last block encryption to affect the
+current block. An initialization vector of the same size as the cipher
+block size is used to handle the first block. The initialization
+vector should be chosen randomly and transmitted as the first block of
+the output. Errors in encryption affect the current block and the next
+block after which the cipher will correct itself. CBC is the most
+commonly used mode in software encryption. This is the default mode
+of operation for this module.
+
+[list_end]
+
+[section "EXAMPLES"]
+
+[example {
+% set nil_block [string repeat \\0 16]
+% aes::aes -hex -mode cbc -dir encrypt -key $nil_block $nil_block
+66e94bd4ef8a2c3b884cfa59ca342b2e
+}]
+
+[example {
+set Key [aes::Init cbc $sixteen_bytes_key_data $sixteen_byte_iv]
+append ciphertext [aes::Encrypt $Key $plaintext]
+append ciphertext [aes::Encrypt $Key $additional_plaintext]
+aes::Final $Key
+}]
+
+[section "REFERENCES"]
+
+[list_begin enumerated]
+
+[enum]
+ "Advanced Encryption Standard",
+ Federal Information Processing Standards Publication 197, 2001
+ ([uri http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf])
+
+[list_end]
+
+[section AUTHORS]
+Thorsten Schloermann, Pat Thoyts
+
+[vset CATEGORY aes]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/aes/aes.pcx b/tcllib/modules/aes/aes.pcx
new file mode 100644
index 0000000..75031f4
--- /dev/null
+++ b/tcllib/modules/aes/aes.pcx
@@ -0,0 +1,99 @@
+# -*- tcl -*- aes.pcx
+# Syntax of the commands provided by package aes.
+#
+# For use by TclDevKit's static syntax checker (v4.1+).
+# See http://www.activestate.com/solutions/tcl/
+# See http://aspn.activestate.com/ASPN/docs/Tcl_Dev_Kit/4.0/Checker.html#pcx_api
+# for the specification of the format of the code in this file.
+#
+
+package require pcx
+pcx::register aes
+pcx::tcldep 1.0.0 needs tcl 8.2
+
+namespace eval ::aes {}
+
+# Using the indirections below looks to be quite pointless, given that
+# they simply substitute the commands for others. I am doing this for
+# two reasons.
+
+# First, the rules coming after become self-commenting, i.e. a
+# maintainer can immediately see what an argument is supposed to be,
+# instead of having to search elsewhere (like the documentation and
+# implementation). In this manner our definitions here are a type of
+# semantic markup.
+
+# The second reason is alluded to as well in the comments to the first
+# three definitions. While we have no special checks now we cannot be
+# sure if such will (have to) be added in the future. With all
+# checking routed through our definitions we now already have the
+# basic infrastructure (i.e. hooks) in place in which we can easily
+# add any new checks by simply redefining the relevant command, and
+# all the rules update on their own. Mostly. This should cover 90% of
+# the cases. Sometimes new checks will require to create deeper
+# distinctions between different calls of the same thing. For such we
+# may have to update the rules as well, to provide the necessary
+# information to the checker.
+
+interp alias {} aes::checkAesKey {} checkWord ; # Consider redefinition to check literals
+interp alias {} aes::checkAesData {} checkWord ; # for the proper size.
+interp alias {} aes::checkAesIV {} checkWord ; #
+interp alias {} aes::checkAesMode {} checkKeyword 1 {ecb cbc}
+interp alias {} aes::checkAesAction {} checkKeyword 1 {encrypt decrypt}
+
+#pcx::message FOO {... text ...} type
+pcx::message needKey {Required -key is missing} err
+#pcx::scan <VERSION> <NAME> <RULE>
+
+pcx::check 1.0.0 std ::aes::Decrypt \
+ {checkSimpleArgs 2 2 {
+ aes::checkAesKey
+ aes::checkAesData
+ }}
+pcx::check 1.0.0 std ::aes::Encrypt \
+ {checkSimpleArgs 2 2 {
+ aes::checkAesKey
+ aes::checkAesData
+ }}
+pcx::check 1.0.0 std ::aes::Final \
+ {checkSimpleArgs 1 1 {
+ aes::checkAesKey
+ }}
+pcx::check 1.0.0 std ::aes::Init \
+ {checkSimpleArgs 3 3 {
+ aes::checkAesMode
+ aes::checkAesKey
+ aes::checkAesIV
+ }}
+pcx::check 1.0.0 std ::aes::Reset \
+ {checkSimpleArgs 2 2 {
+ aes::checkAesKey
+ aes::checkAesIV
+ }}
+pcx::check 1.0.0 std ::aes::aes \
+ {checkConstrained {checkSimpleArgs 1 -1 {
+ {checkSwitches 1 {
+ {-mode aes::checkAesMode}
+ {-dir aes::checkAesAction}
+ {-key {checkSetConstraint haskey aes::checkAesKey}}
+ {-iv aes::checkAesIV}
+ {-hex}
+ {-out checkChannelID}
+ {-chunksize checkWholeNum}
+ {-in {checkSetConstraint hasin checkChannelID}}
+ } {checkConstraint {
+ {{!haskey && hasin} {warn aes::needKey {} {
+ checkAtEnd
+ }}}
+ {hasin checkAtEnd}
+ {{!haskey} {warn aes::needKey {} {checkSimpleArgs 1 1 {
+ aes::checkAesData
+ }}}}
+ } {checkSimpleArgs 1 1 {
+ aes::checkAesData
+ }}}}
+ }}}
+
+# Initialization via pcx::init.
+# Use a ::aes::init procedure for non-standard initialization.
+pcx::complete
diff --git a/tcllib/modules/aes/aes.tcl b/tcllib/modules/aes/aes.tcl
new file mode 100644
index 0000000..6a1849b
--- /dev/null
+++ b/tcllib/modules/aes/aes.tcl
@@ -0,0 +1,625 @@
+# aes.tcl -
+#
+# Copyright (c) 2005 Thorsten Schloermann
+# Copyright (c) 2005 Pat Thoyts <patthoyts@users.sourceforge.net>
+# Copyright (c) 2013 Andreas Kupries
+#
+# A Tcl implementation of the Advanced Encryption Standard (US FIPS PUB 197)
+#
+# AES is a block cipher with a block size of 128 bits and a variable
+# key size of 128, 192 or 256 bits.
+# The algorithm works on each block as a 4x4 state array. There are 4 steps
+# in each round:
+# SubBytes a non-linear substitution step using a predefined S-box
+# ShiftRows cyclic transposition of rows in the state matrix
+# MixColumns transformation upon columns in the state matrix
+# AddRoundKey application of round specific sub-key
+#
+# -------------------------------------------------------------------------
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# -------------------------------------------------------------------------
+
+package require Tcl 8.5
+
+namespace eval ::aes {
+ variable uid
+ if {![info exists uid]} { set uid 0 }
+
+ namespace export aes
+
+ # constants
+
+ # S-box
+ variable sbox {
+ 0x63 0x7c 0x77 0x7b 0xf2 0x6b 0x6f 0xc5 0x30 0x01 0x67 0x2b 0xfe 0xd7 0xab 0x76
+ 0xca 0x82 0xc9 0x7d 0xfa 0x59 0x47 0xf0 0xad 0xd4 0xa2 0xaf 0x9c 0xa4 0x72 0xc0
+ 0xb7 0xfd 0x93 0x26 0x36 0x3f 0xf7 0xcc 0x34 0xa5 0xe5 0xf1 0x71 0xd8 0x31 0x15
+ 0x04 0xc7 0x23 0xc3 0x18 0x96 0x05 0x9a 0x07 0x12 0x80 0xe2 0xeb 0x27 0xb2 0x75
+ 0x09 0x83 0x2c 0x1a 0x1b 0x6e 0x5a 0xa0 0x52 0x3b 0xd6 0xb3 0x29 0xe3 0x2f 0x84
+ 0x53 0xd1 0x00 0xed 0x20 0xfc 0xb1 0x5b 0x6a 0xcb 0xbe 0x39 0x4a 0x4c 0x58 0xcf
+ 0xd0 0xef 0xaa 0xfb 0x43 0x4d 0x33 0x85 0x45 0xf9 0x02 0x7f 0x50 0x3c 0x9f 0xa8
+ 0x51 0xa3 0x40 0x8f 0x92 0x9d 0x38 0xf5 0xbc 0xb6 0xda 0x21 0x10 0xff 0xf3 0xd2
+ 0xcd 0x0c 0x13 0xec 0x5f 0x97 0x44 0x17 0xc4 0xa7 0x7e 0x3d 0x64 0x5d 0x19 0x73
+ 0x60 0x81 0x4f 0xdc 0x22 0x2a 0x90 0x88 0x46 0xee 0xb8 0x14 0xde 0x5e 0x0b 0xdb
+ 0xe0 0x32 0x3a 0x0a 0x49 0x06 0x24 0x5c 0xc2 0xd3 0xac 0x62 0x91 0x95 0xe4 0x79
+ 0xe7 0xc8 0x37 0x6d 0x8d 0xd5 0x4e 0xa9 0x6c 0x56 0xf4 0xea 0x65 0x7a 0xae 0x08
+ 0xba 0x78 0x25 0x2e 0x1c 0xa6 0xb4 0xc6 0xe8 0xdd 0x74 0x1f 0x4b 0xbd 0x8b 0x8a
+ 0x70 0x3e 0xb5 0x66 0x48 0x03 0xf6 0x0e 0x61 0x35 0x57 0xb9 0x86 0xc1 0x1d 0x9e
+ 0xe1 0xf8 0x98 0x11 0x69 0xd9 0x8e 0x94 0x9b 0x1e 0x87 0xe9 0xce 0x55 0x28 0xdf
+ 0x8c 0xa1 0x89 0x0d 0xbf 0xe6 0x42 0x68 0x41 0x99 0x2d 0x0f 0xb0 0x54 0xbb 0x16
+ }
+ # inverse S-box
+ variable xobs {
+ 0x52 0x09 0x6a 0xd5 0x30 0x36 0xa5 0x38 0xbf 0x40 0xa3 0x9e 0x81 0xf3 0xd7 0xfb
+ 0x7c 0xe3 0x39 0x82 0x9b 0x2f 0xff 0x87 0x34 0x8e 0x43 0x44 0xc4 0xde 0xe9 0xcb
+ 0x54 0x7b 0x94 0x32 0xa6 0xc2 0x23 0x3d 0xee 0x4c 0x95 0x0b 0x42 0xfa 0xc3 0x4e
+ 0x08 0x2e 0xa1 0x66 0x28 0xd9 0x24 0xb2 0x76 0x5b 0xa2 0x49 0x6d 0x8b 0xd1 0x25
+ 0x72 0xf8 0xf6 0x64 0x86 0x68 0x98 0x16 0xd4 0xa4 0x5c 0xcc 0x5d 0x65 0xb6 0x92
+ 0x6c 0x70 0x48 0x50 0xfd 0xed 0xb9 0xda 0x5e 0x15 0x46 0x57 0xa7 0x8d 0x9d 0x84
+ 0x90 0xd8 0xab 0x00 0x8c 0xbc 0xd3 0x0a 0xf7 0xe4 0x58 0x05 0xb8 0xb3 0x45 0x06
+ 0xd0 0x2c 0x1e 0x8f 0xca 0x3f 0x0f 0x02 0xc1 0xaf 0xbd 0x03 0x01 0x13 0x8a 0x6b
+ 0x3a 0x91 0x11 0x41 0x4f 0x67 0xdc 0xea 0x97 0xf2 0xcf 0xce 0xf0 0xb4 0xe6 0x73
+ 0x96 0xac 0x74 0x22 0xe7 0xad 0x35 0x85 0xe2 0xf9 0x37 0xe8 0x1c 0x75 0xdf 0x6e
+ 0x47 0xf1 0x1a 0x71 0x1d 0x29 0xc5 0x89 0x6f 0xb7 0x62 0x0e 0xaa 0x18 0xbe 0x1b
+ 0xfc 0x56 0x3e 0x4b 0xc6 0xd2 0x79 0x20 0x9a 0xdb 0xc0 0xfe 0x78 0xcd 0x5a 0xf4
+ 0x1f 0xdd 0xa8 0x33 0x88 0x07 0xc7 0x31 0xb1 0x12 0x10 0x59 0x27 0x80 0xec 0x5f
+ 0x60 0x51 0x7f 0xa9 0x19 0xb5 0x4a 0x0d 0x2d 0xe5 0x7a 0x9f 0x93 0xc9 0x9c 0xef
+ 0xa0 0xe0 0x3b 0x4d 0xae 0x2a 0xf5 0xb0 0xc8 0xeb 0xbb 0x3c 0x83 0x53 0x99 0x61
+ 0x17 0x2b 0x04 0x7e 0xba 0x77 0xd6 0x26 0xe1 0x69 0x14 0x63 0x55 0x21 0x0c 0x7d
+ }
+}
+
+# aes::Init --
+#
+# Initialise our AES state and calculate the key schedule. An initialization
+# vector is maintained in the state for modes that require one. The key must
+# be binary data of the correct size and the IV must be 16 bytes.
+#
+# Nk: columns of the key-array
+# Nr: number of rounds (depends on key-length)
+# Nb: columns of the text-block, is always 4 in AES
+#
+proc ::aes::Init {mode key iv} {
+ switch -exact -- $mode {
+ ecb - cbc { }
+ cfb - ofb {
+ return -code error "$mode mode not implemented"
+ }
+ default {
+ return -code error "invalid mode \"$mode\":\
+ must be one of ecb or cbc."
+ }
+ }
+
+ set size [expr {[string length $key] << 3}]
+ switch -exact -- $size {
+ 128 {set Nk 4; set Nr 10; set Nb 4}
+ 192 {set Nk 6; set Nr 12; set Nb 4}
+ 256 {set Nk 8; set Nr 14; set Nb 4}
+ default {
+ return -code error "invalid key size \"$size\":\
+ must be one of 128, 192 or 256."
+ }
+ }
+
+ variable uid
+ set Key [namespace current]::[incr uid]
+ upvar #0 $Key state
+ if {[binary scan $iv Iu4 state(I)] != 1} {
+ return -code error "invalid initialization vector: must be 16 bytes"
+ }
+ array set state [list M $mode K $key Nk $Nk Nr $Nr Nb $Nb W {}]
+ ExpandKey $Key
+ return $Key
+}
+
+# aes::Reset --
+#
+# Reset the initialization vector for the specified key. This permits the
+# key to be reused for encryption or decryption without the expense of
+# re-calculating the key schedule.
+#
+proc ::aes::Reset {Key iv} {
+ upvar #0 $Key state
+ if {[binary scan $iv Iu4 state(I)] != 1} {
+ return -code error "invalid initialization vector: must be 16 bytes"
+ }
+ return
+}
+
+# aes::Final --
+#
+# Clean up the key state
+#
+proc ::aes::Final {Key} {
+ # FRINK: nocheck
+ unset $Key
+}
+
+# -------------------------------------------------------------------------
+
+# 5.1 Cipher: Encipher a single block of 128 bits.
+proc ::aes::EncryptBlock {Key block} {
+ upvar #0 $Key state
+ if {[binary scan $block Iu4 data] != 1} {
+ return -code error "invalid block size: blocks must be 16 bytes"
+ }
+
+ if {$state(M) eq {cbc}} {
+ # Loop unrolled.
+ lassign $data d0 d1 d2 d3
+ lassign $state(I) s0 s1 s2 s3
+ set data [list \
+ [expr {$d0 ^ $s0}] \
+ [expr {$d1 ^ $s1}] \
+ [expr {$d2 ^ $s2}] \
+ [expr {$d3 ^ $s3}] ]
+ }
+
+ set data [AddRoundKey $Key 0 $data]
+ for {set n 1} {$n < $state(Nr)} {incr n} {
+ set data [AddRoundKey $Key $n [MixColumns [ShiftRows [SubBytes $data]]]]
+ }
+ set data [AddRoundKey $Key $n [ShiftRows [SubBytes $data]]]
+
+ # Bug 2993029:
+ # Force all elements of data into the 32bit range.
+ # Loop unrolled
+ set res [Clamp32 $data]
+
+ set state(I) $res
+ binary format Iu4 $res
+}
+
+# 5.3: Inverse Cipher: Decipher a single 128 bit block.
+proc ::aes::DecryptBlock {Key block} {
+ upvar #0 $Key state
+ if {[binary scan $block Iu4 data] != 1} {
+ return -code error "invalid block size: block must be 16 bytes"
+ }
+ set iv $data
+
+ set n $state(Nr)
+ set data [AddRoundKey $Key $state(Nr) $data]
+ for {incr n -1} {$n > 0} {incr n -1} {
+ set data [InvMixColumns [AddRoundKey $Key $n [InvSubBytes [InvShiftRows $data]]]]
+ }
+ set data [AddRoundKey $Key $n [InvSubBytes [InvShiftRows $data]]]
+
+ if {$state(M) eq {cbc}} {
+ lassign $data d0 d1 d2 d3
+ lassign $state(I) s0 s1 s2 s3
+ set data [list \
+ [expr {($d0 ^ $s0) & 0xffffffff}] \
+ [expr {($d1 ^ $s1) & 0xffffffff}] \
+ [expr {($d2 ^ $s2) & 0xffffffff}] \
+ [expr {($d3 ^ $s3) & 0xffffffff}] ]
+ } else {
+ # Bug 2993029:
+ # The integrated clamping we see above only happens for CBC mode.
+ set data [Clamp32 $data]
+ }
+
+ set state(I) $iv
+ binary format Iu4 $data
+}
+
+proc ::aes::Clamp32 {data} {
+ # Force all elements into 32bit range.
+ lassign $data d0 d1 d2 d3
+ list \
+ [expr {$d0 & 0xffffffff}] \
+ [expr {$d1 & 0xffffffff}] \
+ [expr {$d2 & 0xffffffff}] \
+ [expr {$d3 & 0xffffffff}]
+}
+
+# 5.2: KeyExpansion
+proc ::aes::ExpandKey {Key} {
+ upvar #0 $Key state
+ set Rcon [list 0x00000000 0x01000000 0x02000000 0x04000000 0x08000000 \
+ 0x10000000 0x20000000 0x40000000 0x80000000 0x1b000000 \
+ 0x36000000 0x6c000000 0xd8000000 0xab000000 0x4d000000]
+ # Split the key into Nk big-endian words
+ binary scan $state(K) I* W
+ set max [expr {$state(Nb) * ($state(Nr) + 1)}]
+ set i $state(Nk)
+ set h [expr {$i - 1}]
+ set j 0
+ for {} {$i < $max} {incr i; incr h; incr j} {
+ set temp [lindex $W $h]
+ if {($i % $state(Nk)) == 0} {
+ set sub [SubWord [RotWord $temp]]
+ set rc [lindex $Rcon [expr {$i/$state(Nk)}]]
+ set temp [expr {$sub ^ $rc}]
+ } elseif {$state(Nk) > 6 && ($i % $state(Nk)) == 4} {
+ set temp [SubWord $temp]
+ }
+ lappend W [expr {[lindex $W $j] ^ $temp}]
+ }
+ set state(W) $W
+}
+
+# 5.2: Key Expansion: Apply S-box to each byte in the 32 bit word
+proc ::aes::SubWord {w} {
+ variable sbox
+ set s3 [lindex $sbox [expr {($w >> 24) & 255}]]
+ set s2 [lindex $sbox [expr {($w >> 16) & 255}]]
+ set s1 [lindex $sbox [expr {($w >> 8 ) & 255}]]
+ set s0 [lindex $sbox [expr { $w & 255}]]
+ return [expr {($s3 << 24) | ($s2 << 16) | ($s1 << 8) | $s0}]
+}
+
+proc ::aes::InvSubWord {w} {
+ variable xobs
+ set s3 [lindex $xobs [expr {($w >> 24) & 255}]]
+ set s2 [lindex $xobs [expr {($w >> 16) & 255}]]
+ set s1 [lindex $xobs [expr {($w >> 8 ) & 255}]]
+ set s0 [lindex $xobs [expr { $w & 255}]]
+ return [expr {($s3 << 24) | ($s2 << 16) | ($s1 << 8) | $s0}]
+}
+
+# 5.2: Key Expansion: Rotate a 32bit word by 8 bits
+proc ::aes::RotWord {w} {
+ return [expr {(($w << 8) | (($w >> 24) & 0xff)) & 0xffffffff}]
+}
+
+# 5.1.1: SubBytes() Transformation
+proc ::aes::SubBytes {words} {
+ lassign $words w0 w1 w2 w3
+ list [SubWord $w0] [SubWord $w1] [SubWord $w2] [SubWord $w3]
+}
+
+# 5.3.2: InvSubBytes() Transformation
+proc ::aes::InvSubBytes {words} {
+ lassign $words w0 w1 w2 w3
+ list [InvSubWord $w0] [InvSubWord $w1] [InvSubWord $w2] [InvSubWord $w3]
+}
+
+# 5.1.2: ShiftRows() Transformation
+proc ::aes::ShiftRows {words} {
+ for {set n0 0} {$n0 < 4} {incr n0} {
+ set n1 [expr {($n0 + 1) % 4}]
+ set n2 [expr {($n0 + 2) % 4}]
+ set n3 [expr {($n0 + 3) % 4}]
+ lappend r [expr {( [lindex $words $n0] & 0xff000000)
+ | ([lindex $words $n1] & 0x00ff0000)
+ | ([lindex $words $n2] & 0x0000ff00)
+ | ([lindex $words $n3] & 0x000000ff)
+ }]
+ }
+ return $r
+}
+
+
+# 5.3.1: InvShiftRows() Transformation
+proc ::aes::InvShiftRows {words} {
+ for {set n0 0} {$n0 < 4} {incr n0} {
+ set n1 [expr {($n0 + 1) % 4}]
+ set n2 [expr {($n0 + 2) % 4}]
+ set n3 [expr {($n0 + 3) % 4}]
+ lappend r [expr {( [lindex $words $n0] & 0xff000000)
+ | ([lindex $words $n3] & 0x00ff0000)
+ | ([lindex $words $n2] & 0x0000ff00)
+ | ([lindex $words $n1] & 0x000000ff)
+ }]
+ }
+ return $r
+}
+
+# 5.1.3: MixColumns() Transformation
+proc ::aes::MixColumns {words} {
+ set r {}
+ foreach w $words {
+ set r0 [expr {(($w >> 24) & 255)}]
+ set r1 [expr {(($w >> 16) & 255)}]
+ set r2 [expr {(($w >> 8 ) & 255)}]
+ set r3 [expr {( $w & 255)}]
+
+ set s0 [expr {[GFMult2 $r0] ^ [GFMult3 $r1] ^ $r2 ^ $r3}]
+ set s1 [expr {$r0 ^ [GFMult2 $r1] ^ [GFMult3 $r2] ^ $r3}]
+ set s2 [expr {$r0 ^ $r1 ^ [GFMult2 $r2] ^ [GFMult3 $r3]}]
+ set s3 [expr {[GFMult3 $r0] ^ $r1 ^ $r2 ^ [GFMult2 $r3]}]
+
+ lappend r [expr {($s0 << 24) | ($s1 << 16) | ($s2 << 8) | $s3}]
+ }
+ return $r
+}
+
+# 5.3.3: InvMixColumns() Transformation
+proc ::aes::InvMixColumns {words} {
+ set r {}
+ foreach w $words {
+ set r0 [expr {(($w >> 24) & 255)}]
+ set r1 [expr {(($w >> 16) & 255)}]
+ set r2 [expr {(($w >> 8 ) & 255)}]
+ set r3 [expr {( $w & 255)}]
+
+ set s0 [expr {[GFMult0e $r0] ^ [GFMult0b $r1] ^ [GFMult0d $r2] ^ [GFMult09 $r3]}]
+ set s1 [expr {[GFMult09 $r0] ^ [GFMult0e $r1] ^ [GFMult0b $r2] ^ [GFMult0d $r3]}]
+ set s2 [expr {[GFMult0d $r0] ^ [GFMult09 $r1] ^ [GFMult0e $r2] ^ [GFMult0b $r3]}]
+ set s3 [expr {[GFMult0b $r0] ^ [GFMult0d $r1] ^ [GFMult09 $r2] ^ [GFMult0e $r3]}]
+
+ lappend r [expr {($s0 << 24) | ($s1 << 16) | ($s2 << 8) | $s3}]
+ }
+ return $r
+}
+
+# 5.1.4: AddRoundKey() Transformation
+proc ::aes::AddRoundKey {Key round words} {
+ upvar #0 $Key state
+ set r {}
+ set n [expr {$round * $state(Nb)}]
+ foreach w $words {
+ lappend r [expr {$w ^ [lindex $state(W) $n]}]
+ incr n
+ }
+ return $r
+}
+
+# -------------------------------------------------------------------------
+# ::aes::GFMult*
+#
+# some needed functions for multiplication in a Galois-field
+#
+proc ::aes::GFMult2 {number} {
+ # this is a tabular representation of xtime (multiplication by 2)
+ # it is used instead of calculation to prevent timing attacks
+ set xtime {
+ 0x00 0x02 0x04 0x06 0x08 0x0a 0x0c 0x0e 0x10 0x12 0x14 0x16 0x18 0x1a 0x1c 0x1e
+ 0x20 0x22 0x24 0x26 0x28 0x2a 0x2c 0x2e 0x30 0x32 0x34 0x36 0x38 0x3a 0x3c 0x3e
+ 0x40 0x42 0x44 0x46 0x48 0x4a 0x4c 0x4e 0x50 0x52 0x54 0x56 0x58 0x5a 0x5c 0x5e
+ 0x60 0x62 0x64 0x66 0x68 0x6a 0x6c 0x6e 0x70 0x72 0x74 0x76 0x78 0x7a 0x7c 0x7e
+ 0x80 0x82 0x84 0x86 0x88 0x8a 0x8c 0x8e 0x90 0x92 0x94 0x96 0x98 0x9a 0x9c 0x9e
+ 0xa0 0xa2 0xa4 0xa6 0xa8 0xaa 0xac 0xae 0xb0 0xb2 0xb4 0xb6 0xb8 0xba 0xbc 0xbe
+ 0xc0 0xc2 0xc4 0xc6 0xc8 0xca 0xcc 0xce 0xd0 0xd2 0xd4 0xd6 0xd8 0xda 0xdc 0xde
+ 0xe0 0xe2 0xe4 0xe6 0xe8 0xea 0xec 0xee 0xf0 0xf2 0xf4 0xf6 0xf8 0xfa 0xfc 0xfe
+ 0x1b 0x19 0x1f 0x1d 0x13 0x11 0x17 0x15 0x0b 0x09 0x0f 0x0d 0x03 0x01 0x07 0x05
+ 0x3b 0x39 0x3f 0x3d 0x33 0x31 0x37 0x35 0x2b 0x29 0x2f 0x2d 0x23 0x21 0x27 0x25
+ 0x5b 0x59 0x5f 0x5d 0x53 0x51 0x57 0x55 0x4b 0x49 0x4f 0x4d 0x43 0x41 0x47 0x45
+ 0x7b 0x79 0x7f 0x7d 0x73 0x71 0x77 0x75 0x6b 0x69 0x6f 0x6d 0x63 0x61 0x67 0x65
+ 0x9b 0x99 0x9f 0x9d 0x93 0x91 0x97 0x95 0x8b 0x89 0x8f 0x8d 0x83 0x81 0x87 0x85
+ 0xbb 0xb9 0xbf 0xbd 0xb3 0xb1 0xb7 0xb5 0xab 0xa9 0xaf 0xad 0xa3 0xa1 0xa7 0xa5
+ 0xdb 0xd9 0xdf 0xdd 0xd3 0xd1 0xd7 0xd5 0xcb 0xc9 0xcf 0xcd 0xc3 0xc1 0xc7 0xc5
+ 0xfb 0xf9 0xff 0xfd 0xf3 0xf1 0xf7 0xf5 0xeb 0xe9 0xef 0xed 0xe3 0xe1 0xe7 0xe5
+ }
+ lindex $xtime $number
+}
+
+proc ::aes::GFMult3 {number} {
+ # multliply by 2 (via GFMult2) and add the number again on the result (via XOR)
+ expr {$number ^ [GFMult2 $number]}
+}
+
+proc ::aes::GFMult09 {number} {
+ # 09 is: (02*02*02) + 01
+ expr {[GFMult2 [GFMult2 [GFMult2 $number]]] ^ $number}
+}
+
+proc ::aes::GFMult0b {number} {
+ # 0b is: (02*02*02) + 02 + 01
+ #return [expr [GFMult2 [GFMult2 [GFMult2 $number]]] ^ [GFMult2 $number] ^ $number]
+ #set g0 [GFMult2 $number]
+ expr {[GFMult09 $number] ^ [GFMult2 $number]}
+}
+
+proc ::aes::GFMult0d {number} {
+ # 0d is: (02*02*02) + (02*02) + 01
+ set temp [GFMult2 [GFMult2 $number]]
+ expr {[GFMult2 $temp] ^ ($temp ^ $number)}
+}
+
+proc ::aes::GFMult0e {number} {
+ # 0e is: (02*02*02) + (02*02) + 02
+ set temp [GFMult2 [GFMult2 $number]]
+ expr {[GFMult2 $temp] ^ ($temp ^ [GFMult2 $number])}
+}
+
+# -------------------------------------------------------------------------
+
+# aes::Encrypt --
+#
+# Encrypt a blocks of plain text and returns blocks of cipher text.
+# The input data must be a multiple of the block size (16).
+#
+proc ::aes::Encrypt {Key data} {
+ set len [string length $data]
+ if {($len % 16) != 0} {
+ return -code error "invalid block size: AES requires 16 byte blocks"
+ }
+
+ set result {}
+ for {set i 0} {$i < $len} {incr i 1} {
+ set block [string range $data $i [incr i 15]]
+ append result [EncryptBlock $Key $block]
+ }
+ return $result
+}
+
+# aes::Decrypt --
+#
+# Decrypt blocks of cipher text and returns blocks of plain text.
+# The input data must be a multiple of the block size (16).
+#
+proc ::aes::Decrypt {Key data} {
+ set len [string length $data]
+ if {($len % 16) != 0} {
+ return -code error "invalid block size: AES requires 16 byte blocks"
+ }
+
+ set result {}
+ for {set i 0} {$i < $len} {incr i 1} {
+ set block [string range $data $i [incr i 15]]
+ append result [DecryptBlock $Key $block]
+ }
+ return $result
+}
+
+# -------------------------------------------------------------------------
+# chan event handler for chunked file reading.
+#
+proc ::aes::Chunk {Key in {out {}} {chunksize 4096}} {
+ upvar #0 $Key state
+
+ #puts ||CHUNK.X||i=$in|o=$out|c=$chunksize|eof=[eof $in]
+
+ if {[eof $in]} {
+ chan event $in readable {}
+ set state(reading) 0
+ }
+
+ set data [read $in $chunksize]
+
+ #puts ||CHUNK.R||i=$in|o=$out|c=$chunksize|eof=[eof $in]||[string length $data]||$data||
+
+ # Do nothing when data was read at all.
+ if {$data eq {}} return
+
+ if {[eof $in]} {
+ #puts CHUNK.Z
+ set data [Pad $data 16]
+ }
+
+ #puts ||CHUNK.P||i=$in|o=$out|c=$chunksize|eof=[eof $in]||[string length $data]||$data||
+
+ if {$out eq {}} {
+ append state(output) [$state(cmd) $Key $data]
+ } else {
+ puts -nonewline $out [$state(cmd) $Key $data]
+ }
+}
+
+proc ::aes::SetOneOf {lst item} {
+ set ndx [lsearch -glob $lst "${item}*"]
+ if {$ndx == -1} {
+ set err [join $lst ", "]
+ return -code error "invalid mode \"$item\": must be one of $err"
+ }
+ lindex $lst $ndx
+}
+
+proc ::aes::CheckSize {what size thing} {
+ if {[string length $thing] != $size} {
+ return -code error "invalid value for $what: must be $size bytes long"
+ }
+ return $thing
+}
+
+proc ::aes::Pad {data blocksize {fill \0}} {
+ set len [string length $data]
+ if {$len == 0} {
+ set data [string repeat $fill $blocksize]
+ } elseif {($len % $blocksize) != 0} {
+ set pad [expr {$blocksize - ($len % $blocksize)}]
+ append data [string repeat $fill $pad]
+ }
+ return $data
+}
+
+proc ::aes::Pop {varname {nth 0}} {
+ upvar 1 $varname args
+ set r [lindex $args $nth]
+ set args [lreplace $args $nth $nth]
+ return $r
+}
+
+proc ::aes::aes {args} {
+ array set opts {-dir encrypt -mode cbc -key {} -in {} -out {} -chunksize 4096 -hex 0}
+ set opts(-iv) [string repeat \0 16]
+ set modes {ecb cbc}
+ set dirs {encrypt decrypt}
+ while {([llength $args] > 1) && [string match -* [set option [lindex $args 0]]]} {
+ switch -exact -- $option {
+ -mode { set opts(-mode) [SetOneOf $modes [Pop args 1]] }
+ -dir { set opts(-dir) [SetOneOf $dirs [Pop args 1]] }
+ -iv { set opts(-iv) [CheckSize -iv 16 [Pop args 1]] }
+ -key { set opts(-key) [Pop args 1] }
+ -in { set opts(-in) [Pop args 1] }
+ -out { set opts(-out) [Pop args 1] }
+ -chunksize { set opts(-chunksize) [Pop args 1] }
+ -hex { set opts(-hex) 1 }
+ -- { Pop args ; break }
+ default {
+ set err [join [lsort [array names opts]] ", "]
+ return -code error "bad option \"$option\":\
+ must be one of $err"
+ }
+ }
+ Pop args
+ }
+
+ if {$opts(-key) eq {}} {
+ return -code error "no key provided: the -key option is required"
+ }
+
+ set r {}
+ if {$opts(-in) eq {}} {
+
+ if {[llength $args] != 1} {
+ return -code error "wrong \# args:\
+ should be \"aes ?options...? -key keydata plaintext\""
+ }
+
+ set data [Pad [lindex $args 0] 16]
+ set Key [Init $opts(-mode) $opts(-key) $opts(-iv)]
+ if {[string equal $opts(-dir) "encrypt"]} {
+ set r [Encrypt $Key $data]
+ } else {
+ set r [Decrypt $Key $data]
+ }
+
+ if {$opts(-out) ne {}} {
+ puts -nonewline $opts(-out) $r
+ set r {}
+ }
+ Final $Key
+
+ } else {
+
+ if {[llength $args] != 0} {
+ return -code error "wrong \# args:\
+ should be \"aes ?options...? -key keydata -in channel\""
+ }
+
+ set Key [Init $opts(-mode) $opts(-key) $opts(-iv)]
+
+ set readcmd [list [namespace origin Chunk] \
+ $Key $opts(-in) $opts(-out) \
+ $opts(-chunksize)]
+
+ upvar 1 $Key state
+ set state(reading) 1
+ if {[string equal $opts(-dir) "encrypt"]} {
+ set state(cmd) Encrypt
+ } else {
+ set state(cmd) Decrypt
+ }
+ set state(output) ""
+ chan event $opts(-in) readable $readcmd
+ if {[info commands ::tkwait] != {}} {
+ tkwait variable [subst $Key](reading)
+ } else {
+ vwait [subst $Key](reading)
+ }
+ if {$opts(-out) == {}} {
+ set r $state(output)
+ }
+ Final $Key
+ }
+
+ if {$opts(-hex)} {
+ binary scan $r H* r
+ }
+ return $r
+}
+
+# -------------------------------------------------------------------------
+
+package provide aes 1.2.1
+
+# -------------------------------------------------------------------------
+# Local variables:
+# mode: tcl
+# indent-tabs-mode: nil
+# End:
diff --git a/tcllib/modules/aes/aes.test b/tcllib/modules/aes/aes.test
new file mode 100644
index 0000000..c7305ef
--- /dev/null
+++ b/tcllib/modules/aes/aes.test
@@ -0,0 +1,358 @@
+# aes.test - Copyright (c) 2005 Thorsten Schloermann
+#
+# the test-values are taken from:
+# http://csrc.nist.gov/CryptoToolkit/aes/rijndael/rijndael-vals.zip
+# where only the first 12 entries of Know Answer Test for variable key and
+# variable text are used
+# Unfortunately, only encryption is tested by this.
+#
+#
+# Monte Carlo Tests with 4 Million cycles through the algorithm will need too much time
+#
+# $Id: aes.test,v 1.8 2010/07/06 19:39:00 andreas_kupries Exp $
+
+# -------------------------------------------------------------------------
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+testsNeedTcl 8.5
+testsNeedTcltest 2
+
+testing {
+ useLocal aes.tcl aes
+}
+
+# -------------------------------------------------------------------------
+
+# data for variable key KAT
+
+# Sample vectors from FIPS 197 specification document.
+#
+test aes-fips-C.1e {Test vector for AES-128 from FIPS-197 Appendix C.1} -setup {
+ set txt [binary format H* 00112233445566778899aabbccddeeff]
+ set key [binary format H* 000102030405060708090a0b0c0d0e0f]
+} -body {
+ set enc [aes::aes -mode ecb -dir enc -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 69c4e0d86a7b0430d8cdb78070b4c55a
+
+test aes-fips-C.1d {Test vector for AES-128 from FIPS-197 Appendix C.1} -setup {
+ set txt [binary format H* 69c4e0d86a7b0430d8cdb78070b4c55a]
+ set key [binary format H* 000102030405060708090a0b0c0d0e0f]
+} -body {
+ set enc [aes::aes -mode ecb -dir dec -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 00112233445566778899aabbccddeeff
+
+test aes-fips-C.2e {Test vector for AES-192 from FIPS-197 Appendix C.2} -setup {
+ set txt [binary format H* 00112233445566778899aabbccddeeff]
+ set key [binary format H* 000102030405060708090a0b0c0d0e0f1011121314151617]
+} -body {
+ set enc [aes::aes -mode ecb -dir enc -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result dda97ca4864cdfe06eaf70a0ec0d7191
+
+test aes-fips-C.2d {Test vector for AES-192 from FIPS-197 Appendix C.2} -setup {
+ set txt [binary format H* dda97ca4864cdfe06eaf70a0ec0d7191]
+ set key [binary format H* 000102030405060708090a0b0c0d0e0f1011121314151617]
+} -body {
+ set enc [aes::aes -mode ecb -dir dec -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 00112233445566778899aabbccddeeff
+
+test aes-fips-C.3e {Test vector for AES-256 from FIPS-197 Appendix C.3} -setup {
+ set txt [binary format H* 00112233445566778899aabbccddeeff]
+ set key [binary format H* 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f]
+} -body {
+ set enc [aes::aes -mode ecb -dir enc -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 8ea2b7ca516745bfeafc49904b496089
+
+test aes-fips-C.3d {Test vector for AES-256 from FIPS-197 Appendix C.3} -setup {
+ set txt [binary format H* 8ea2b7ca516745bfeafc49904b496089]
+ set key [binary format H* 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f]
+} -body {
+ set enc [aes::aes -mode ecb -dir dec -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 00112233445566778899aabbccddeeff
+
+test aes-kat-ecb-128e {Known answer tests - AES-128 ECB encryption} -setup {
+ set txt [binary format H* 000102030405060708090a0b0c0d0e0f]
+ set key [binary format H* 000102030405060708090a0b0c0d0e0f]
+} -body {
+ set enc [aes::aes -mode ecb -dir enc -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 0a940bb5416ef045f1c39458c653ea5a
+
+test aes-kat-ecb-128d {Known answer tests - AES-128 ECB decryption} -setup {
+ set txt [binary format H* 0a940bb5416ef045f1c39458c653ea5a]
+ set key [binary format H* 000102030405060708090a0b0c0d0e0f]
+} -body {
+ set enc [aes::aes -mode ecb -dir dec -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 000102030405060708090a0b0c0d0e0f
+
+test aes-kat-ecb-192e {Known answer tests - AES-192 ECB encryption} -setup {
+ set txt [binary format H* 000102030405060708090a0b0c0d0e0f]
+ set key [binary format H* 000102030405060708090A0B0C0D0E0F1011121314151617]
+} -body {
+ set enc [aes::aes -mode ecb -dir enc -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 0060bffe46834bb8da5cf9a61ff220ae
+
+test aes-kat-ecb-192d {Known answer tests - AES-192 ECB decryption} -setup {
+ set txt [binary format H* 0060bffe46834bb8da5cf9a61ff220ae]
+ set key [binary format H* 000102030405060708090A0B0C0D0E0F1011121314151617]
+} -body {
+ set enc [aes::aes -mode ecb -dir dec -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 000102030405060708090a0b0c0d0e0f
+
+test aes-kat-ecb-256e {Known answer tests - AES-256 ECB encryption} -setup {
+ set txt [binary format H* 000102030405060708090a0b0c0d0e0f]
+ set key [binary format H* 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F]
+} -body {
+ set enc [aes::aes -mode ecb -dir enc -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 5a6e045708fb7196f02e553d02c3a692
+
+test aes-kat-ecb-256d {Known answer tests - AES-256 ECB decryption} -setup {
+ set txt [binary format H* 5a6e045708fb7196f02e553d02c3a692]
+ set key [binary format H* 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F]
+} -body {
+ set enc [aes::aes -mode ecb -dir dec -key $key $txt]
+ binary scan $enc H* r
+ set r
+} -cleanup {
+ unset txt key enc r
+} -result 000102030405060708090a0b0c0d0e0f
+
+
+# N key ic plain cipher
+set vectors {
+ 1 06a9214036b8a15b512e03d534120006 3dafba429d9eb430b422da802c9fac41
+ 53696e676c6520626c6f636b206d7367 e353779c1079aeb82708942dbe77181a
+ 2 c286696d887c9aa0611bbb3e2025a45a 562e17996d093d28ddb3ba695a2e6f58
+ 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+ d296cd94c2cccf8a3a863028b5e1dc0a7586602d253cfff91b8266bea6d61ab1
+ 3 6c3ea0477630ce21a2ce334aa746c2cd c782dc4c098c66cbd9cd27d825682c81
+ 5468697320697320612034382d62797465206d657373616765202865786163746c7920332041455320626c6f636b7329
+ d0a02b3836451753d493665d33f0e8862dea54cdb293abc7506939276772f8d5021c19216bad525c8579695d83ba2684
+ 4 56e47a38c5598974bc46903dba290349 8ce82eefbea0da3c44699ed7db51b7d9
+ a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf
+ c30e32ffedc0774e6aff6af0869f71aa0f3af07a9a31a9c684db207eb0ef8e4e35907aa632c3ffdf868bb7b29d3d46ad83ce9f9a102ee99d49a53e87f4c3da55
+}
+
+foreach {n key iv pt ct} $vectors {
+ test aes-cbc-${n}e {RFC3602 AES-128 CBC mode encryption} -setup {
+ set K [binary format H* $key]
+ set I [binary format H* $iv]
+ } -body {
+ set aes [aes::aes -mode cbc -dir enc -key $K -iv $I [binary format H* $pt]]
+ binary scan $aes H* r
+ set r
+ } -cleanup {
+ unset r K I aes
+ } -result $ct
+
+ test aes-cbc-${n}d {RFC3602 AES-128 CBC mode decryption} -setup {
+ set K [binary format H* $key]
+ set I [binary format H* $iv]
+ } -body {
+ set aes [aes::aes -mode cbc -dir dec -key $K -iv $I [binary format H* $ct]]
+ binary scan $aes H* r
+ set r
+ } -cleanup {
+ unset r K I aes
+ } -result $pt
+}
+
+# Known answer tests (CBC)
+# 0 00000000000000000000000000000000 00000000000000000000000000000000
+# 00000000000000000000000000000000 8a05fc5e095af4848a08d328d3688e3d
+# 1 8a05fc5e095af4848a08d328d3688e3d 8a05fc5e095af4848a08d328d3688e3d
+# 204f17e2444381f6114ff53934c0bcd3 192d9b3aa10bb2f7846ccba0085c657a
+# 2 93286764a85146730e641888db34eb47 192d9b3aa10bb2f7846ccba0085c657a
+# 983bf6f5a6dfbcdaa19370666e83a99a 40d8daf6d1fda0a073b3bd18b7695d2e
+# 3 d3f0bd9279ace6d37dd7a5906c5db669 40d8daf6d1fda0a073b3bd18b7695d2e
+# c48cd503a21c8ad0b2483ef15f79571d 3edbe80d69a1d2248ca55fc17c4ef3c5
+
+# Bugs
+
+# N key ic plain cipher
+set vectors {
+ 1
+ 3132333435363738393031323334353637383930313233343536373839303132
+ c3f0929f353c2fc78b9c6705397f22c8
+ 005a0000003b00000000000000000000
+ 97d94ab5d6a6bf3e9a126b67b8b3bc12
+}
+
+foreach {n key iv pt ct} $vectors {
+ test aes-cbc-x${n}e {RFC3602 AES-128 CBC mode encryption} -setup {
+ set K [binary format H* $key]
+ set I [binary format H* $iv]
+ } -body {
+ set aes [aes::aes -mode cbc -dir enc -key $K -iv $I [binary format H* $pt]]
+ binary scan $aes H* r
+ set r
+ } -cleanup {
+ unset r K I aes
+ } -result $ct
+
+ test aes-cbc-x${n}d {RFC3602 AES-128 CBC mode decryption} -setup {
+ set K [binary format H* $key]
+ set I [binary format H* $iv]
+ } -body {
+ set aes [aes::aes -mode cbc -dir dec -key $K -iv $I [binary format H* $ct]]
+ binary scan $aes H* r
+ set r
+ } -cleanup {
+ unset r K I aes
+ } -result $pt
+}
+
+test aes-sf2993029 {aes decrypt, wide integer, sf bug 2993029} -body {
+ aes::aes -hex -mode ecb -dir decrypt \
+ -key [binary format H* FEDCBA98FEDCBA98FEDCBA98FEDCBA98] \
+ [binary format H* 2a666624a86d4c29de37b520781c1069]
+} -result 01000000000000003d5afbb584a29f57
+
+# -------------------------------------------------------------------------
+
+test aes-sf-3574004-a {aes use with data starting with a dash, auto-stop} -body {
+ aes::aes -hex -mode cbc -dir encrypt -key [string repeat \\0 16] -[string repeat \\0 15]
+} -result cc45117986e38ae95944f9eeaa7b700b240fdd169eacd2a20505ef4c6507c907
+
+test aes-sf-3574004-b {aes use with data starting with a dash, double-dash} -body {
+ aes::aes -hex -mode cbc -dir encrypt -key [string repeat \\0 16] -- -[string repeat \\0 15]
+} -result cc45117986e38ae95944f9eeaa7b700b240fdd169eacd2a20505ef4c6507c907
+
+# -------------------------------------------------------------------------
+## TODO: Go through the various possible options and combinations.
+
+test aes-sf-3612645-a0 {aes use of -in option, allura 1366} -setup {
+ set key [binary format a32 0123456789012345678901234567890123456789]
+ set encfile [tcltest::makeFile {} aes.encrypt]
+ set decfile [tcltest::makeFile {} aes.decrypt]
+ set outchan [open $encfile w]
+ fconfigure $outchan -translation binary
+ aes::aes -key $key -out $outchan "Hello World Tcl"
+ close $outchan
+ unset outchan
+} -body {
+ set inchan [open $encfile r]
+ fconfigure $inchan -translation binary
+ set outchan [open $decfile w+]
+ aes::aes -dir decrypt -key $key -in $inchan -out $outchan
+ close $inchan
+ close $outchan
+ viewFile $decfile
+} -cleanup {
+ file delete $encfile $decfile
+ unset key encfile decfile inchan outchan
+} -result "Hello World Tcl\000"
+
+test aes-sf-3612645-a1 {aes use of -in option, allura 1366} -setup {
+ set key [binary format a32 0123456789012345678901234567890123456789]
+ set encfile [tcltest::makeFile {} aes.encrypt]
+ set outchan [open $encfile w]
+ fconfigure $outchan -translation binary
+ aes::aes -key $key -out $outchan "Hello World Tcl"
+ close $outchan
+ unset outchan
+} -body {
+ set inchan [open $encfile r]
+ fconfigure $inchan -translation binary
+ set out [aes::aes -dir decrypt -key $key -in $inchan]
+ close $inchan
+ set out
+} -cleanup {
+ file delete $encfile
+ unset out key encfile inchan
+} -result "Hello World Tcl\000"
+
+test aes-sf-3612645-b0 {aes non-use of -in option, allura 1366} -setup {
+ set key [binary format a32 0123456789012345678901234567890123456789]
+ set encfile [tcltest::makeFile {} aes.encrypt]
+ set decfile [tcltest::makeFile {} aes.decrypt]
+ set outchan [open $encfile w]
+ fconfigure $outchan -translation binary
+ aes::aes -key $key -out $outchan "Hello World Tcl"
+ close $outchan
+ unset outchan
+} -body {
+ set inchan [open $encfile r]
+ fconfigure $inchan -translation binary
+ set outchan [open $decfile w+]
+ aes::aes -dir decrypt -key $key -out $outchan [read $inchan]
+ close $inchan
+ close $outchan
+ viewFile $decfile
+} -cleanup {
+ file delete $encfile $decfile
+ unset key encfile decfile inchan outchan
+} -result "Hello World Tcl\000"
+
+test aes-sf-3612645-b1 {aes non-use of -in option, allura 1366} -setup {
+ set key [binary format a32 0123456789012345678901234567890123456789]
+ set encfile [tcltest::makeFile {} aes.encrypt]
+ set outchan [open $encfile w]
+ fconfigure $outchan -translation binary
+ aes::aes -key $key -out $outchan "Hello World Tcl"
+ close $outchan
+ unset outchan
+} -body {
+ set inchan [open $encfile r]
+ fconfigure $inchan -translation binary
+ set out [aes::aes -dir decrypt -key $key [read $inchan]]
+ close $inchan
+ set out
+} -cleanup {
+ file delete $encfile
+ unset out key encfile inchan
+} -result "Hello World Tcl\000"
+
+# -------------------------------------------------------------------------
+
+testsuiteCleanup
+
+# Local variables:
+# mode: tcl
+# indent-tabs-mode: nil
+# End:
diff --git a/tcllib/modules/aes/pkgIndex.tcl b/tcllib/modules/aes/pkgIndex.tcl
new file mode 100644
index 0000000..83cc80f
--- /dev/null
+++ b/tcllib/modules/aes/pkgIndex.tcl
@@ -0,0 +1,5 @@
+if {![package vsatisfies [package provide Tcl] 8.5]} {
+ # PRAGMA: returnok
+ return
+}
+package ifneeded aes 1.2.1 [list source [file join $dir aes.tcl]]