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
@@ -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
+