twofish 1.0.5 → 1.0.6
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.
- 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
|