twofish 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.rdoc +0 -4
- data/lib/twofish.rb +15 -17
- data/test/test_twofish.rb +22 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00b2bbf43d9b32ff9b0e8eed4a21195deba38bd7
|
4
|
+
data.tar.gz: 6b23d440cb0cac34cbba9c37062ab51ce168b4f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f591af29855dce80ccd4f922f146a5ad7bb43cd1b3eba07826f34df0e3ebf605f680eeea7d690538cb5ca9c11e5473355040a103ec1e25d15e1387821309381e
|
7
|
+
data.tar.gz: 81a586774968b3511354de8979944949e55232d470cd033a2190fdf2b622a7524eefcd7e710fb4f0bc69d62fe503eb8b61980b14b048e1d4e0d74b6c240e6fc1
|
data/README.rdoc
CHANGED
@@ -115,10 +115,6 @@ to move to byte arrays throughout.
|
|
115
115
|
Possible implementation-dependent timing attacks (Bignum promotion,
|
116
116
|
#pack(), ...).
|
117
117
|
|
118
|
-
If no initialization vector is provided for CBC mode then the system
|
119
|
-
random number generator (Kernel#rand) is used to generate one. The system
|
120
|
-
random number generator may be weaker than desired.
|
121
|
-
|
122
118
|
The IV is not silently prepended to the ciphertext since if
|
123
119
|
the resulting ciphertext is transmitted as is this can introduce
|
124
120
|
a weakness. IV should ideally be transmitted OOB. There
|
data/lib/twofish.rb
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
# encryption algorithm based on original work by Guido Flohr.
|
9
9
|
class Twofish
|
10
10
|
|
11
|
+
require 'securerandom'
|
11
12
|
require 'string' # monkey patch for MRI 1.8.7
|
12
13
|
require 'twofish/mode'
|
13
14
|
require 'twofish/padding'
|
@@ -306,7 +307,7 @@ class Twofish
|
|
306
307
|
|
307
308
|
self.mode = opts[:mode] # use setter for validation
|
308
309
|
self.padding = opts[:padding] # use setter for validation
|
309
|
-
@iv = opts[:iv] ||
|
310
|
+
@iv = opts[:iv] || SecureRandom.random_bytes(BLOCK_SIZE) unless @mode == Mode::ECB
|
310
311
|
|
311
312
|
# The key consists of k=len/8 (2, 3 or 4) 64-bit units.
|
312
313
|
key = key_string.unpack("C*")
|
@@ -474,13 +475,13 @@ class Twofish
|
|
474
475
|
padded_plaintext = Padding.pad!(plaintext, BLOCK_SIZE, @padding)
|
475
476
|
result = ''.force_encoding('ASCII-8BIT')
|
476
477
|
if @mode == Mode::CBC
|
477
|
-
@iv
|
478
|
-
|
478
|
+
@iv ||= SecureRandom.random_bytes(BLOCK_SIZE)
|
479
|
+
@_feedback ||= @iv
|
479
480
|
end
|
480
481
|
(0...padded_plaintext.length).step(BLOCK_SIZE) do |block_ptr|
|
481
482
|
plaintext_block = padded_plaintext[block_ptr, BLOCK_SIZE]
|
482
|
-
xor_block!(plaintext_block,
|
483
|
-
result <<
|
483
|
+
xor_block!(plaintext_block, @_feedback) if Mode::CBC == @mode
|
484
|
+
result << @_feedback = encrypt_block(plaintext_block)
|
484
485
|
end
|
485
486
|
result
|
486
487
|
end
|
@@ -494,22 +495,27 @@ class Twofish
|
|
494
495
|
result = ''.force_encoding('ASCII-8BIT')
|
495
496
|
if Mode::CBC == @mode
|
496
497
|
if @iv
|
497
|
-
|
498
|
+
@_feedback ||= @iv
|
498
499
|
else
|
499
|
-
|
500
|
+
@_feedback ||= ciphertext[0, BLOCK_SIZE]
|
500
501
|
ciphertext = ciphertext[BLOCK_SIZE..-1]
|
501
502
|
end
|
502
503
|
end
|
503
504
|
(0...ciphertext.length).step(BLOCK_SIZE) do |block_ptr|
|
504
505
|
ciphertext_block = ciphertext[block_ptr, BLOCK_SIZE]
|
505
506
|
plaintext_block = decrypt_block(ciphertext_block)
|
506
|
-
xor_block!(plaintext_block,
|
507
|
+
xor_block!(plaintext_block, @_feedback) if Mode::CBC == @mode
|
507
508
|
result << plaintext_block
|
508
|
-
|
509
|
+
@_feedback = ciphertext_block
|
509
510
|
end
|
510
511
|
Padding.unpad!(result, BLOCK_SIZE, @padding)
|
511
512
|
end
|
512
513
|
|
514
|
+
# Reset the cipher state (for feedback modes).
|
515
|
+
def reset!
|
516
|
+
@_feedback = nil
|
517
|
+
end
|
518
|
+
|
513
519
|
# Exclusive-or two blocks together, byte-by-byte, storing the result
|
514
520
|
# in the first block.
|
515
521
|
def xor_block!(target, source)
|
@@ -1098,13 +1104,5 @@ private
|
|
1098
1104
|
[b >> 24, b >> 16 & 0xff, b >> 8 & 0xff, b & 0xff]
|
1099
1105
|
end
|
1100
1106
|
|
1101
|
-
# Generates a random initialization vector of the given length.
|
1102
|
-
# Warning: use Ruby standard library Kernel#rand.
|
1103
|
-
def generate_iv(block_size)
|
1104
|
-
Array.new(block_size).
|
1105
|
-
map{ |x| rand(256) }.
|
1106
|
-
pack("C#{block_size}") # defaults to ASCII-8BIT encoding
|
1107
|
-
end
|
1108
|
-
|
1109
1107
|
end
|
1110
1108
|
|
data/test/test_twofish.rb
CHANGED
@@ -135,13 +135,8 @@ end
|
|
135
135
|
# Test the Cipher Block Chaining mode.
|
136
136
|
class TestCbcEncryption < TestBasics
|
137
137
|
|
138
|
-
|
139
|
-
|
140
|
-
#LONG_CIPHERTEXT = ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'].pack('H*')
|
141
|
-
#KEY = ['5d9d4eeffa9151575524f115815a12e0'].pack('H*')
|
142
|
-
#IV = ['e75449212beef9f4a390bd860a640941'].pack('H*')
|
143
|
-
LONG_PLAINTEXT = ("\0"*32).freeze
|
144
|
-
LONG_CIPHERTEXT = ['9f589f5cf6122c32b6bfec2f2ae8c35ad491db16e7b1c39e86cb086b789f5419'].pack('H*').freeze
|
138
|
+
LONG_PLAINTEXT = ("\0"*64).freeze
|
139
|
+
LONG_CIPHERTEXT = ['9f589f5cf6122c32b6bfec2f2ae8c35ad491db16e7b1c39e86cb086b789f541905ef8c61a811582634ba5cb7106aa6416748d17e67848a7ac57a1033d3dcef56'].pack('H*').freeze
|
145
140
|
|
146
141
|
def test_encryption_decryption_random_iv
|
147
142
|
tf = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc)
|
@@ -175,6 +170,26 @@ class TestCbcEncryption < TestBasics
|
|
175
170
|
assert_equal(plaintext, tf2.decrypt(ciphertext))
|
176
171
|
end
|
177
172
|
|
173
|
+
def test_reset
|
174
|
+
tf = Twofish.new(NULL_KEY_16_BYTES, :mode => :cbc, :padding => :pkcs7)
|
175
|
+
iv = tf.iv
|
176
|
+
ciphertext = tf.encrypt(LONG_PLAINTEXT)
|
177
|
+
assert_not_equal(LONG_PLAINTEXT, tf.decrypt(ciphertext))
|
178
|
+
tf.reset!
|
179
|
+
assert_equal(iv, tf.iv)
|
180
|
+
assert_equal(LONG_PLAINTEXT, tf.decrypt(ciphertext))
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_incremental
|
184
|
+
key = ['9f589f5cf6122c32b6bfec2f2ae8c35a'].pack('H*').freeze
|
185
|
+
iv = ['a74f3ed9a33ca158f3d09a629f9b26ba'].pack('H*').freeze
|
186
|
+
data = %w{ abcdefghijklmnop qrstuvwxyz123456 }
|
187
|
+
tf = Twofish.new(key, :iv => iv, :mode => :cbc)
|
188
|
+
result = data.inject('') { |ciphertext, block| ciphertext << tf.encrypt(block) }
|
189
|
+
assert_equal(["e14d0f030aa843b14b616928a1c18e8b76c008aa27015dd21bb747a18715172a"].pack('H*'),
|
190
|
+
result)
|
191
|
+
end
|
192
|
+
|
178
193
|
end
|
179
194
|
|
180
195
|
class TestInitializationVector < TestBasics
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twofish
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Carpenter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-09-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Twofish symmetric cipher in pure Ruby with ECB and CBC cipher modes derived
|
14
14
|
from an original Perl implementation by Guido Flohr
|