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