twofish 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. data/LICENSE +27 -0
  2. data/README.rdoc +130 -0
  3. data/Rakefile +35 -0
  4. data/lib/twofish.rb +1177 -0
  5. data/test/test_twofish.rb +290 -0
  6. metadata +61 -0
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+
2
+ Copyright 2009 Martin Carpenter. All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are
5
+ permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this list of
8
+ conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
11
+ of conditions and the following disclaimer in the documentation and/or other materials
12
+ provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY Martin Carpenter ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Martin Carpenter OR
17
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ The views and conclusions contained in the software and documentation are those of the
25
+ authors and should not be interpreted as representing official policies, either expressed
26
+ or implied, of Martin Carpenter.
27
+
data/README.rdoc ADDED
@@ -0,0 +1,130 @@
1
+
2
+ = twofish.rb
3
+
4
+ Author:: Martin Carpenter
5
+ Email:: mcarpenter@free.fr
6
+ Copyright:: Copyright (c) Martin Carpenter 2009
7
+
8
+ This class implements the Twofish symmetric encryption algorithm
9
+ in pure Ruby. The original paper describing the cipher "Twofish:
10
+ A 128-Bit Block Cipher" (Schneier, Kelsey, Whiting, Wagner, Hall,
11
+ Ferguson) and further information on Twofish can be found at
12
+ http://www.schneier.com/twofish.html.
13
+
14
+ This implementation is derived with kind permission
15
+ from Guido Flohr's "pure Perl" module Crypt-Twofish_PP:
16
+ http://search.cpan.org/~guido/Crypt-Twofish_PP-0.17. The overall
17
+ structure and a good number of the comments from that implementation
18
+ have been retained.
19
+
20
+
21
+ === Example
22
+
23
+ ECB mode:
24
+
25
+ require 'twofish'
26
+
27
+ key = '1234567890123456'
28
+ tf = Twofish.new(key, :padding => :zero_byte)
29
+ ciphertext = tf.encrypt('Lorem ipsum dolor sit amet')
30
+
31
+ CBC mode with manually specified initialization vector (may alternatively
32
+ be specified in constructor options hash):
33
+
34
+ require 'twofish'
35
+
36
+ key = '1234567890123456'
37
+ tf = Twofish.new(key, :mode => :cbc, :padding => :zero_byte)
38
+ tf.iv = 'abcdefghijklmnop'
39
+ ciphertext = tf.encrypt('Lorem ipsum dolor sit amet')
40
+
41
+
42
+ === Unit tests
43
+
44
+ test_twofish.rb defines the unit tests. The iterative test vectors
45
+ from the original paper are used (although only the final result is
46
+ checked). The CBC mode test vectors were checked using the BouncyCastle
47
+ implementation with JRuby as follows:
48
+
49
+
50
+ include Java
51
+
52
+ require 'bcprov-jdk16-145.jar'
53
+
54
+ include_class Java::org.bouncycastle.jce.provider.BouncyCastleProvider
55
+ include_class Java::org.bouncycastle.crypto.modes.CBCBlockCipher
56
+ include_class Java::org.bouncycastle.crypto.engines.TwofishEngine
57
+ include_class Java::org.bouncycastle.crypto.params.KeyParameter
58
+ include_class Java::org.bouncycastle.crypto.params.ParametersWithIV
59
+
60
+ plaintext = ("\0"*32).to_java_bytes
61
+ ciphertext = ("\0"*32).to_java_bytes
62
+ key = ("\0"*16).to_java_bytes
63
+ iv = ("\0"*16).to_java_bytes
64
+ key_parameter = KeyParameter.new(key)
65
+ cipher_parameter = ParametersWithIV.new(key_parameter, iv)
66
+ cipher = CBCBlockCipher.new TwofishEngine.new
67
+ cipher.init(true, cipher_parameter) # true == encrypt
68
+
69
+ len = 0
70
+ while len < plaintext.length
71
+ len += cipher.processBlock(plaintext, len, ciphertext, len)
72
+ end
73
+
74
+ puts ciphertext.to_a.pack('c*').unpack('H*')
75
+
76
+ The original block test vectors are available as a
77
+ machine-readable file from http://www.schneier.com/code/ecb_ival.txt
78
+
79
+ To run the unit tests, type:
80
+
81
+ rake test
82
+
83
+
84
+ === Documentation
85
+
86
+ Aside from this README, rdoc documentation may be built as follows:
87
+
88
+ rake rdoc
89
+
90
+ The documentation will be built in the rdoc subdirectory.
91
+
92
+
93
+ === Bugs, omissions and weaknesses
94
+
95
+ Encryption and decryption are (not unexpectedly) slow. If you need a
96
+ faster implementation for Ruby then the BouncyCastle provider
97
+ (http://www.bouncycastle.org) plays well with JRuby (http://www.jruby.org).
98
+ See above ("Unit tests") for a sample script.
99
+
100
+ The original "pure Perl" implementation used Perl's integer pragma.
101
+ This implementation uses a private method mask32 to strip off any high
102
+ order bits in an effort to prevent (slow) promotion of Fixnums to Bignums.
103
+ This is a little clumsy and probably could be quicker.
104
+
105
+ Ruby >=1.9 introduces string encodings. The current workaround uses
106
+ #ord and #chr but this is not very satisfactory: it would be preferable
107
+ to move to byte arrays throughout.
108
+
109
+ The only padding mechanisms implemented are "none" (don't pad) and "zero
110
+ byte" (append zero bytes to make up a full block). Zero byte padding has
111
+ a well-known failure mode: if the plaintext terminates in null bytes
112
+ then these may be erroneously removed when un-padding is performed.
113
+
114
+ If no initialization vector is provided for CBC mode then the system
115
+ random number generator (Kernel#rand) is used to generate one. The system
116
+ random number generator may be weaker than desired.
117
+
118
+ The IV is not silently prepended to the ciphertext since if
119
+ the resulting ciphertext is transmitted as is this can introduce
120
+ a weakness. IV should ideally be transmitted OOB. There
121
+ is a good explanation of this risk at Terry Ritter's page
122
+ http://www.ciphersbyritter.com/GLOSSARY.HTM#CipherBlockChaining
123
+
124
+ if the IV is not enciphered, and if the opponents
125
+ can intercept and change the IV in transit, they can
126
+ change the first-block plaintext bit-for-bit, without
127
+ a block-wide garble. That means an opponent could make
128
+ systematic changes to the first block plaintext simply
129
+ by changing the IV.
130
+
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/testtask'
7
+
8
+ desc 'Default task (test)'
9
+ task :default => [:test]
10
+
11
+ Rake::TestTask.new('test') do |test|
12
+ test.pattern = 'test/*.rb'
13
+ test.warning = true
14
+ end
15
+
16
+ SPECFILE = 'twofish.gemspec'
17
+ if File.exist?(SPECFILE)
18
+ spec = eval( File.read(SPECFILE) )
19
+ Rake::GemPackageTask.new(spec) do |pkg|
20
+ pkg.need_tar = true
21
+ end
22
+ end
23
+
24
+ Rake::RDocTask.new do |rdoc|
25
+ rdoc.rdoc_dir = 'rdoc'
26
+ rdoc.title = 'twofish.rb'
27
+ rdoc.options << '--line-numbers' << '--inline-source'
28
+ rdoc.options << '-A cattr_accessor=object'
29
+ rdoc.options << '--charset' << 'utf-8'
30
+ rdoc.options << '--all'
31
+ rdoc.rdoc_files.include('README.rdoc')
32
+ rdoc.rdoc_files.include('lib/twofish.rb')
33
+ rdoc.rdoc_files.include('test/test_twofish.rb')
34
+ end
35
+
data/lib/twofish.rb ADDED
@@ -0,0 +1,1177 @@
1
+ # twofish.rb
2
+ #
3
+ # Author:: Martin Carpenter
4
+ # Email:: mcarpenter@free.fr
5
+ # Copyright:: Copyright (c) Martin Carpenter 2009
6
+ #
7
+ # Implements a class for symmetric encryption using the Twofish
8
+ # encryption algorithm based on original work by Guido Flohr.
9
+ class Twofish
10
+
11
+ attr_reader :iv, :key_size, :mode, :padding # setters for iv, mode defined below for validation
12
+
13
+ BLOCK_SIZE = 16 # 16 bytes, 128 bits
14
+
15
+ #:stopdoc:
16
+ Q0 = [
17
+ 169, 103, 179, 232, 4, 253, 163, 118, 154, 146, 128, 120, 228,
18
+ 221, 209, 56, 13, 198, 53, 152, 24, 247, 236, 108, 67, 117,
19
+ 55, 38, 250, 19, 148, 72, 242, 208, 139, 48, 132, 84, 223,
20
+ 35, 25, 91, 61, 89, 243, 174, 162, 130, 99, 1, 131, 46,
21
+ 217, 81, 155, 124, 166, 235, 165, 190, 22, 12, 227, 97, 192,
22
+ 140, 58, 245, 115, 44, 37, 11, 187, 78, 137, 107, 83, 106,
23
+ 180, 241, 225, 230, 189, 69, 226, 244, 182, 102, 204, 149, 3,
24
+ 86, 212, 28, 30, 215, 251, 195, 142, 181, 233, 207, 191, 186,
25
+ 234, 119, 57, 175, 51, 201, 98, 113, 129, 121, 9, 173, 36,
26
+ 205, 249, 216, 229, 197, 185, 77, 68, 8, 134, 231, 161, 29,
27
+ 170, 237, 6, 112, 178, 210, 65, 123, 160, 17, 49, 194, 39,
28
+ 144, 32, 246, 96, 255, 150, 92, 177, 171, 158, 156, 82, 27,
29
+ 95, 147, 10, 239, 145, 133, 73, 238, 45, 79, 143, 59, 71,
30
+ 135, 109, 70, 214, 62, 105, 100, 42, 206, 203, 47, 252, 151,
31
+ 5, 122, 172, 127, 213, 26, 75, 14, 167, 90, 40, 20, 63,
32
+ 41, 136, 60, 76, 2, 184, 218, 176, 23, 85, 31, 138, 125,
33
+ 87, 199, 141, 116, 183, 196, 159, 114, 126, 21, 34, 18, 88,
34
+ 7, 153, 52, 110, 80, 222, 104, 101, 188, 219, 248, 200, 168,
35
+ 43, 64, 220, 254, 50, 164, 202, 16, 33, 240, 211, 93, 15,
36
+ 0, 111, 157, 54, 66, 74, 94, 193, 224
37
+ ]
38
+
39
+ Q1 = [
40
+ 117, 243, 198, 244, 219, 123, 251, 200, 74, 211, 230, 107, 69,
41
+ 125, 232, 75, 214, 50, 216, 253, 55, 113, 241, 225, 48, 15,
42
+ 248, 27, 135, 250, 6, 63, 94, 186, 174, 91, 138, 0, 188,
43
+ 157, 109, 193, 177, 14, 128, 93, 210, 213, 160, 132, 7, 20,
44
+ 181, 144, 44, 163, 178, 115, 76, 84, 146, 116, 54, 81, 56,
45
+ 176, 189, 90, 252, 96, 98, 150, 108, 66, 247, 16, 124, 40,
46
+ 39, 140, 19, 149, 156, 199, 36, 70, 59, 112, 202, 227, 133,
47
+ 203, 17, 208, 147, 184, 166, 131, 32, 255, 159, 119, 195, 204,
48
+ 3, 111, 8, 191, 64, 231, 43, 226, 121, 12, 170, 130, 65,
49
+ 58, 234, 185, 228, 154, 164, 151, 126, 218, 122, 23, 102, 148,
50
+ 161, 29, 61, 240, 222, 179, 11, 114, 167, 28, 239, 209, 83,
51
+ 62, 143, 51, 38, 95, 236, 118, 42, 73, 129, 136, 238, 33,
52
+ 196, 26, 235, 217, 197, 57, 153, 205, 173, 49, 139, 1, 24,
53
+ 35, 221, 31, 78, 45, 249, 72, 79, 242, 101, 142, 120, 92,
54
+ 88, 25, 141, 229, 152, 87, 103, 127, 5, 100, 175, 99, 182,
55
+ 254, 245, 183, 60, 165, 206, 233, 104, 68, 224, 77, 67, 105,
56
+ 41, 46, 172, 21, 89, 168, 10, 158, 110, 71, 223, 52, 53,
57
+ 106, 207, 220, 34, 201, 192, 155, 137, 212, 237, 171, 18, 162,
58
+ 13, 82, 187, 2, 47, 169, 215, 97, 30, 180, 80, 4, 246,
59
+ 194, 22, 37, 134, 86, 85, 9, 190, 145
60
+ ]
61
+
62
+ M0 = [
63
+ 3166450293, 3974898163, 538985414, 3014904308, 3671720923,
64
+ 33721211, 3806473211, 2661219016, 3385453642, 3570665939,
65
+ 404253670, 505323371, 2560101957, 2998024317, 2795950824,
66
+ 640071499, 1010587606, 2475919922, 2189618904, 1381144829,
67
+ 2071712823, 3149608817, 1532729329, 1195869153, 606354480,
68
+ 1364320783, 3132802808, 1246425883, 3216984199, 218984698,
69
+ 2964370182, 1970658879, 3537042782, 2105352378, 1717973422,
70
+ 976921435, 1499012234, 0, 3452801980, 437969053,
71
+ 2930650221, 2139073473, 724289457, 3200170254, 3772817536,
72
+ 2324303965, 993743570, 1684323029, 3638069408, 3890718084,
73
+ 1600120839, 454758676, 741130933, 4244419728, 825304876,
74
+ 2155898275, 1936927410, 202146163, 2037997388, 1802191188,
75
+ 1263207058, 1397975412, 2492763958, 2206408529, 707409464,
76
+ 3301219504, 572704957, 3587569754, 3183330300, 1212708960,
77
+ 4294954594, 1280051094, 1094809452, 3351766594, 3958056183,
78
+ 471602192, 1566401404, 909517352, 1734852647, 3924406156,
79
+ 1145370899, 336915093, 4126522268, 3486456007, 1061104932,
80
+ 3233866566, 1920129851, 1414818928, 690572490, 4042274275,
81
+ 134807173, 3334870987, 4092808977, 2358043856, 2762234259,
82
+ 3402274488, 1751661478, 3099086211, 943204384, 3857002239,
83
+ 2913818271, 185304183, 3368558019, 2577006540, 1482222851,
84
+ 421108335, 235801096, 2509602495, 1886408768, 4160172263,
85
+ 1852755755, 522153698, 3048553849, 151588620, 1633760426,
86
+ 1465325186, 2678000449, 2644344890, 286352618, 623234489,
87
+ 2947538404, 1162152090, 3755969956, 2745392279, 3941258622,
88
+ 892688602, 3991785594, 1128528919, 4177054566, 4227576212,
89
+ 926405537, 4210704413, 3267520573, 3031747824, 842161630,
90
+ 2627498419, 1448535819, 3823360626, 2273796263, 353704732,
91
+ 4193860335, 1667481553, 875866451, 2593817918, 2981184143,
92
+ 2088554803, 2290653990, 1027450463, 2711738348, 3840204662,
93
+ 2172752938, 2442199369, 252705665, 4008618632, 370565614,
94
+ 3621221153, 2543318468, 2779097114, 4278075371, 1835906521,
95
+ 2021174981, 3318050105, 488498585, 1987486925, 1044307117,
96
+ 3419105073, 3065399179, 4025441025, 303177240, 1616954659,
97
+ 1785376989, 1296954911, 3469666638, 3739122733, 1431674361,
98
+ 2122209864, 555856463, 50559730, 2694850149, 1583225230,
99
+ 1515873912, 1701137244, 1650609752, 4261233945, 101119117,
100
+ 1077970661, 4075994776, 859024471, 387420263, 84250239,
101
+ 3907542533, 1330609508, 2307484335, 269522275, 1953771446,
102
+ 168457726, 1549570805, 2610656439, 757936956, 808507045,
103
+ 774785486, 1229556201, 1179021928, 2004309316, 2829637856,
104
+ 2526413901, 673758531, 2846435689, 3654908201, 2256965934,
105
+ 3520169900, 4109650453, 2374833497, 3604382376, 3115957258,
106
+ 1111625118, 4143366510, 791656519, 3722249951, 589510964,
107
+ 3435946549, 4059153514, 3250655951, 2240146396, 2408554018,
108
+ 1903272393, 2425417920, 2863289243, 16904585, 2341200340,
109
+ 1313770733, 2391699371, 2880152082, 1869561506, 3873854477,
110
+ 3688624722, 2459073467, 3082270210, 1768540719, 960092585,
111
+ 3553823959, 2812748641, 2728570142, 3284375988, 1819034704,
112
+ 117900548, 67403766, 656885442, 2896996118, 3503322661,
113
+ 1347425158, 3705468758, 2223250005, 3789639945, 2054825406,
114
+ 320073617
115
+ ]
116
+
117
+ M1 = [
118
+ 2849585465, 1737496343, 3010567324, 3906119334, 67438343,
119
+ 4254618194, 2741338240, 1994384612, 2584233285, 2449623883,
120
+ 2158026976, 2019973722, 3839733679, 3719326314, 3518980963,
121
+ 943073834, 223667942, 3326287904, 895667404, 2562650866,
122
+ 404623890, 4146392043, 3973554593, 1819754817, 1136470056,
123
+ 1966259388, 936672123, 647727240, 4201647373, 335103044,
124
+ 2494692347, 1213890174, 4068082435, 3504639116, 2336732854,
125
+ 809247780, 2225465319, 1413573483, 3741769181, 600137824,
126
+ 424017405, 1537423930, 1030275778, 1494584717, 4079086828,
127
+ 2922473062, 2722000751, 2182502231, 1670713360, 22802415,
128
+ 2202908856, 781289094, 3652545901, 1361019779, 2605951658,
129
+ 2086886749, 2788911208, 3946839806, 2782277680, 3190127226,
130
+ 380087468, 202311945, 3811963120, 1629726631, 3236991120,
131
+ 2360338921, 981507485, 4120009820, 1937837068, 740766001,
132
+ 628543696, 199710294, 3145437842, 1323945678, 2314273025,
133
+ 1805590046, 1403597876, 1791291889, 3029976003, 4053228379,
134
+ 3783477063, 3865778200, 3184009762, 1158584472, 3798867743,
135
+ 4106859443, 3056563316, 1724643576, 3439303065, 2515145748,
136
+ 65886296, 1459084508, 3571551115, 471536917, 514695842,
137
+ 3607942099, 4213957346, 3273509064, 2384027230, 3049401388,
138
+ 3918088521, 3474112961, 3212744085, 3122691453, 3932426513,
139
+ 2005142283, 963495365, 2942994825, 869366908, 3382800753,
140
+ 1657733119, 1899477947, 2180714255, 2034087349, 156361185,
141
+ 2916892222, 606945087, 3450107510, 4187837781, 3639509634,
142
+ 3850780736, 3316545656, 3117229349, 1292146326, 1146451831,
143
+ 134876686, 2249412688, 3878746103, 2714974007, 490797818,
144
+ 2855559521, 3985395278, 112439472, 1886147668, 2989126515,
145
+ 3528604475, 1091280799, 2072707586, 2693322968, 290452467,
146
+ 828885963, 3259377447, 666920807, 2427780348, 539506744,
147
+ 4135519236, 1618495560, 4281263589, 2517060684, 1548445029,
148
+ 2982619947, 2876214926, 2651669058, 2629563893, 1391647707,
149
+ 468929098, 1604730173, 2472125604, 180140473, 4013619705,
150
+ 2448364307, 2248017928, 1224839569, 3999340054, 763158238,
151
+ 1337073953, 2403512753, 1004237426, 1203253039, 2269691839,
152
+ 1831644846, 1189331136, 3596041276, 1048943258, 1764338089,
153
+ 1685933903, 714375553, 3460902446, 3407333062, 801794409,
154
+ 4240686525, 2539430819, 90106088, 2060512749, 2894582225,
155
+ 2140013829, 3585762404, 447260069, 1270294054, 247054014,
156
+ 2808121223, 1526257109, 673330742, 336665371, 1071543669,
157
+ 695851481, 2292903662, 1009986861, 1281325433, 45529015,
158
+ 3096890058, 3663213877, 2963064004, 402408259, 1427801220,
159
+ 536235341, 2317113689, 2100867762, 1470903091, 3340292047,
160
+ 2381579782, 1953059667, 3077872539, 3304429463, 2673257901,
161
+ 1926947811, 2127948522, 357233908, 580816783, 312650667,
162
+ 1481532002, 132669279, 2581929245, 876159779, 1858205430,
163
+ 1346661484, 3730649650, 1752319558, 1697030304, 3163803085,
164
+ 3674462938, 4173773498, 3371867806, 2827146966, 735014510,
165
+ 1079013488, 3706422661, 4269083146, 847942547, 2760761311,
166
+ 3393988905, 269753372, 561240023, 4039947444, 3540636884,
167
+ 1561365130, 266490193, 0, 1872369945, 2648709658,
168
+ 915379348, 1122420679, 1257032137, 1593692882, 3249241983,
169
+ 3772295336
170
+ ]
171
+
172
+ M2 = [
173
+ 3161832498, 3975408673, 549855299, 3019158473, 3671841283,
174
+ 41616011, 3808158251, 2663948026, 3377121772, 3570652169,
175
+ 417732715, 510336671, 2554697742, 2994582072, 2800264914,
176
+ 642459319, 1020673111, 2469565322, 2195227374, 1392333464,
177
+ 2067233748, 3144792887, 1542544279, 1205946243, 607134780,
178
+ 1359958498, 3136862918, 1243302643, 3213344584, 234491248,
179
+ 2953228467, 1967093214, 3529429757, 2109373728, 1722705457,
180
+ 979057315, 1502239004, 0, 3451702675, 446503648,
181
+ 2926423596, 2143387563, 733031367, 3188637369, 3766542496,
182
+ 2321386000, 1003633490, 1691706554, 3634419848, 3884246949,
183
+ 1594318824, 454302481, 750070978, 4237360308, 824979751,
184
+ 2158198885, 1941074730, 208866433, 2035054943, 1800694593,
185
+ 1267878658, 1400132457, 2486604943, 2203157279, 708323894,
186
+ 3299919004, 582820552, 3579500024, 3187457475, 1214269560,
187
+ 4284678094, 1284918279, 1097613687, 3343042534, 3958893348,
188
+ 470817812, 1568431459, 908604962, 1730635712, 3918326191,
189
+ 1142113529, 345314538, 4120704443, 3485978392, 1059340077,
190
+ 3225862371, 1916498651, 1416647788, 701114700, 4041470005,
191
+ 142936318, 3335243287, 4078039887, 2362477796, 2761139289,
192
+ 3401108118, 1755736123, 3095640141, 941635624, 3858752814,
193
+ 2912922966, 192351108, 3368273949, 2580322815, 1476614381,
194
+ 426711450, 235408906, 2512360830, 1883271248, 4159174448,
195
+ 1848340175, 534912878, 3044652349, 151783695, 1638555956,
196
+ 1468159766, 2671877899, 2637864320, 300552548, 632890829,
197
+ 2951000029, 1167738120, 3752124301, 2744623964, 3934186197,
198
+ 903492952, 3984256464, 1125598204, 4167497931, 4220844977,
199
+ 933312467, 4196268608, 3258827368, 3035673804, 853422685,
200
+ 2629016689, 1443583719, 3815957466, 2275903328, 354161947,
201
+ 4193253690, 1674666943, 877868201, 2587794053, 2978984258,
202
+ 2083749073, 2284226715, 1029651878, 2716639703, 3832997087,
203
+ 2167046548, 2437517569, 260116475, 4001951402, 384702049,
204
+ 3609319283, 2546243573, 2769986984, 4276878911, 1842965941,
205
+ 2026207406, 3308897645, 496573925, 1993176740, 1051541212,
206
+ 3409038183, 3062609479, 4009881435, 303567390, 1612931269,
207
+ 1792895664, 1293897206, 3461271273, 3727548028, 1442403741,
208
+ 2118680154, 558834098, 66192250, 2691014694, 1586388505,
209
+ 1517836902, 1700554059, 1649959502, 4246338885, 109905652,
210
+ 1088766086, 4070109886, 861352876, 392632208, 92210574,
211
+ 3892701278, 1331974013, 2309982570, 274927765, 1958114351,
212
+ 184420981, 1559583890, 2612501364, 758918451, 816132310,
213
+ 785264201, 1240025481, 1181238898, 2000975701, 2833295576,
214
+ 2521667076, 675489981, 2842274089, 3643398521, 2251196049,
215
+ 3517763975, 4095079498, 2371456277, 3601389186, 3104487868,
216
+ 1117667853, 4134467265, 793194424, 3722435846, 590619449,
217
+ 3426077794, 4050317764, 3251618066, 2245821931, 2401406878,
218
+ 1909027233, 2428539120, 2862328403, 25756145, 2345962465,
219
+ 1324174988, 2393607791, 2870127522, 1872916286, 3859670612,
220
+ 3679640562, 2461766267, 3070408630, 1764714954, 967391705,
221
+ 3554136844, 2808194851, 2719916717, 3283403673, 1817209924,
222
+ 117704453, 83231871, 667035462, 2887167143, 3492139126,
223
+ 1350979603, 3696680183, 2220196890, 3775521105, 2059303461,
224
+ 328274927
225
+ ]
226
+
227
+ M3 = [
228
+ 3644434905, 2417452944, 1906094961, 3534153938, 84345861,
229
+ 2555575704, 1702929253, 3756291807, 138779144, 38507010,
230
+ 2699067552, 1717205094, 3719292125, 2959793584, 3210990015,
231
+ 908736566, 1424362836, 1126221379, 1657550178, 3203569854,
232
+ 504502302, 619444004, 3617713367, 2000776311, 3173532605,
233
+ 851211570, 3564845012, 2609391259, 1879964272, 4181988345,
234
+ 2986054833, 1518225498, 2047079034, 3834433764, 1203145543,
235
+ 1009004604, 2783413413, 1097552961, 115203846, 3311412165,
236
+ 1174214981, 2738510755, 1757560168, 361584917, 569176865,
237
+ 828812849, 1047503422, 374833686, 2500879253, 1542390107,
238
+ 1303937869, 2441490065, 3043875253, 528699679, 1403689811,
239
+ 1667071075, 996714043, 1073670975, 3593512406, 628801061,
240
+ 2813073063, 252251151, 904979253, 598171939, 4036018416,
241
+ 2951318703, 2157787776, 2455565714, 2165076865, 657533991,
242
+ 1993352566, 3881176039, 2073213819, 3922611945, 4043409905,
243
+ 2669570975, 2838778793, 3304155844, 2579739801, 2539385239,
244
+ 2202526083, 1796793963, 3357720008, 244860174, 1847583342,
245
+ 3384014025, 796177967, 3422054091, 4288269567, 3927217642,
246
+ 3981968365, 4158412535, 3784037601, 454368283, 2913083053,
247
+ 215209740, 736295723, 499696413, 425627161, 3257710018,
248
+ 2303322505, 314691346, 2123743102, 545110560, 1678895716,
249
+ 2215344004, 1841641837, 1787408234, 3514577873, 2708588961,
250
+ 3472843470, 935031095, 4212097531, 1035303229, 1373702481,
251
+ 3695095260, 759112749, 2759249316, 2639657373, 4001552622,
252
+ 2252400006, 2927150510, 3441801677, 76958980, 1433879637,
253
+ 168691722, 324044307, 821552944, 3543638483, 1090133312,
254
+ 878815796, 2353982860, 3014657715, 1817473132, 712225322,
255
+ 1379652178, 194986251, 2332195723, 2295898248, 1341329743,
256
+ 1741369703, 1177010758, 3227985856, 3036450996, 674766888,
257
+ 2131031679, 2018009208, 786825006, 122459655, 1264933963,
258
+ 3341529543, 1871620975, 222469645, 3153435835, 4074459890,
259
+ 4081720307, 2789040038, 1503957849, 3166243516, 989458234,
260
+ 4011037167, 4261971454, 26298625, 1628892769, 2094935420,
261
+ 2988527538, 1118932802, 3681696731, 3090106296, 1220511560,
262
+ 749628716, 3821029091, 1463604823, 2241478277, 698968361,
263
+ 2102355069, 2491493012, 1227804233, 398904087, 3395891146,
264
+ 3284008131, 1554224988, 1592264030, 3505224400, 2278665351,
265
+ 2382725006, 3127170490, 2829392552, 3072740279, 3116240569,
266
+ 1619502944, 4174732024, 573974562, 286987281, 3732226014,
267
+ 2044275065, 2867759274, 858602547, 1601784927, 3065447094,
268
+ 2529867926, 1479924312, 2630135964, 4232255484, 444880154,
269
+ 4132249590, 475630108, 951221560, 2889045932, 416270104,
270
+ 4094070260, 1767076969, 1956362100, 4120364277, 1454219094,
271
+ 3672339162, 3588914901, 1257510218, 2660180638, 2729120418,
272
+ 1315067982, 3898542056, 3843922405, 958608441, 3254152897,
273
+ 1147949124, 1563614813, 1917216882, 648045862, 2479733907,
274
+ 64674563, 3334142150, 4204710138, 2195105922, 3480103887,
275
+ 1349533776, 3951418603, 1963654773, 2324902538, 2380244109,
276
+ 1277807180, 337383444, 1943478643, 3434410188, 164942601,
277
+ 277503248, 3796963298, 0, 2585358234, 3759840736,
278
+ 2408855183, 3871818470, 3972614892, 4258422525, 2877276587,
279
+ 3634946264
280
+ ]
281
+ #:startdoc:
282
+
283
+ # Takes a mandatory key (16, 24 or 32 bytes), and an options
284
+ # hash as follows:
285
+ # :mode => :ecb (default) or :cbc
286
+ # :iv => optional 16 byte initialization vector (randomly generated if not supplied)
287
+ # :padding => :none (default) or :zero_byte
288
+ def initialize(key_string, opts={})
289
+
290
+ self.mode = opts[:mode] # use setter for validation
291
+ self.padding = opts[:padding] # use setter for validation
292
+ @iv = opts[:iv] || generate_iv(BLOCK_SIZE) unless @mode == Mode::ECB
293
+
294
+ # The key consists of k=len/8 (2, 3 or 4) 64-bit units.
295
+ key = key_string.unpack("C*")
296
+ @key_size = key.length
297
+
298
+ # We must derive three vectors Me, Mo, and S, each with k 32-bit
299
+ # words, from the 2k words in the key.
300
+ #
301
+ # Me = (key[0], key[2], ..., key[2k-2]) (even words)
302
+ # Mo = (key[1], key[3], ..., key[2k-1]) (odd words)
303
+ #
304
+ # The third vector is derived by multiplying each of the k groups
305
+ # of 8 bytes from the key by a 4x8 matrix, to get k 32-bit words.
306
+ #
307
+ # S = (S[k-1], S[k-2], ..., S[0])
308
+ #
309
+ # where S[i] are the 4 bytes from the multiplication, interpreted
310
+ # as a 32-bit word. As described later, mds_rem is equivalent to
311
+ # the matrix multiplication, but faster.
312
+ le_longs = key_string.unpack("V*")
313
+
314
+ # The words of the expanded key K are defined using the h function:
315
+ #
316
+ # rho = 2^24 + 2^16 + 2^8 + 2^0 (0x01010101)
317
+ # A[i] = h(2i*rho, Me)
318
+ # B[i] = ROL(h(2(i+1)*rho, Mo), 8)
319
+ # K[2i] = (A[i] + B[i]) mod 2^32
320
+ # K[2i+1] = ROL((A[i] + 2B[i]) mod 2^32, 9)
321
+ #
322
+ # rho has the property that, for i = 0..255, the word i*rho
323
+ # consists of four equal bytes, each with the value i. The function
324
+ # h is only applied to words of this type, so we only pass it the
325
+ # value of i.
326
+ k = []
327
+
328
+ # The key-dependent S-boxes used in the g() function are created
329
+ # below. They are defined by g(X) = h(X, S), where S is the vector
330
+ # derived from the key. That is, for i=0..3, the S-box S[i] is
331
+ # formed by mapping from x[i] to y[i] in the h function.
332
+ #
333
+ # The relevant lookup tables qN have been precomputed and stored in
334
+ # tables.h; we also perform full key precomputations incorporating
335
+ # the MDS matrix multiplications.
336
+ xS0, xS1, xS2, xS3 = [], [], [], []
337
+ case @key_size
338
+ when 16
339
+ s7, s6, s5, s4 = *mds_rem(le_longs[0], le_longs[1])
340
+ s3, s2, s1, s0 = *mds_rem(le_longs[2], le_longs[3])
341
+ a, b = 0, 0
342
+ (0..38).step(2) do |i|
343
+ j = i + 1
344
+ a = M0[Q0[Q0[i] ^ key[8]] ^ key[0]] ^
345
+ M1[Q0[Q1[i] ^ key[9]] ^ key[1]] ^
346
+ M2[Q1[Q0[i] ^ key[10]] ^ key[2]] ^
347
+ M3[Q1[Q1[i] ^ key[11]] ^ key[3]]
348
+ b = M0[Q0[Q0[j] ^ key[12]] ^ key[4]] ^
349
+ M1[Q0[Q1[j] ^ key[13]] ^ key[5]] ^
350
+ M2[Q1[Q0[j] ^ key[14]] ^ key[6]] ^
351
+ M3[Q1[Q1[j] ^ key[15]] ^ key[7]]
352
+ b = mask32(b << 8) | (b >> 24)
353
+ a = mask32(a+b)
354
+ k.push(a)
355
+ a = mask32(a+b)
356
+ k.push(mask32(a << 9) | a >> 23)
357
+ end
358
+ (0..255).each do |i|
359
+ xS0[i] = M0[Q0[Q0[i] ^ s4] ^ s0]
360
+ xS1[i] = M1[Q0[Q1[i] ^ s5] ^ s1]
361
+ xS2[i] = M2[Q1[Q0[i] ^ s6] ^ s2]
362
+ xS3[i] = M3[Q1[Q1[i] ^ s7] ^ s3]
363
+ end
364
+ when 24
365
+ sb, sa, s9, s8 = *mds_rem(le_longs[0], le_longs[1])
366
+ s7, s6, s5, s4 = *mds_rem(le_longs[2], le_longs[3])
367
+ s3, s2, s1, s0 = *mds_rem(le_longs[4], le_longs[5])
368
+ i, j = 0, 1
369
+ (0..38).step(2) do |i|
370
+ j = i + 1
371
+ a = M0[Q0[Q0[Q1[i] ^ key[16]] ^ key[8]] ^ key[0]] ^
372
+ M1[Q0[Q1[Q1[i] ^ key[17]] ^ key[9]] ^ key[1]] ^
373
+ M2[Q1[Q0[Q0[i] ^ key[18]] ^ key[10]] ^ key[2]] ^
374
+ M3[Q1[Q1[Q0[i] ^ key[19]] ^ key[11]] ^ key[3]]
375
+ b = M0[Q0[Q0[Q1[j] ^ key[20]] ^ key[12]] ^ key[4]] ^
376
+ M1[Q0[Q1[Q1[j] ^ key[21]] ^ key[13]] ^ key[5]] ^
377
+ M2[Q1[Q0[Q0[j] ^ key[22]] ^ key[14]] ^ key[6]] ^
378
+ M3[Q1[Q1[Q0[j] ^ key[23]] ^ key[15]] ^ key[7]]
379
+ b = mask32(b << 8) | (b >> 24)
380
+ a = mask32(a+b)
381
+ k.push(a)
382
+ a = mask32(a+b)
383
+ k.push(mask32(a << 9) | a >> 23)
384
+ end
385
+ (0..255).each do |i|
386
+ xS0[i] = M0[Q0[Q0[Q1[i] ^ s8] ^ s4] ^ s0]
387
+ xS1[i] = M1[Q0[Q1[Q1[i] ^ s9] ^ s5] ^ s1]
388
+ xS2[i] = M2[Q1[Q0[Q0[i] ^ sa] ^ s6] ^ s2]
389
+ xS3[i] = M3[Q1[Q1[Q0[i] ^ sb] ^ s7] ^ s3]
390
+ end
391
+ when 32
392
+ sf, se, sd, sc = *mds_rem(le_longs[0], le_longs[1])
393
+ sb, sa, s9, s8 = *mds_rem(le_longs[2], le_longs[3])
394
+ s7, s6, s5, s4 = *mds_rem(le_longs[4], le_longs[5])
395
+ s3, s2, s1, s0 = *mds_rem(le_longs[6], le_longs[7])
396
+ i, j = 0, 1
397
+ (0..38).step(2) do |i|
398
+ j = i + 1
399
+ a = M0[Q0[Q0[Q1[Q1[i] ^ key[24]] ^ key[16]] ^ key[8]] ^ key[0]] ^
400
+ M1[Q0[Q1[Q1[Q0[i] ^ key[25]] ^ key[17]] ^ key[9]] ^ key[1]] ^
401
+ M2[Q1[Q0[Q0[Q0[i] ^ key[26]] ^ key[18]] ^ key[10]] ^ key[2]] ^
402
+ M3[Q1[Q1[Q0[Q1[i] ^ key[27]] ^ key[19]] ^ key[11]] ^ key[3]]
403
+ b = M0[Q0[Q0[Q1[Q1[j] ^ key[28]] ^ key[20]] ^ key[12]] ^ key[4]] ^
404
+ M1[Q0[Q1[Q1[Q0[j] ^ key[29]] ^ key[21]] ^ key[13]] ^ key[5]] ^
405
+ M2[Q1[Q0[Q0[Q0[j] ^ key[30]] ^ key[22]] ^ key[14]] ^ key[6]] ^
406
+ M3[Q1[Q1[Q0[Q1[j] ^ key[31]] ^ key[23]] ^ key[15]] ^ key[7]]
407
+ b = mask32(b << 8) | (b >> 24)
408
+ a = mask32(a+b)
409
+ k.push(a)
410
+ a = mask32(a+b)
411
+ k.push(mask32(a << 9) | a >> 23)
412
+ end
413
+ (0..255).each do |i|
414
+ xS0[i] = M0[Q0[Q0[Q1[Q1[i]^sc]^s8]^s4]^s0]
415
+ xS1[i] = M1[Q0[Q1[Q1[Q0[i]^sd]^s9]^s5]^s1]
416
+ xS2[i] = M2[Q1[Q0[Q0[Q0[i]^se]^sa]^s6]^s2]
417
+ xS3[i] = M3[Q1[Q1[Q0[Q1[i]^sf]^sb]^s7]^s3]
418
+ end
419
+ else
420
+ raise ArgumentError, "invalid key length #{@key_size} (expecting 16, 24 or 32 bytes)"
421
+ end
422
+
423
+ @k = k
424
+ @s = [ xS0, xS1, xS2, xS3 ]
425
+
426
+ end
427
+
428
+ # Assign the initialization vector.
429
+ # This does not make sense for ECB mode. Also the IV length
430
+ # must be a multiple of the block size.
431
+ def iv=(iv)
432
+ raise ArgumentError, 'cannot specify initialization vector for ECB mode' if @mode == Mode::ECB
433
+ raise ArgumentError, "initialization vectcor is not a multiple of #{BLOCK_SIZE} bytes" unless (iv.length % BLOCK_SIZE).zero?
434
+ @iv = iv
435
+ end
436
+
437
+ # Set the mode of the cipher (Mode::ECB == :ecb or
438
+ # Mode::CBC == :cbc).
439
+ # If the cipher has an IV already and mode is now
440
+ # set to Mode::ECB then the IV will be ignored for any
441
+ # encrypt/decrypt operations.
442
+ def mode=(mode)
443
+ @mode = Mode::validate(mode)
444
+ end
445
+
446
+ # Set the padding scheme for the (CBC mode) cipher
447
+ # (Padding::NONE == :none or Padding::ZERO_BYTE ==
448
+ # :zero_byte).
449
+ def padding=(scheme)
450
+ @padding = Padding::validate(scheme)
451
+ end
452
+
453
+ # Return the cipher's block size in bytes.
454
+ def self.block_size
455
+ BLOCK_SIZE
456
+ end
457
+
458
+ # Encrypt a plaintext string, chunking as required for
459
+ # CBC mode.
460
+ def encrypt(plaintext)
461
+ padded_plaintext = Padding::pad(plaintext, BLOCK_SIZE, self.padding)
462
+ result = ''
463
+ if @mode == Mode::CBC
464
+ @iv = generate_iv(BLOCK_SIZE) unless @iv
465
+ ciphertext_block = @iv
466
+ end
467
+ (0..padded_plaintext.length-1).step(BLOCK_SIZE) do |block_ptr|
468
+ (0..BLOCK_SIZE-1).each { |i| padded_plaintext[block_ptr+i] = ( padded_plaintext[block_ptr+i].ord ^ ciphertext_block[i].ord ).chr } if Mode::CBC == @mode
469
+ result << ciphertext_block = self.encrypt_block(padded_plaintext[block_ptr, BLOCK_SIZE])
470
+ end
471
+ result
472
+ end
473
+
474
+ # Decrypt a ciphertext string, unchunking as required for
475
+ # chaining modes. If @iv is not set then we use the first block
476
+ # as the initialization vector when chaining.
477
+ def decrypt(ciphertext)
478
+ raise ArgumentError, "Ciphertext is not a multiple of #{BLOCK_SIZE} bytes" unless (ciphertext.length % BLOCK_SIZE).zero?
479
+ result = ''
480
+ if Mode::CBC == @mode
481
+ if @iv
482
+ feedback = @iv
483
+ else
484
+ feedback = ciphertext[0, BLOCK_SIZE]
485
+ ciphertext = ciphertext[BLOCK_SIZE..-1]
486
+ end
487
+ end
488
+ (0..ciphertext.length-1).step(BLOCK_SIZE) do |block_ptr|
489
+ ciphertext_block = ciphertext[block_ptr, BLOCK_SIZE]
490
+ plaintext_block = self.decrypt_block(ciphertext_block)
491
+ (0..BLOCK_SIZE-1).each { |i| plaintext_block[i] = (plaintext_block[i].ord ^ feedback[i].ord).chr } if Mode::CBC == @mode
492
+ result << plaintext_block
493
+ feedback = ciphertext_block
494
+ end
495
+ Padding::unpad(result, BLOCK_SIZE, self.padding)
496
+ end
497
+
498
+ # Encrypt a single block (16 bytes).
499
+ def encrypt_block(plain_text)
500
+
501
+ words = plain_text.unpack('V4')
502
+ k = @k
503
+
504
+ r0 = k[0] ^ words[0]
505
+ r1 = k[1] ^ words[1]
506
+ r2 = k[2] ^ words[2]
507
+ r3 = k[3] ^ words[3]
508
+
509
+ xS0, xS1, xS2, xS3 = *@s
510
+
511
+ # i = 0
512
+ t0 = xS0[r0 & 0xff] ^
513
+ xS1[(r0 >> 8) & 0xff] ^
514
+ xS2[(r0 >> 16) & 0xff] ^
515
+ xS3[(r0 >> 24) & 0xff]
516
+ t1 = xS0[(r1 >> 24) & 0xff] ^
517
+ xS1[r1 & 0xff] ^
518
+ xS2[(r1 >> 8) & 0xff] ^
519
+ xS3[(r1 >> 16) & 0xff]
520
+
521
+ r2 ^= mask32(t0 + t1 + k[8])
522
+ r2 = (r2 >> 1 & 0x7fffffff) | mask32(r2 << 31)
523
+
524
+ r3 = ((r3 >> 31) & 1) | mask32(r3 << 1)
525
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[9])
526
+
527
+ t0 = xS0[r2 & 0xff] ^
528
+ xS1[(r2 >> 8) & 0xff] ^
529
+ xS2[(r2 >> 16) & 0xff] ^
530
+ xS3[(r2 >> 24) & 0xff]
531
+ t1 = xS0[(r3 >> 24) & 0xff] ^
532
+ xS1[r3 & 0xff] ^
533
+ xS2[(r3 >> 8) & 0xff] ^
534
+ xS3[(r3 >> 16) & 0xff]
535
+
536
+ r0 ^= mask32(t0 + t1 + k[10])
537
+ r0 = (r0 >> 1 & 0x7fffffff) | mask32(r0 << 31)
538
+
539
+ r1 = ((r1 >> 31) & 1) | mask32(r1 << 1)
540
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[11])
541
+
542
+ # i = 1
543
+ t0 = xS0[r0 & 0xff] ^
544
+ xS1[(r0 >> 8) & 0xff] ^
545
+ xS2[(r0 >> 16) & 0xff] ^
546
+ xS3[(r0 >> 24) & 0xff]
547
+ t1 = xS0[(r1 >> 24) & 0xff] ^
548
+ xS1[r1 & 0xff] ^
549
+ xS2[(r1 >> 8) & 0xff] ^
550
+ xS3[(r1 >> 16) & 0xff]
551
+
552
+ r2 ^= mask32(t0 + t1 + k[12])
553
+ r2 = (r2 >> 1 & 0x7fffffff) | mask32(r2 << 31)
554
+
555
+ r3 = ((r3 >> 31) & 1) | mask32(r3 << 1)
556
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[13])
557
+
558
+ t0 = xS0[r2 & 0xff] ^
559
+ xS1[(r2 >> 8) & 0xff] ^
560
+ xS2[(r2 >> 16) & 0xff] ^
561
+ xS3[(r2 >> 24) & 0xff]
562
+ t1 = xS0[(r3 >> 24) & 0xff] ^
563
+ xS1[r3 & 0xff] ^
564
+ xS2[(r3 >> 8) & 0xff] ^
565
+ xS3[(r3 >> 16) & 0xff]
566
+
567
+ r0 ^= mask32(t0 + t1 + k[14])
568
+ r0 = (r0 >> 1 & 0x7fffffff) | mask32(r0 << 31)
569
+
570
+ r1 = ((r1 >> 31) & 1) | mask32(r1 << 1)
571
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[15])
572
+
573
+ # i = 2
574
+ t0 = xS0[r0 & 0xff] ^
575
+ xS1[(r0 >> 8) & 0xff] ^
576
+ xS2[(r0 >> 16) & 0xff] ^
577
+ xS3[(r0 >> 24) & 0xff]
578
+ t1 = xS0[(r1 >> 24) & 0xff] ^
579
+ xS1[r1 & 0xff] ^
580
+ xS2[(r1 >> 8) & 0xff] ^
581
+ xS3[(r1 >> 16) & 0xff]
582
+
583
+ r2 ^= mask32(t0 + t1 + k[16])
584
+ r2 = (r2 >> 1 & 0x7fffffff) | mask32(r2 << 31)
585
+
586
+ r3 = ((r3 >> 31) & 1) | mask32(r3 << 1)
587
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[17])
588
+
589
+ t0 = xS0[r2 & 0xff] ^
590
+ xS1[(r2 >> 8) & 0xff] ^
591
+ xS2[(r2 >> 16) & 0xff] ^
592
+ xS3[(r2 >> 24) & 0xff]
593
+ t1 = xS0[(r3 >> 24) & 0xff] ^
594
+ xS1[r3 & 0xff] ^
595
+ xS2[(r3 >> 8) & 0xff] ^
596
+ xS3[(r3 >> 16) & 0xff]
597
+
598
+ r0 ^= mask32(t0 + t1 + k[18])
599
+ r0 = (r0 >> 1 & 0x7fffffff) | mask32(r0 << 31)
600
+
601
+ r1 = ((r1 >> 31) & 1) | mask32(r1 << 1)
602
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[19])
603
+
604
+ # i = 3
605
+ t0 = xS0[r0 & 0xff] ^
606
+ xS1[(r0 >> 8) & 0xff] ^
607
+ xS2[(r0 >> 16) & 0xff] ^
608
+ xS3[(r0 >> 24) & 0xff]
609
+ t1 = xS0[(r1 >> 24) & 0xff] ^
610
+ xS1[r1 & 0xff] ^
611
+ xS2[(r1 >> 8) & 0xff] ^
612
+ xS3[(r1 >> 16) & 0xff]
613
+
614
+ r2 ^= mask32(t0 + t1 + k[20])
615
+ r2 = (r2 >> 1 & 0x7fffffff) | mask32(r2 << 31)
616
+
617
+ r3 = ((r3 >> 31) & 1) | mask32(r3 << 1)
618
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[21])
619
+
620
+ t0 = xS0[r2 & 0xff] ^
621
+ xS1[(r2 >> 8) & 0xff] ^
622
+ xS2[(r2 >> 16) & 0xff] ^
623
+ xS3[(r2 >> 24) & 0xff]
624
+ t1 = xS0[(r3 >> 24) & 0xff] ^
625
+ xS1[r3 & 0xff] ^
626
+ xS2[(r3 >> 8) & 0xff] ^
627
+ xS3[(r3 >> 16) & 0xff]
628
+
629
+ r0 ^= mask32(t0 + t1 + k[22])
630
+ r0 = (r0 >> 1 & 0x7fffffff) | mask32(r0 << 31)
631
+
632
+ r1 = ((r1 >> 31) & 1) | mask32(r1 << 1)
633
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[23])
634
+
635
+ # i = 4
636
+ t0 = xS0[r0 & 0xff] ^
637
+ xS1[(r0 >> 8) & 0xff] ^
638
+ xS2[(r0 >> 16) & 0xff] ^
639
+ xS3[(r0 >> 24) & 0xff]
640
+ t1 = xS0[(r1 >> 24) & 0xff] ^
641
+ xS1[r1 & 0xff] ^
642
+ xS2[(r1 >> 8) & 0xff] ^
643
+ xS3[(r1 >> 16) & 0xff]
644
+
645
+ r2 ^= mask32(t0 + t1 + k[24])
646
+ r2 = (r2 >> 1 & 0x7fffffff) | mask32(r2 << 31)
647
+
648
+ r3 = ((r3 >> 31) & 1) | mask32(r3 << 1)
649
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[25])
650
+
651
+ t0 = xS0[r2 & 0xff] ^
652
+ xS1[(r2 >> 8) & 0xff] ^
653
+ xS2[(r2 >> 16) & 0xff] ^
654
+ xS3[(r2 >> 24) & 0xff]
655
+ t1 = xS0[(r3 >> 24) & 0xff] ^
656
+ xS1[r3 & 0xff] ^
657
+ xS2[(r3 >> 8) & 0xff] ^
658
+ xS3[(r3 >> 16) & 0xff]
659
+
660
+ r0 ^= mask32(t0 + t1 + k[26])
661
+ r0 = (r0 >> 1 & 0x7fffffff) | mask32(r0 << 31);
662
+
663
+ r1 = ((r1 >> 31) & 1) | mask32(r1 << 1)
664
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[27])
665
+
666
+ # i = 5
667
+ t0 = xS0[r0 & 0xff] ^
668
+ xS1[(r0 >> 8) & 0xff] ^
669
+ xS2[(r0 >> 16) & 0xff] ^
670
+ xS3[(r0 >> 24) & 0xff]
671
+ t1 = xS0[(r1 >> 24) & 0xff] ^
672
+ xS1[r1 & 0xff] ^
673
+ xS2[(r1 >> 8) & 0xff] ^
674
+ xS3[(r1 >> 16) & 0xff]
675
+
676
+ r2 ^= mask32(t0 + t1 + k[28])
677
+ r2 = (r2 >> 1 & 0x7fffffff) | mask32(r2 << 31)
678
+
679
+ r3 = ((r3 >> 31) & 1) | mask32(r3 << 1)
680
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[29])
681
+
682
+ t0 = xS0[r2 & 0xff] ^
683
+ xS1[(r2 >> 8) & 0xff] ^
684
+ xS2[(r2 >> 16) & 0xff] ^
685
+ xS3[(r2 >> 24) & 0xff]
686
+ t1 = xS0[(r3 >> 24) & 0xff] ^
687
+ xS1[r3 & 0xff] ^
688
+ xS2[(r3 >> 8) & 0xff] ^
689
+ xS3[(r3 >> 16) & 0xff]
690
+
691
+ r0 ^= mask32(t0 + t1 + k[30])
692
+ r0 = (r0 >> 1 & 0x7fffffff) | mask32(r0 << 31)
693
+
694
+ r1 = ((r1 >> 31) & 1) | mask32(r1 << 1)
695
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[31])
696
+
697
+ # i = 6
698
+ t0 = xS0[r0 & 0xff] ^
699
+ xS1[(r0 >> 8) & 0xff] ^
700
+ xS2[(r0 >> 16) & 0xff] ^
701
+ xS3[(r0 >> 24) & 0xff]
702
+ t1 = xS0[(r1 >> 24) & 0xff] ^
703
+ xS1[r1 & 0xff] ^
704
+ xS2[(r1 >> 8) & 0xff] ^
705
+ xS3[(r1 >> 16) & 0xff]
706
+
707
+ r2 ^= mask32(t0 + t1 + k[32])
708
+ r2 = (r2 >> 1 & 0x7fffffff) | mask32(r2 << 31)
709
+
710
+ r3 = ((r3 >> 31) & 1) | mask32(r3 << 1)
711
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[33])
712
+
713
+ t0 = xS0[r2 & 0xff] ^
714
+ xS1[(r2 >> 8) & 0xff] ^
715
+ xS2[(r2 >> 16) & 0xff] ^
716
+ xS3[(r2 >> 24) & 0xff]
717
+ t1 = xS0[(r3 >> 24) & 0xff] ^
718
+ xS1[r3 & 0xff] ^
719
+ xS2[(r3 >> 8) & 0xff] ^
720
+ xS3[(r3 >> 16) & 0xff]
721
+
722
+ r0 ^= mask32(t0 + t1 + k[34])
723
+ r0 = (r0 >> 1 & 0x7fffffff) | mask32(r0 << 31)
724
+
725
+ r1 = ((r1 >> 31) & 1) | mask32(r1 << 1)
726
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[35])
727
+
728
+ # i = 7
729
+ t0 = xS0[r0 & 0xff] ^
730
+ xS1[(r0 >> 8) & 0xff] ^
731
+ xS2[(r0 >> 16) & 0xff] ^
732
+ xS3[(r0 >> 24) & 0xff]
733
+ t1 = xS0[(r1 >> 24) & 0xff] ^
734
+ xS1[r1 & 0xff] ^
735
+ xS2[(r1 >> 8) & 0xff] ^
736
+ xS3[(r1 >> 16) & 0xff]
737
+
738
+ r2 ^= mask32(t0 + t1 + k[36])
739
+ r2 = (r2 >> 1 & 0x7fffffff) | mask32(r2 << 31)
740
+
741
+ r3 = ((r3 >> 31) & 1) | mask32(r3 << 1)
742
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[37])
743
+
744
+ t0 = xS0[r2 & 0xff] ^
745
+ xS1[(r2 >> 8) & 0xff] ^
746
+ xS2[(r2 >> 16) & 0xff] ^
747
+ xS3[(r2 >> 24) & 0xff]
748
+ t1 = xS0[(r3 >> 24) & 0xff] ^
749
+ xS1[r3 & 0xff] ^
750
+ xS2[(r3 >> 8) & 0xff] ^
751
+ xS3[(r3 >> 16) & 0xff]
752
+
753
+ r0 ^= mask32(t0 + t1 + k[38])
754
+ r0 = (r0 >> 1 & 0x7fffffff) | mask32(r0 << 31)
755
+
756
+ r1 = ((r1 >> 31) & 1) | mask32(r1 << 1)
757
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[39])
758
+
759
+ [k[4] ^ r2, k[5] ^ r3, k[6] ^ r0, k[7] ^ r1].pack("V4")
760
+ end
761
+
762
+ # Decrypt a single block (16 bytes).
763
+ def decrypt_block(plain)
764
+ words = plain.unpack("V4")
765
+ k = @k
766
+
767
+ r0 = k[4] ^ words[0]
768
+ r1 = k[5] ^ words[1]
769
+ r2 = k[6] ^ words[2]
770
+ r3 = k[7] ^ words[3]
771
+
772
+ xS0, xS1, xS2, xS3 = *@s
773
+
774
+ # i = 7
775
+ t0 = xS0[r0 & 0xff] ^
776
+ xS1[r0 >> 8 & 0xff] ^
777
+ xS2[r0 >> 16 & 0xff] ^
778
+ xS3[r0 >> 24 & 0xff]
779
+ t1 = xS0[r1 >> 24 & 0xff] ^
780
+ xS1[r1 & 0xff] ^
781
+ xS2[r1 >> 8 & 0xff] ^
782
+ xS3[r1 >> 16 & 0xff]
783
+
784
+ r2 = r2 >> 31 & 0x1 | mask32(r2 << 1)
785
+ r2 ^= mask32(t0 + t1 + k[38])
786
+
787
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[39])
788
+ r3 = r3 >> 1 & 0x7fffffff | mask32(r3 << 31)
789
+
790
+ t0 = xS0[r2 & 0xff] ^
791
+ xS1[r2 >> 8 & 0xff] ^
792
+ xS2[r2 >> 16 & 0xff] ^
793
+ xS3[r2 >> 24 & 0xff]
794
+ t1 = xS0[r3 >> 24 & 0xff] ^
795
+ xS1[r3 & 0xff] ^
796
+ xS2[r3 >> 8 & 0xff] ^
797
+ xS3[r3 >> 16 & 0xff]
798
+
799
+ r0 = r0 >> 31 & 0x1 | mask32(r0 << 1)
800
+ r0 ^= mask32(t0 + t1 + k[36])
801
+
802
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[37])
803
+ r1 = r1 >> 1 & 0x7fffffff | mask32(r1 << 31)
804
+
805
+ # i = 6
806
+ t0 = xS0[r0 & 0xff] ^
807
+ xS1[r0 >> 8 & 0xff] ^
808
+ xS2[r0 >> 16 & 0xff] ^
809
+ xS3[r0 >> 24 & 0xff]
810
+ t1 = xS0[r1 >> 24 & 0xff] ^
811
+ xS1[r1 & 0xff] ^
812
+ xS2[r1 >> 8 & 0xff] ^
813
+ xS3[r1 >> 16 & 0xff]
814
+
815
+ r2 = r2 >> 31 & 0x1 | mask32(r2 << 1)
816
+ r2 ^= mask32(t0 + t1 + k[34])
817
+
818
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[35])
819
+ r3 = r3 >> 1 & 0x7fffffff | mask32(r3 << 31)
820
+
821
+ t0 = xS0[r2 & 0xff] ^
822
+ xS1[r2 >> 8 & 0xff] ^
823
+ xS2[r2 >> 16 & 0xff] ^
824
+ xS3[r2 >> 24 & 0xff]
825
+ t1 = xS0[r3 >> 24 & 0xff] ^
826
+ xS1[r3 & 0xff] ^
827
+ xS2[r3 >> 8 & 0xff] ^
828
+ xS3[r3 >> 16 & 0xff]
829
+
830
+ r0 = r0 >> 31 & 0x1 | mask32(r0 << 1)
831
+ r0 ^= mask32(t0 + t1 + k[32])
832
+
833
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[33])
834
+ r1 = r1 >> 1 & 0x7fffffff | mask32(r1 << 31)
835
+
836
+ # i = 5
837
+ t0 = xS0[r0 & 0xff] ^
838
+ xS1[r0 >> 8 & 0xff] ^
839
+ xS2[r0 >> 16 & 0xff] ^
840
+ xS3[r0 >> 24 & 0xff]
841
+ t1 = xS0[r1 >> 24 & 0xff] ^
842
+ xS1[r1 & 0xff] ^
843
+ xS2[r1 >> 8 & 0xff] ^
844
+ xS3[r1 >> 16 & 0xff]
845
+
846
+ r2 = r2 >> 31 & 0x1 | mask32(r2 << 1)
847
+ r2 ^= mask32(t0 + t1 + k[30])
848
+
849
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[31])
850
+ r3 = r3 >> 1 & 0x7fffffff | mask32(r3 << 31)
851
+
852
+ t0 = xS0[r2 & 0xff] ^
853
+ xS1[r2 >> 8 & 0xff] ^
854
+ xS2[r2 >> 16 & 0xff] ^
855
+ xS3[r2 >> 24 & 0xff]
856
+ t1 = xS0[r3 >> 24 & 0xff] ^
857
+ xS1[r3 & 0xff] ^
858
+ xS2[r3 >> 8 & 0xff] ^
859
+ xS3[r3 >> 16 & 0xff]
860
+
861
+ r0 = r0 >> 31 & 0x1 | mask32(r0 << 1)
862
+ r0 ^= mask32(t0 + t1 + k[28])
863
+
864
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[29])
865
+ r1 = r1 >> 1 & 0x7fffffff | mask32(r1 << 31)
866
+
867
+ # i = 4
868
+ t0 = xS0[r0 & 0xff] ^
869
+ xS1[r0 >> 8 & 0xff] ^
870
+ xS2[r0 >> 16 & 0xff] ^
871
+ xS3[r0 >> 24 & 0xff]
872
+ t1 = xS0[r1 >> 24 & 0xff] ^
873
+ xS1[r1 & 0xff] ^
874
+ xS2[r1 >> 8 & 0xff] ^
875
+ xS3[r1 >> 16 & 0xff]
876
+
877
+ r2 = r2 >> 31 & 0x1 | mask32(r2 << 1)
878
+ r2 ^= mask32(t0 + t1 + k[26])
879
+
880
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[27])
881
+ r3 = r3 >> 1 & 0x7fffffff | mask32(r3 << 31)
882
+
883
+ t0 = xS0[r2 & 0xff] ^
884
+ xS1[r2 >> 8 & 0xff] ^
885
+ xS2[r2 >> 16 & 0xff] ^
886
+ xS3[r2 >> 24 & 0xff]
887
+ t1 = xS0[r3 >> 24 & 0xff] ^
888
+ xS1[r3 & 0xff] ^
889
+ xS2[r3 >> 8 & 0xff] ^
890
+ xS3[r3 >> 16 & 0xff]
891
+
892
+ r0 = r0 >> 31 & 0x1 | mask32(r0 << 1)
893
+ r0 ^= mask32(t0 + t1 + k[24])
894
+
895
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[25])
896
+ r1 = r1 >> 1 & 0x7fffffff | mask32(r1 << 31)
897
+
898
+
899
+ # i = 3
900
+ t0 = xS0[r0 & 0xff] ^
901
+ xS1[r0 >> 8 & 0xff] ^
902
+ xS2[r0 >> 16 & 0xff] ^
903
+ xS3[r0 >> 24 & 0xff]
904
+ t1 = xS0[r1 >> 24 & 0xff] ^
905
+ xS1[r1 & 0xff] ^
906
+ xS2[r1 >> 8 & 0xff] ^
907
+ xS3[r1 >> 16 & 0xff]
908
+
909
+ r2 = r2 >> 31 & 0x1 | mask32(r2 << 1)
910
+ r2 ^= mask32(t0 + t1 + k[22])
911
+
912
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[23])
913
+ r3 = r3 >> 1 & 0x7fffffff | mask32(r3 << 31)
914
+
915
+ t0 = xS0[r2 & 0xff] ^
916
+ xS1[r2 >> 8 & 0xff] ^
917
+ xS2[r2 >> 16 & 0xff] ^
918
+ xS3[r2 >> 24 & 0xff]
919
+ t1 = xS0[r3 >> 24 & 0xff] ^
920
+ xS1[r3 & 0xff] ^
921
+ xS2[r3 >> 8 & 0xff] ^
922
+ xS3[r3 >> 16 & 0xff]
923
+
924
+ r0 = r0 >> 31 & 0x1 | mask32(r0 << 1)
925
+ r0 ^= mask32(t0 + t1 + k[20])
926
+
927
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[21])
928
+ r1 = r1 >> 1 & 0x7fffffff | mask32(r1 << 31)
929
+
930
+ # i = 2
931
+ t0 = xS0[r0 & 0xff] ^
932
+ xS1[r0 >> 8 & 0xff] ^
933
+ xS2[r0 >> 16 & 0xff] ^
934
+ xS3[r0 >> 24 & 0xff]
935
+ t1 = xS0[r1 >> 24 & 0xff] ^
936
+ xS1[r1 & 0xff] ^
937
+ xS2[r1 >> 8 & 0xff] ^
938
+ xS3[r1 >> 16 & 0xff]
939
+
940
+ r2 = r2 >> 31 & 0x1 | mask32(r2 << 1)
941
+ r2 ^= mask32(t0 + t1 + k[18])
942
+
943
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[19])
944
+ r3 = r3 >> 1 & 0x7fffffff | mask32(r3 << 31)
945
+
946
+ t0 = xS0[r2 & 0xff] ^
947
+ xS1[r2 >> 8 & 0xff] ^
948
+ xS2[r2 >> 16 & 0xff] ^
949
+ xS3[r2 >> 24 & 0xff]
950
+ t1 = xS0[r3 >> 24 & 0xff] ^
951
+ xS1[r3 & 0xff] ^
952
+ xS2[r3 >> 8 & 0xff] ^
953
+ xS3[r3 >> 16 & 0xff]
954
+
955
+ r0 = r0 >> 31 & 0x1 | mask32(r0 << 1)
956
+ r0 ^= mask32(t0 + t1 + k[16])
957
+
958
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[17])
959
+ r1 = r1 >> 1 & 0x7fffffff | mask32(r1 << 31)
960
+
961
+ # i = 1
962
+ t0 = xS0[r0 & 0xff] ^
963
+ xS1[r0 >> 8 & 0xff] ^
964
+ xS2[r0 >> 16 & 0xff] ^
965
+ xS3[r0 >> 24 & 0xff]
966
+ t1 = xS0[r1 >> 24 & 0xff] ^
967
+ xS1[r1 & 0xff] ^
968
+ xS2[r1 >> 8 & 0xff] ^
969
+ xS3[r1 >> 16 & 0xff]
970
+
971
+ r2 = r2 >> 31 & 0x1 | mask32(r2 << 1)
972
+ r2 ^= mask32(t0 + t1 + k[14])
973
+
974
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[15])
975
+ r3 = r3 >> 1 & 0x7fffffff | mask32(r3 << 31)
976
+
977
+ t0 = xS0[r2 & 0xff] ^
978
+ xS1[r2 >> 8 & 0xff] ^
979
+ xS2[r2 >> 16 & 0xff] ^
980
+ xS3[r2 >> 24 & 0xff]
981
+ t1 = xS0[r3 >> 24 & 0xff] ^
982
+ xS1[r3 & 0xff] ^
983
+ xS2[r3 >> 8 & 0xff] ^
984
+ xS3[r3 >> 16 & 0xff]
985
+
986
+ r0 = r0 >> 31 & 0x1 | mask32(r0 << 1)
987
+ r0 ^= mask32(t0 + t1 + k[12])
988
+
989
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[13])
990
+ r1 = r1 >> 1 & 0x7fffffff | mask32(r1 << 31)
991
+
992
+ # i = 0
993
+ t0 = xS0[r0 & 0xff] ^
994
+ xS1[r0 >> 8 & 0xff] ^
995
+ xS2[r0 >> 16 & 0xff] ^
996
+ xS3[r0 >> 24 & 0xff]
997
+ t1 = xS0[r1 >> 24 & 0xff] ^
998
+ xS1[r1 & 0xff] ^
999
+ xS2[r1 >> 8 & 0xff] ^
1000
+ xS3[r1 >> 16 & 0xff]
1001
+
1002
+ r2 = r2 >> 31 & 0x1 | mask32(r2 << 1)
1003
+ r2 ^= mask32(t0 + t1 + k[10])
1004
+
1005
+ r3 ^= mask32(t0 + mask32(t1 << 1) + k[11])
1006
+ r3 = r3 >> 1 & 0x7fffffff | mask32(r3 << 31)
1007
+
1008
+ t0 = xS0[r2 & 0xff] ^
1009
+ xS1[r2 >> 8 & 0xff] ^
1010
+ xS2[r2 >> 16 & 0xff] ^
1011
+ xS3[r2 >> 24 & 0xff]
1012
+ t1 = xS0[r3 >> 24 & 0xff] ^
1013
+ xS1[r3 & 0xff] ^
1014
+ xS2[r3 >> 8 & 0xff] ^
1015
+ xS3[r3 >> 16 & 0xff]
1016
+
1017
+ r0 = r0 >> 31 & 0x1 | mask32(r0 << 1)
1018
+ r0 ^= mask32(t0 + t1 + k[8])
1019
+
1020
+ r1 ^= mask32(t0 + mask32(t1 << 1) + k[9])
1021
+ r1 = r1 >> 1 & 0x7fffffff | mask32(r1 << 31)
1022
+
1023
+ [mask32(k[0] ^ r2), mask32(k[1] ^ r3), mask32(k[2] ^ r0), mask32(k[3] ^ r1)].pack("V4")
1024
+ end
1025
+
1026
+ private
1027
+
1028
+ # The (12, 8) Reed Solomon code has the generator polynomial:
1029
+ #
1030
+ # g(x) = x^4 + (a + 1/a) * x^3 + a * x^2 + (a + 1/a) * x + 1
1031
+ #
1032
+ # where the coefficients are in the finite field GF(2^8) with a modular
1033
+ # polynomial a^8+a^6+a^3+a^2+1. To generate the remainder, we have to
1034
+ # start with a 12th order polynomial with our eight input bytes as the
1035
+ # coefficients of the 4th to 11th terms:
1036
+ #
1037
+ # m[7] * x^11 + m[6] * x^10 ... + m[0] * x^4 + 0 * x^3 +... + 0
1038
+ #
1039
+ # We then multiply the generator polynomial by m[7]*x^7 and subtract it
1040
+ # (XOR in GF(2^8)) from the above to eliminate the x^7 term (the
1041
+ # arithmetic on the coefficients is done in GF(2^8)). We then multiply
1042
+ # the generator polynomial by m[6]*x^6 and use this to remove the x^10
1043
+ # term, and so on until the x^4 term is removed, and we are left with:
1044
+ #
1045
+ # r[3] * x^3 + r[2] * x^2 + r[1] 8 x^1 + r[0]
1046
+ #
1047
+ # which give the resulting 4 bytes of the remainder. This is equivalent
1048
+ # to the matrix multiplication described in the Twofish paper, but is
1049
+ # much faster.
1050
+ def mds_rem(a, b)
1051
+
1052
+ # use constant G_MOD => 0x14d
1053
+
1054
+ t, u = 0, 0
1055
+
1056
+ # No gain by unrolling this loop.
1057
+ 8.times do
1058
+ t = b >> 24
1059
+
1060
+ # Shift the others up.
1061
+ b = mask32(b << 8) | (a >> 24)
1062
+ a = mask32(a << 8)
1063
+
1064
+ u = mask32(t << 1)
1065
+
1066
+ # Subtract the modular polynomial on overflow.
1067
+ u ^= 0x14d unless (t & 0x80).zero?
1068
+
1069
+ # Remove t * (a * x^2 + 1).
1070
+ b ^= t ^ mask32(u << 16)
1071
+
1072
+ # Form u = a*t + t/a = t*(a + 1/a).
1073
+ u ^= 0x7fffffff & (t >> 1)
1074
+
1075
+ # Add the modular polynomial on underflow.
1076
+ u ^= 0xa6 unless (t & 0x01).zero?
1077
+
1078
+ # Remove t * (a + 1/a) * (x^3 + x).
1079
+ b ^= mask32(u << 24) | mask32(u << 8)
1080
+
1081
+ end
1082
+
1083
+ [ b >> 24, b >> 16 & 0xff, b >> 8 & 0xff, b & 0xff ]
1084
+ end
1085
+
1086
+ # Retain only lowest 32 bits of the given integer.
1087
+ def mask32(x)
1088
+ x & 0xffffffff
1089
+ end
1090
+
1091
+ # Generates a random initialization vector of the given length.
1092
+ # Warning: use Ruby standard library Kernel#rand.
1093
+ def generate_iv(block_size)
1094
+ Array.new(block_size).
1095
+ map{ |x| rand(256) }.
1096
+ pack("C#{block_size}")
1097
+ end
1098
+
1099
+ end
1100
+
1101
+ # Encryption modes.
1102
+ #
1103
+ # The only currently implemented modes are ECB (Electronic Code Book)
1104
+ # and CBC (Cipher Block Chaining).
1105
+ module Mode
1106
+
1107
+ ECB = :ecb
1108
+ CBC = :cbc
1109
+ ALL = [ CBC, ECB ]
1110
+ DEFAULT = ECB
1111
+
1112
+ # Takes a string or symbol and returns the lowercased
1113
+ # symbol representation if this is a recognized mode.
1114
+ # Otherwise, throws ArgumentError.
1115
+ def Mode::validate(mode)
1116
+ mode_sym = mode.nil? ? DEFAULT : mode.to_s.downcase.to_sym
1117
+ raise ArgumentError, "unknown cipher mode #{mode.inspect}" unless ALL.include? mode_sym
1118
+ mode_sym
1119
+ end
1120
+
1121
+ end
1122
+
1123
+ # Implements padding modes to make plaintext into a complete
1124
+ # number of blocks before encryption and to remove that padding
1125
+ # after successful decryption.
1126
+ #
1127
+ # The only implemented padding schemes are :none and
1128
+ # :zero_byte. Note that zero byte padding is potentially
1129
+ # dangerous because if the plaintext terminates in
1130
+ # zero bytes then these will be erroneously removed by #unpad.
1131
+ # A more sensible padding scheme should be used in this case.
1132
+ module Padding
1133
+
1134
+ NONE = :none
1135
+ ZERO_BYTE = :zero_byte
1136
+ ALL = [ NONE, ZERO_BYTE ]
1137
+ DEFAULT = NONE
1138
+
1139
+ # Takes a string or symbol and returns the lowercased
1140
+ # symbol representation if this is a recognized padding scheme.
1141
+ # Otherwise, throws ArgumentError.
1142
+ def Padding::validate(scheme)
1143
+ scheme_sym = scheme.nil? ? DEFAULT : scheme.to_s.downcase.to_sym
1144
+ raise ArgumentError, "unknown padding scheme #{scheme.inspect}" unless ALL.include? scheme_sym
1145
+ scheme_sym
1146
+ end
1147
+
1148
+ # Pad the given plaintext to a complete number of blocks. If
1149
+ # the padding scheme is :none and the plaintext is not a whole
1150
+ # number of blocks then ArgumentError is thrown.
1151
+ def Padding::pad(plaintext, block_size, scheme=DEFAULT)
1152
+ scheme_sym = validate(scheme)
1153
+ remainder = plaintext.length % block_size
1154
+ case scheme_sym
1155
+ when NONE
1156
+ raise ArgumentError, "no padding scheme specified and plaintext length is not a multiple of the block size" unless remainder.zero?
1157
+ plaintext.dup
1158
+ when ZERO_BYTE
1159
+ unless remainder.zero?
1160
+ plaintext.dup << "\0" * (block_size - remainder)
1161
+ end
1162
+ end
1163
+ end
1164
+
1165
+ # Unpad the given plaintext using the given scheme.
1166
+ def Padding::unpad(plaintext, block_size, scheme=DEFAULT)
1167
+ scheme_sym = validate(scheme)
1168
+ case scheme_sym
1169
+ when NONE
1170
+ plaintext.dup
1171
+ when ZERO_BYTE
1172
+ plaintext.dup.sub(/\000+\Z/, '')
1173
+ end
1174
+ end
1175
+
1176
+ end
1177
+