Tcl Library Source Code

Check-in [4b3d8bca51]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:aes - Ticket [358a88716e]. Applied patch improving performance by changing how the IV is stored. Version bumped to 1.2. Core dependency change! This version requires Tcl 8.5.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4b3d8bca510d4c5504f46f2f38040f54a67c32de
User & Date: andreask 2014-09-23 00:18:14
Context
2014-09-26
10:08
Applied the patch for ticket a6d69107d5 check-in: 7ed9feb717 user: markus tags: trunk
2014-09-23
00:18
aes - Ticket [358a88716e]. Applied patch improving performance by changing how the IV is stored. Version bumped to 1.2. Core dependency change! This version requires Tcl 8.5. check-in: 4b3d8bca51 user: andreask tags: trunk
00:09
aes - Moved tests fully to tcltest v2 format. Moved to require Tcl 8.5. check-in: 43401a27e1 user: andreask tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to modules/aes/aes.man.

1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[comment {-*- tcl -*- doctools manpage}]

[manpage_begin aes n 1.1.1]
[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 <[email protected]>}]
[copyright {2012-2013, Andreas Kupries <[email protected]>}]
[moddesc {Advanced Encryption Standard (AES)}]
[titledesc {Implementation of the AES block cipher}]
[category  {Hashes, checksums, and encryption}]
[require Tcl 8.2]
[require aes [opt 1.1.1]]
[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

>
|










|



|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[comment {-*- tcl -*- doctools manpage}]
[vset AES_VERSION 1.2]
[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 <[email protected]>}]
[copyright {2012-2014, Andreas Kupries <[email protected]>}]
[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

Changes to modules/aes/aes.tcl.

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#   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.2

namespace eval ::aes {
    variable version 1.1.1
    variable rcsid {$Id: aes.tcl,v 1.7 2010/07/06 19:39:00 andreas_kupries Exp $}
    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







|


|



|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#   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 version 1.2
    variable rcsid {$Id: aes.tcl,v 1.7 2010/07/06 19:39:00 andreas_kupries Exp $}
    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
103
104
105
106
107
108
109



110
111
112
113
114
115
116
117
118
119
120
121
122
123


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176
177

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
                must be one of 128, 192 or 256."
        }
    }

    variable uid
    set Key [namespace current]::[incr uid]
    upvar #0 $Key state



    array set state [list M $mode K $key I $iv 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
    set state(I) $iv


    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 I4 data] != 1} {
        return -code error "invalid block size: blocks must be 16 bytes"
    }

    if {[string equal $state(M) cbc]} {
        if {[binary scan $state(I) I4 iv] != 1} {
            return -code error "invalid initialization vector: must be 16 bytes"
        }
        for {set n 0} {$n < 4} {incr n} {
            lappend data2 [expr {0xffffffff & ([lindex $data $n] ^ [lindex $iv $n])}]
        }
        set data $data2
    }

    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.
    set res {}
    foreach d $data {
        lappend res [expr {$d & 0xffffffff}]
    }
    set data $res
    

    return [set state(I) [binary format I4 $data]]
}

# 5.3: Inverse Cipher: Decipher a single 128 bit block.
proc ::aes::DecryptBlock {Key block} {
    upvar #0 $Key state
    if {[binary scan $block I4 data] != 1} {
        return -code error "invalid block size: block must be 16 bytes"
    }


    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 {[string equal $state(M) cbc]} {
        if {[binary scan $state(I) I4 iv] != 1} {
            return -code error "invalid initialization vector: must be 16 bytes"
        }
        for {set n 0} {$n < 4} {incr n} {
            lappend data2 [expr {0xffffffff & ([lindex $data $n] ^ [lindex $iv $n])}]
        }
        set data $data2
    } else {
        # Bug 2993029:
        # Force all elements of data into the 32bit range.
        # The trimming we see above only happens for CBC mode.
        set res {}
        foreach d $data {
            lappend res [expr {$d & 0xffffffff}]
        }
        set data $res
    }

    set state(I) $block
    return [binary format I4 $data]
}

# 5.2: KeyExpansion
proc ::aes::ExpandKey {Key} {
    upvar #0 $Key state
    set Rcon [list 0x00000000 0x01000000 0x02000000 0x04000000 0x08000000 \
                  0x10000000 0x20000000 0x40000000 0x80000000 0x1b000000 \







>
>
>
|












|
>
>

















|




<
<
<

|
















<
|
>
|





|


>









<
<
<

|













|
|







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
                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 {[string equal $state(M) cbc]} {



        for {set n 0} {$n < 4} {incr n} {
            lappend data2 [expr {0xffffffff & ([lindex $data $n] ^ [lindex $state(I) $n])}]
        }
        set data $data2
    }

    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.
    set res {}
    foreach d $data {
        lappend res [expr {$d & 0xffffffff}]
    }


    set state(I) $res
    return [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 {[string equal $state(M) cbc]} {



        for {set n 0} {$n < 4} {incr n} {
            lappend data2 [expr {0xffffffff & ([lindex $data $n] ^ [lindex $state(I) $n])}]
        }
        set data $data2
    } else {
        # Bug 2993029:
        # Force all elements of data into the 32bit range.
        # The trimming we see above only happens for CBC mode.
        set res {}
        foreach d $data {
            lappend res [expr {$d & 0xffffffff}]
        }
        set data $res
    }

    set state(I) $iv
    return [binary format Iu4 $data]
}

# 5.2: KeyExpansion
proc ::aes::ExpandKey {Key} {
    upvar #0 $Key state
    set Rcon [list 0x00000000 0x01000000 0x02000000 0x04000000 0x08000000 \
                  0x10000000 0x20000000 0x40000000 0x80000000 0x1b000000 \
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
    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::DecryptBlock --
#
#	Decrypt a 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"
    }







|

|







431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
    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"
    }

Changes to modules/aes/pkgIndex.tcl.

1
2
3
4
5
if {![package vsatisfies [package provide Tcl] 8.2]} {
    # PRAGMA: returnok
    return
}
package ifneeded aes 1.1.1 [list source [file join $dir aes.tcl]]
|



|
1
2
3
4
5
if {![package vsatisfies [package provide Tcl] 8.5]} {
    # PRAGMA: returnok
    return
}
package ifneeded aes 1.2 [list source [file join $dir aes.tcl]]