twofish 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,290 @@
1
+
2
+ require 'test/unit'
3
+ require 'twofish'
4
+
5
+ # Define some useful constants and test some basic properties.
6
+ class TestBasics < Test::Unit::TestCase
7
+
8
+ NULL_KEY_16_BYTES = ("\0" * 16).freeze
9
+ NULL_KEY_24_BYTES = ("\0" * 24).freeze
10
+ NULL_KEY_32_BYTES = ("\0" * 32).freeze
11
+ NULL_BLOCK = ("\0" * Twofish::BLOCK_SIZE).freeze
12
+ BLOCK_SIZE = Twofish::BLOCK_SIZE
13
+
14
+ def test_16_byte_key_size
15
+ tf = Twofish.new(NULL_KEY_16_BYTES)
16
+ assert_equal(tf.key_size, 16)
17
+ end
18
+
19
+ def test_24_byte_key_size
20
+ tf = Twofish.new(NULL_KEY_24_BYTES)
21
+ assert_equal(tf.key_size, 24)
22
+ end
23
+
24
+ def test_32_byte_key_size
25
+ tf = Twofish.new(NULL_KEY_32_BYTES)
26
+ assert_equal(tf.key_size, 32)
27
+ end
28
+
29
+ def test_invalid_key_size
30
+ assert_raise ArgumentError do
31
+ Twofish.new('short key')
32
+ end
33
+ end
34
+
35
+ def test_block_size
36
+ assert(16, BLOCK_SIZE)
37
+ end
38
+
39
+ def test_default_mode
40
+ assert_equal(Mode::DEFAULT, Mode::ECB)
41
+ end
42
+
43
+ end
44
+
45
+ # Test the encryption vectors as given in the specification
46
+ # using block encryption (Electronic Code Book mode).
47
+ # On the way we check that each encrypted block successfully
48
+ # decrypts to the given plaintext.
49
+ class TestEcbEncryption < TestBasics
50
+
51
+ def test_16_byte_key_encryption
52
+ assert_equal(
53
+ pack_bytes('5d9d4eeffa9151575524f115815a12e0'),
54
+ repeated_block_encrypt(NULL_KEY_16_BYTES, NULL_BLOCK, 49)
55
+ )
56
+ end
57
+
58
+ def test_24_byte_key_encryption
59
+ assert_equal(
60
+ pack_bytes('e75449212beef9f4a390bd860a640941'),
61
+ repeated_block_encrypt(NULL_KEY_24_BYTES, NULL_BLOCK, 49)
62
+ )
63
+ end
64
+
65
+ def test_32_byte_key_encryption
66
+ assert_equal(
67
+ pack_bytes('37fe26ff1cf66175f5ddf4c33b97a205'),
68
+ repeated_block_encrypt(NULL_KEY_32_BYTES, NULL_BLOCK, 49)
69
+ )
70
+ end
71
+
72
+ def test_padding_exception
73
+ plaintext = 'short' # < BLOCKSIZE == 16 bytes
74
+ key = pack_bytes('37fe26ff1cf66175f5ddf4c33b97a205')
75
+ tf = Twofish.new(key)
76
+ assert_raise ArgumentError do
77
+ ciphertext = tf.encrypt(plaintext)
78
+ end
79
+ end
80
+
81
+ def test_null_in_plaintext
82
+ plaintext = "xxxxxxx\0\0yyyyyyy"
83
+ key = pack_bytes('37fe26ff1cf66175f5ddf4c33b97a205')
84
+ tf = Twofish.new(key)
85
+ ciphertext = tf.encrypt(plaintext)
86
+ assert_equal(plaintext, tf.decrypt(ciphertext))
87
+ end
88
+
89
+ private
90
+
91
+ # Convert ASCII hex representation into binary.
92
+ def pack_bytes(byte_string)
93
+ [byte_string].pack('H*')
94
+ end
95
+
96
+ # Repeatedly encrypt the given plain text n times
97
+ # with the same key.
98
+ def repeated_block_encrypt(key, plain, iterations)
99
+ key_length = key.length
100
+ iterations.times do
101
+ tf = Twofish.new(key)
102
+ cipher = tf.encrypt(plain)
103
+ assert_equal(plain, tf.decrypt(cipher))
104
+ key = (plain + key)[0, key_length]
105
+ plain = cipher
106
+ end
107
+ plain
108
+ end
109
+
110
+ end
111
+
112
+ # Test the Cipher Block Chaining mode.
113
+ class TestCbcEncryption < TestBasics
114
+
115
+ # 123456781234567812345678123456781234567812
116
+ #LONG_PLAINTEXT = 'this message is longer than the block size'
117
+ #LONG_CIPHERTEXT = ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'].pack('H*')
118
+ #KEY = ['5d9d4eeffa9151575524f115815a12e0'].pack('H*')
119
+ #IV = ['e75449212beef9f4a390bd860a640941'].pack('H*')
120
+ LONG_PLAINTEXT = ("\0"*32).freeze
121
+ LONG_CIPHERTEXT = ['9f589f5cf6122c32b6bfec2f2ae8c35ad491db16e7b1c39e86cb086b789f5419'].pack('H*').freeze
122
+
123
+ def test_encryption_decryption_random_iv
124
+ tf = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc)
125
+ ciphertext = tf.encrypt(LONG_PLAINTEXT)
126
+ iv = tf.iv
127
+ tf2 = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc, :iv => iv)
128
+ assert_equal(LONG_PLAINTEXT, tf2.decrypt(ciphertext))
129
+ end
130
+
131
+ def test_encryption_given_null_iv
132
+ tf = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc, :iv => NULL_BLOCK)
133
+ ciphertext = tf.encrypt(LONG_PLAINTEXT)
134
+ assert_equal(LONG_PLAINTEXT.size, ciphertext.size)
135
+ assert_equal(LONG_CIPHERTEXT, ciphertext)
136
+ end
137
+
138
+ def test_decryption_given_null_iv
139
+ tf = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc, :iv => NULL_BLOCK)
140
+ assert_equal(LONG_PLAINTEXT, tf.decrypt(LONG_CIPHERTEXT))
141
+ end
142
+
143
+ def test_encryption_decryption_incomplete_block
144
+ tf1 = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc, :padding => :zero_byte)
145
+ plaintext = 'abcdefghijklmnopqrst'
146
+ ciphertext = tf1.encrypt(plaintext)
147
+ iv = tf1.iv
148
+ tf2 = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc, :iv => iv, :padding => :zero_byte)
149
+ assert_equal(plaintext, tf2.decrypt(ciphertext))
150
+ end
151
+
152
+ end
153
+
154
+ class TestInitializationVector < TestBasics
155
+
156
+ def test_nil_iv_for_ecb_mode
157
+ tf = Twofish.new(NULL_KEY_16_BYTES, :mode => :ecb)
158
+ assert_equal(nil, tf.iv)
159
+ end
160
+
161
+ def test_cannot_assign_iv_ecb_mode
162
+ tf = Twofish.new(NULL_KEY_16_BYTES, :mode => :ecb)
163
+ assert_raise ArgumentError do
164
+ tf.iv = '1234567812345678'
165
+ end
166
+ end
167
+
168
+ def test_assign_bad_iv
169
+ tf = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc)
170
+ assert_raise ArgumentError do
171
+ tf.iv = '1234'
172
+ end
173
+ end
174
+
175
+ def test_generated_length
176
+ tf = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc)
177
+ assert_equal(BLOCK_SIZE, tf.iv.length)
178
+ end
179
+
180
+ def test_generated_not_srand
181
+ tf1 = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc)
182
+ tf2 = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc)
183
+ assert_not_equal(tf1.iv, tf2.iv)
184
+ end
185
+
186
+ end
187
+
188
+ # Test the available encryption modes.
189
+ class TestModes < TestBasics
190
+
191
+ def test_default_mode
192
+ tf = Twofish.new(NULL_KEY_16_BYTES)
193
+ assert_equal(:ecb, tf.mode)
194
+ end
195
+
196
+ def test_unknown_mode
197
+ assert_raise ArgumentError do
198
+ tf = Twofish.new(NULL_KEY_16_BYTES)
199
+ tf.mode = :unknown
200
+ end
201
+ end
202
+
203
+ def test_unknown_mode_constructor
204
+ assert_raise ArgumentError do
205
+ Twofish.new(NULL_KEY_16_BYTES, :mode => :unknown)
206
+ end
207
+ end
208
+
209
+ def test_cbc_mode_constructor_string
210
+ tf = Twofish.new(NULL_KEY_16_BYTES, :mode => 'cbc')
211
+ assert_equal(:cbc, tf.mode)
212
+ end
213
+
214
+ def test_cbc_mode_constructor_symbol
215
+ tf = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc)
216
+ assert_equal(:cbc, tf.mode)
217
+ end
218
+
219
+ def test_ecb_mode
220
+ tf = Twofish.new(NULL_KEY_16_BYTES)
221
+ tf.mode = :ecb
222
+ assert_equal(:ecb, tf.mode)
223
+ end
224
+
225
+ def test_cbc_mode
226
+ tf = Twofish.new(NULL_KEY_16_BYTES)
227
+ tf.mode = :cbc
228
+ assert_equal(:cbc, tf.mode)
229
+ end
230
+
231
+ def test_symbolize_mode
232
+ tf = Twofish.new(NULL_KEY_16_BYTES)
233
+ tf.mode = 'ecb'
234
+ assert_equal(:ecb, tf.mode)
235
+ end
236
+
237
+ end
238
+
239
+ class TestPadding < TestBasics
240
+
241
+ TO_PAD = 'abcdef'.freeze
242
+
243
+ def test_cipher_zero_byte_padding
244
+ tf = Twofish.new(NULL_KEY_16_BYTES)
245
+ tf.padding = :zero_byte
246
+ assert_equal(:zero_byte, tf.padding)
247
+ end
248
+
249
+ def test_cipher_zero_byte_padding_constructor
250
+ tf = Twofish.new(NULL_KEY_16_BYTES, :padding => :zero_byte)
251
+ assert_equal(:zero_byte, tf.padding)
252
+ end
253
+
254
+ def test_cipher_unknown_padding
255
+ tf = Twofish.new(NULL_KEY_16_BYTES)
256
+ assert_raise ArgumentError do
257
+ tf.padding = :unknown
258
+ end
259
+ end
260
+
261
+ def test_cipher_unknown_padding_constructor
262
+ assert_raise ArgumentError do
263
+ Twofish.new(NULL_KEY_16_BYTES, :padding => :unknown)
264
+ end
265
+ end
266
+
267
+ def test_symbolize_padding
268
+ assert_equal(:zero_byte, Padding::validate('zero_byte'))
269
+ end
270
+
271
+ def test_pad_none
272
+ assert_raise ArgumentError do
273
+ Padding::pad(TO_PAD, BLOCK_SIZE, :none)
274
+ end
275
+ end
276
+
277
+ def test_unpad_none
278
+ assert_equal(TO_PAD+"\0"*10, Padding::unpad(TO_PAD+"\0"*10, BLOCK_SIZE, :none))
279
+ end
280
+
281
+ def test_pad_zero_byte
282
+ assert_equal(TO_PAD+"\0"*10, Padding::pad(TO_PAD, BLOCK_SIZE, :zero_byte))
283
+ end
284
+
285
+ def test_unpad_zero_byte
286
+ assert_equal(TO_PAD, Padding::unpad(TO_PAD+"\0"*10, BLOCK_SIZE, :zero_byte))
287
+ end
288
+
289
+ end
290
+
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: twofish
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Martin Carpenter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-11-26 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Twofish symmetric cipher in pure Ruby with ECB and CBC cipher modes derived from an original Perl implementation by Guido Flohr
17
+ email: mcarpenter@free.fr
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - Rakefile
25
+ - README.rdoc
26
+ files:
27
+ - lib/twofish.rb
28
+ - test/test_twofish.rb
29
+ - LICENSE
30
+ - Rakefile
31
+ - README.rdoc
32
+ has_rdoc: true
33
+ homepage: http://mcarpenter.org/projects/twofish
34
+ licenses:
35
+ - BSD
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.3.5
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Twofish symmetric cipher in pure Ruby
60
+ test_files: []
61
+