diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2016-10-27 19:39:39 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2016-10-27 19:39:39 (GMT) |
commit | ea28451286d3ea4a772fa174483f9a7a66bb1ab3 (patch) | |
tree | 6ee9d8a7848333a7ceeee3b13d492e40225f8b86 /tcllib/modules/aes | |
parent | b5ca09bae0d6a1edce939eea03594dd56383f2c8 (diff) | |
parent | 7c621da28f07e449ad90c387344f07a453927569 (diff) | |
download | blt-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/ChangeLog | 146 | ||||
-rw-r--r-- | tcllib/modules/aes/aes.bench | 75 | ||||
-rw-r--r-- | tcllib/modules/aes/aes.man | 168 | ||||
-rw-r--r-- | tcllib/modules/aes/aes.pcx | 99 | ||||
-rw-r--r-- | tcllib/modules/aes/aes.tcl | 625 | ||||
-rw-r--r-- | tcllib/modules/aes/aes.test | 358 | ||||
-rw-r--r-- | tcllib/modules/aes/pkgIndex.tcl | 5 |
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]] |