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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a9160fa2fe6f0007b1e73557465ba662b23e3949
4
- data.tar.gz: 7baca819819c90a0f0322966d56198fad0bc1cf5
3
+ metadata.gz: 00b2bbf43d9b32ff9b0e8eed4a21195deba38bd7
4
+ data.tar.gz: 6b23d440cb0cac34cbba9c37062ab51ce168b4f3
5
5
  SHA512:
6
- metadata.gz: eec83be529fbc82970ec9d2c3ccbe19e156058d850f596237254c7dbefa18e5c478415c9d9351c6e0f8e0bc3bfa3f00f73bf617020c12e6fcc56f23f1bbb03ab
7
- data.tar.gz: bd3f3529f3093bc3020a728775383dca129b5496f459b4d375aca6467959dd0654d6f4d375a4bd816ff0f04f7c6419942e8a4ef95252a8d778d59dc6458ec8c2
6
+ metadata.gz: f591af29855dce80ccd4f922f146a5ad7bb43cd1b3eba07826f34df0e3ebf605f680eeea7d690538cb5ca9c11e5473355040a103ec1e25d15e1387821309381e
7
+ data.tar.gz: 81a586774968b3511354de8979944949e55232d470cd033a2190fdf2b622a7524eefcd7e710fb4f0bc69d62fe503eb8b61980b14b048e1d4e0d74b6c240e6fc1
@@ -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
@@ -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] || generate_iv(BLOCK_SIZE) unless @mode == Mode::ECB
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 = generate_iv(BLOCK_SIZE) unless @iv
478
- ciphertext_block = @iv
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, ciphertext_block) if Mode::CBC == @mode
483
- result << ciphertext_block = encrypt_block(plaintext_block)
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
- feedback = @iv
498
+ @_feedback ||= @iv
498
499
  else
499
- feedback = ciphertext[0, BLOCK_SIZE]
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, feedback) if Mode::CBC == @mode
507
+ xor_block!(plaintext_block, @_feedback) if Mode::CBC == @mode
507
508
  result << plaintext_block
508
- feedback = ciphertext_block
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
 
@@ -135,13 +135,8 @@ end
135
135
  # Test the Cipher Block Chaining mode.
136
136
  class TestCbcEncryption < TestBasics
137
137
 
138
- # 123456781234567812345678123456781234567812
139
- #LONG_PLAINTEXT = 'this message is longer than the block size'
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.5
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: 2014-05-22 00:00:00.000000000 Z
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