Module: Twofish::Padding

Defined in:
lib/twofish/padding.rb

Overview

Implements padding modes to make plaintext into a complete number of blocks before encryption and to remove that padding after successful decryption.

The only implemented padding schemes are :none and :zero_byte. Note that zero byte padding is potentially dangerous because if the plaintext terminates in zero bytes then these will be erroneously removed by #unpad. A more sensible padding scheme should be used in this case.

Constant Summary collapse

NONE =

Use no padding.

:none
ZERO_BYTE =

Use zero byte padding.

:zero_byte
ISO10126_2 =

Use ISO 10126-2 padding.

:iso10126_2
PKCS7 =

Use PKCS7 byte padding.

:pkcs7
ALL =

Array of all known paddings.

[NONE, ZERO_BYTE, ISO10126_2, PKCS7]
DEFAULT =

Default padding (none).

NONE

Class Method Summary collapse

Class Method Details

.pad(plaintext, block_size, scheme = DEFAULT) ⇒ Object

Pad the given plaintext to a complete number of blocks, returning a new string. See #pad!.



43
44
45
# File 'lib/twofish/padding.rb', line 43

def self.pad(plaintext, block_size, scheme=DEFAULT)
  self.pad!(plaintext.dup, block_size, scheme)
end

.pad!(plaintext, block_size, scheme = DEFAULT) ⇒ Object

Pad the given plaintext to a complete number of blocks, returning a new string. If the padding scheme is :none and the plaintext is not a whole number of blocks then ArgumentError is thrown.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/twofish/padding.rb', line 51

def self.pad!(plaintext, block_size, scheme=DEFAULT)
  remainder = plaintext.length % block_size
  case validate(scheme)
  when NONE
    raise ArgumentError, "no padding scheme specified and plaintext length is not a multiple of the block size" unless remainder.zero?
    plaintext
  when ZERO_BYTE
    remainder.zero? ? plaintext : plaintext << "\0" * (block_size - remainder)
  when ISO10126_2
      number_of_pad_bytes = block_size - remainder
      # Create random bytes
      bytes = Array.new(number_of_pad_bytes - 1) {rand(256)}
      # The last byte specify the total pad byte size
      bytes << number_of_pad_bytes
      plaintext << bytes.pack("C*")
  when PKCS7
    padding_length = (block_size - remainder - 1) % block_size + 1
    plaintext << [padding_length].pack('C*') * padding_length
  end
end

.unpad(plaintext, block_size, scheme = DEFAULT) ⇒ Object

Unpad the given plaintext using the given scheme, returning a new string. See #unpad!.



74
75
76
# File 'lib/twofish/padding.rb', line 74

def self.unpad(plaintext, block_size, scheme=DEFAULT)
  self.unpad!(plaintext.dup, block_size, scheme)
end

.unpad!(plaintext, block_size, scheme = DEFAULT) ⇒ Object

Unpad the given plaintext in place using the given scheme.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/twofish/padding.rb', line 79

def self.unpad!(plaintext, block_size, scheme=DEFAULT)
  case validate(scheme)
  when NONE
    plaintext.dup
  when ZERO_BYTE
    plaintext.sub(/\000+\Z/, '')
  when ISO10126_2
    number_of_pad_bytes = plaintext.bytes.to_a[plaintext.length-1]
    plaintext[0, (plaintext.length - number_of_pad_bytes)]
  when PKCS7
    # the padding length equals to the codepoint of the last char
    padding_length = plaintext[-1..-1].unpack('C*')[0]
    plaintext[0..(-1 * (padding_length + 1))]
  end
end

.validate(scheme) ⇒ Object

Takes a string or symbol and returns the lowercased symbol representation if this is a recognized padding scheme. Otherwise, throws ArgumentError.

Raises:

  • (ArgumentError)


35
36
37
38
39
# File 'lib/twofish/padding.rb', line 35

def self.validate(scheme)
  scheme_sym = scheme.nil? ? DEFAULT : scheme.to_s.downcase.to_sym
  raise ArgumentError, "unknown padding scheme #{scheme.inspect}" unless ALL.include? scheme_sym
  scheme_sym
end