Class: Miscreant::Internals::Block

Inherits:
Object
  • Object
show all
Defined in:
lib/miscreant/internals/block.rb

Overview

A 128-bit block (i.e. for AES)

Constant Summary collapse

SIZE =

Size of an AES block in bytes

16
R =

Minimal irreducible polynomial for a 128-bit block size

0x87

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data = nil) ⇒ Block

Create a new Block, optionally from the given data



17
18
19
20
21
22
23
# File 'lib/miscreant/internals/block.rb', line 17

def initialize(data = nil)
  if data
    @data = Util.validate_bytestring("block data", data, length: SIZE)
  else
    @data = "\0".b * SIZE
  end
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



14
15
16
# File 'lib/miscreant/internals/block.rb', line 14

def data
  @data
end

Instance Method Details

#[](n) ⇒ Object

Retrieve the value of the byte at the given index as an integer

Raises:

  • (IndexError)


31
32
33
34
35
36
# File 'lib/miscreant/internals/block.rb', line 31

def [](n)
  raise IndexError, "n must be zero or greater (got #{n})" if n < 0
  raise IndexError, "n must be less than #{SIZE} (got #{n})" unless n < SIZE

  @data.getbyte(n)
end

#[]=(n, byte) ⇒ Object

Set the value of the byte at the given index as an integer



39
40
41
# File 'lib/miscreant/internals/block.rb', line 39

def []=(n, byte)
  @data.setbyte(n, byte)
end

#clearObject

Reset the value of this block to all zeroes



44
45
46
# File 'lib/miscreant/internals/block.rb', line 44

def clear
  SIZE.times { |n| @data[n] = 0 }
end

#copy(other_block) ⇒ Object

Copy the contents of another block into this block



49
50
51
# File 'lib/miscreant/internals/block.rb', line 49

def copy(other_block)
  SIZE.times { |n| @data[n] = other_block.data[n] }
end

#dblObject

Double a value over GF(2^128):

a<<1 if firstbit(a)=0
(a<<1) ??? 0???????10000111 if firstbit(a)=1


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/miscreant/internals/block.rb', line 58

def dbl
  overflow = 0
  words = @data.unpack("N4").reverse

  words.map! do |word|
    new_word = (word << 1) & 0xFFFFFFFF
    new_word |= overflow
    overflow = (word & 0x80000000) >= 0x80000000 ? 1 : 0
    new_word
  end

  @data = words.reverse.pack("N4")
  @data[-1] = (@data[-1].ord ^ Util.ct_select(overflow, R, 0)).chr
  self
end

#encrypt(cipher) ⇒ Object

Encrypt this block in-place, replacing its current contents with their ciphertext under the given block cipher

Parameters:

Raises:

  • (TypeError)


78
79
80
81
82
83
# File 'lib/miscreant/internals/block.rb', line 78

def encrypt(cipher)
  raise TypeError, "invalid cipher: #{cipher.class}" unless cipher.is_a?(AES::BlockCipher)

  # TODO: more efficient in-place encryption
  @data = cipher.encrypt(@data)
end

#inspectObject

Inspect the contents of the block in hex



26
27
28
# File 'lib/miscreant/internals/block.rb', line 26

def inspect
  "#<#{self.class} data:\"#{@data.unpack('H*').first}\">"
end

#xor_in_place(value) ⇒ Object

XOR the given data into the current block in-place

Parameters:

  • value (AES::Block, String)

    a block or String to XOR into this one



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/miscreant/internals/block.rb', line 88

def xor_in_place(value)
  case value
  when Block
    value = value.data
  when String
    Util.validate_bytestring("value", value, length: SIZE)
  else raise TypeError, "invalid XOR input: #{value.class}"
  end

  SIZE.times do |i|
    self[i] ^= value.getbyte(i)
  end
end