Updated 2016-08-26 17:20:39 by AMG

The Advanced Encryption Standard is the U.S. National Institute of Standards and Technology proposed replacement for the DES cipher. See US FIPS PUB 197 [1]

AES is a block cipher once known as Rijndael which supports variable key and block sizes. As part of the NIST standardization the block size in AES is fixed at 128 bits and the permitted key sizes limited to 128, 192 or 256 bits. AES should be used in preference to DES in all new protocol designs.

A pure-Tcl implementation of AES is now included in tcllib and will be present in the 1.8 release.

SLB Using aes 1.0.0 in Tcl 8.5.0 on Windows, there are some quirks to be aware of:

  • Decrypting an invalid string can cause the error 'integer value too large to represent'
  • If you decrypt using -in, the error is still reported even if you wrap a catch around the call, apparently due to use of fileevent in the implementation.
  • One source of invalid data is from encrypting a string whose length is not a multiple of 16 bytes. The documentation does tell you not to do this but if you forget, the encryption apparently succeeds yet fails in this obscure manner when decrypting.

Example:
 package require aes
 set key [string repeat - 16]
 set fullData {MalletData 9 q q q2 22}
 set encryptedData [aes::aes -dir encrypt -key $key $fullData]
 aes::aes -dir decrypt -key $key $encryptedData
 puts $errorInfo

 integer value too large to represent
    while executing
 "binary format I4 $data"
    (procedure "DecryptBlock" line 25)
    invoked from within
 "DecryptBlock $Key $block"
    (procedure "Decrypt" line 10)
    invoked from within
 "Decrypt $Key $data"
    (procedure "aes::aes" line 41)
    invoked from within
 "aes::aes -dir decrypt -key $key $encryptedData"

LV 2008 June 27.

Here's what I get using ActiveTcl 8.5.2 (and teacup update):
 $ tclsh8.5
% package require aes
 set key [string repeat - 16]
 set fullData {MalletData 9 q q q2 22}
 set encryptedData [aes::aes -dir encrypt -key $key $fullData]
 aes::aes -dir decrypt -key $key $encryptedData
 puts $errorInfo
1.0.1
% ----------------
% MalletData 9 q q q2 22
% I9â3òÌH£í<¯CUÜËÚ¤N|úÙdÜp
% MalletData 9 q q q2 22
% 

I added aes with critcl

LV Anyone have an example of successfully using this?

[AndyA] has this been validated against an authoritative AES example? Using aes 1.2.1 with tcllib 1.18 and tcl 8.6.4, on 64-bit windows firstly the example given in the documentation doesn't work:
% set nil_block [string repeat \\0 16]
% aes::aes -hex -mode cbc -dir encrypt -key $nil_block $nil_block
66e94bd4ef8a2c3b884cfa59ca342b2e

Whereas I get:
4813adc31f481edc7df47497ff72432e2b3c06216a8b8562f963b5410c028c89

(note different length!)

Then when I validate the tcllib aes against http://aes.online-domain-tools.com/ it gives different results. Whereas I have written my own wrapper over B Gladman C code that is consistent with the website. I had actually been hoping to use the tcllib aes wrapper to validate my own code!

So I suspect this library is untested, or only tested on a very specific (32-bit?) platform

It's a bug in aes.tcl. After calling "binary scan binary-array I var", the numbers in var should be converted to unsigned 32-bit integers. You can define a procedure to do this.
        proc ::aes::to_unsigned {data} {
                upvar $data d
                set i 0
                foreach num $d {
                        lset d $i [expr { $num & 0xffffffff }]
                        incr i
                }
        }

There are 5 places to do the convertion, 2 in ::aes::EncryptBlock, 2 in ::aes::DecryptBlock and 1 in ::aes::ExpandKey. You should call to_unsigned after calling of binary scan, like this:
    # original code
    if {[binary scan $block I4 data] != 1} {
        return -code error "invalid block size: blocks must be 16 bytes"
    }
    # bug-fix add here
    to_unsigned data

2011-01-08: Or better yet, if you have 8.5, use the unsigned flag to binary scan, changing your "binary scan binary-array I var" to "binary scan binary-array Iu var".

Then the example code snippet just needs to read:
    if {[binary scan $block Iu4 data] != 1} {

See also des, blowfish, rc4