Class: Tem::SecPack

Inherits:
Object
  • Object
show all
Defined in:
lib/tem/secpack.rb

Constant Summary collapse

@@serialized_ivars =
[:body, :labels, :ep, :sp, :extra_bytes, :signed_bytes,
:secret_bytes, :bound, :lines]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ SecPack

Returns a new instance of SecPack.



54
55
56
57
58
59
60
# File 'lib/tem/secpack.rb', line 54

def initialize(args)
  @@serialized_ivars.map { |m| self.instance_variable_set :"@#{m}", args[m] }
  @bound ||= false
  
  @extra_bytes ||= 0
  # trim_extra_bytes if @extra_bytes == 0

end

Instance Attribute Details

#bodyObject (readonly)

The SECpack's body.



34
35
36
# File 'lib/tem/secpack.rb', line 34

def body
  @body
end

#boundObject (readonly)

The size of the encrypted data, if the SECpack is bound. False otherwise.



36
37
38
# File 'lib/tem/secpack.rb', line 36

def bound
  @bound
end

#linesObject (readonly)

Debugging information.



38
39
40
# File 'lib/tem/secpack.rb', line 38

def lines
  @lines
end

#secret_bytesObject (readonly)

The size of the secret data in the SECpack.



32
33
34
# File 'lib/tem/secpack.rb', line 32

def secret_bytes
  @secret_bytes
end

Class Method Details

.new_from_array(array) ⇒ Object



7
8
9
10
11
# File 'lib/tem/secpack.rb', line 7

def self.new_from_array(array)
  arg_hash = { }
  @@serialized_ivars.each_with_index { |name, i| arg_hash[name] = array[i] }
  self.new arg_hash
end

.new_from_yaml_str(yaml_str) ⇒ Object



13
14
15
16
# File 'lib/tem/secpack.rb', line 13

def self.new_from_yaml_str(yaml_str)
  array = YAML.load yaml_str
  new_from_array array
end

Instance Method Details

#bind(public_key, secret_from = :secret, plain_from = :plain) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/tem/secpack.rb', line 66

def bind(public_key, secret_from = :secret, plain_from = :plain)
  raise "SECpack is already bound" if @bound
  
  expand_extra_bytes
  unless secret_from.kind_of? Numeric
    secret_from_label = secret_from
    secret_from = @labels[secret_from.to_sym]
    raise "Undefined label #{secret_from_label}" unless secret_from
  end
  unless plain_from.kind_of? Numeric
    plain_from_label = plain_from
    plain_from = @labels[plain_from.to_sym]
    raise "Undefined label #{plain_from_label}" unless plain_from      
  end
  
  @signed_bytes = secret_from
  @secret_bytes = plain_from - secret_from

  secpack_sig = Tem::Abi.tem_hash tem_header + @body[0, plain_from]
  crypt = public_key.encrypt @body[secret_from, @secret_bytes] + secpack_sig
  @body = [@body[0, secret_from], crypt, @body[plain_from..-1]].flatten
    
  label_delta = crypt.length - @secret_bytes
  relocate_labels secret_from, plain_from, label_delta
  
  #trim_extra_bytes

  @bound = crypt.length
end

#copyObject

Creates a deep copy of the SECpack.



19
20
21
# File 'lib/tem/secpack.rb', line 19

def copy
  Tem::SecPack.new_from_yaml_str self.to_yaml_str
end

#encrypted_dataObject

The encrypted data in a SECpack.

This is useful for SECpack migration -- the encrypted bytes are the only part that has to be migrated.



139
140
141
# File 'lib/tem/secpack.rb', line 139

def encrypted_data
  @body[@signed_bytes, @bound]
end

#encrypted_data=(new_encrypted_bytes) ⇒ Object

Replaces the encrypted bytes in a SECpack.

This is used in SECpack migration -- the encryption bytes are the only part that changes during migration.



147
148
149
150
151
152
153
154
# File 'lib/tem/secpack.rb', line 147

def encrypted_data=(new_encrypted_bytes)
  raise "SECpack is not bound. See #bind and #fake_bind." unless @bound
  
  @body[@signed_bytes, @bound] = new_encrypted_bytes
  relocate_labels @signed_bytes, @signed_bytes + @bound, 
                  new_encrypted_bytes.length - @bound 
  @bound = new_encrypted_bytes.length
end

#expand_extra_bytesObject



49
50
51
52
# File 'lib/tem/secpack.rb', line 49

def expand_extra_bytes
  @body += [0] * @extra_bytes
  @extra_bytes = 0
end

#fake_bind(secret_from = :secret, plain_from = :plain) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/tem/secpack.rb', line 95

def fake_bind(secret_from = :secret, plain_from = :plain)
  raise "SECpack is already bound" if @bound
  
  expand_extra_bytes
  unless secret_from.kind_of? Numeric
    secret_from_label = secret_from
    secret_from = @labels[secret_from.to_sym]
    raise "Undefined label #{secret_from_label}" unless secret_from
  end
  unless plain_from.kind_of? Numeric
    plain_from_label = plain_from
    plain_from = @labels[plain_from.to_sym]
    raise "Undefined label #{plain_from_label}" unless plain_from      
  end
  
  @signed_bytes = secret_from
  @secret_bytes = plain_from - secret_from
  
  #trim_extra_bytes

  @bound = @secret_bytes    
end

#get_bytes(label, byte_count) ⇒ Object

Methods for interacting with the plaintext content of a SECpack.



191
192
193
194
195
196
197
# File 'lib/tem/secpack.rb', line 191

def get_bytes(label, byte_count)
  expand_extra_bytes
  raise "Unknown label #{label}" unless addr = @labels[label]
  bytes = @body[addr, byte_count]
  #trim_extra_bytes

  bytes
end

#get_value(label, abi_type) ⇒ Object



210
211
212
213
214
215
216
# File 'lib/tem/secpack.rb', line 210

def get_value(label, abi_type)
  expand_extra_bytes
  raise "Unknown label #{label}" unless addr = @labels[label]
  value = Tem::Abi.send :"read_#{abi_type}", @body, addr
  #trim_extra_bytes

  value
end

#label_address(label_name) ⇒ Object



62
63
64
# File 'lib/tem/secpack.rb', line 62

def label_address(label_name)
  @labels[label_name.to_sym]
end

#label_info_for_addr(addr) ⇒ Object



182
183
184
185
186
187
# File 'lib/tem/secpack.rb', line 182

def label_info_for_addr(addr)
  @labels.to_a.reverse_each do |info|
    return info.reverse if addr >= info[1]
  end
  return [0, :__start]
end

#line_info_for_addr(addr) ⇒ Object



171
172
173
174
175
176
177
178
179
180
# File 'lib/tem/secpack.rb', line 171

def line_info_for_addr(addr)
  return nil unless @lines

  @lines.reverse_each do |info|
    # If something breaks, it's likely to happen after the opcode of the 

    # offending instruction has been read, so assume offending_ip < ip.

    return info if addr >= info[0]
  end
  return @lines.first
end

#relocate_labels(same_until, delete_until, delta) ⇒ Object

Relocates the labels to reflect a change in the size of encrypted bytes.

Args:

same_until

the end of the signed area (no relocations done there)

delete_until

the end of the old encrypted area (labels are removed)

delta

the size difference between the new and the old encrypted areas



123
124
125
126
127
128
129
130
131
132
133
# File 'lib/tem/secpack.rb', line 123

def relocate_labels(same_until, delete_until, delta)
  @labels = Hash[*(@labels.map { |k, v|
    if v <= same_until
      [k, v] 
    elsif v < delete_until
      []
    else
      [k, v + delta]
    end
  }.flatten)]    
end

#set_bytes(label, bytes) ⇒ Object



199
200
201
202
203
204
# File 'lib/tem/secpack.rb', line 199

def set_bytes(label, bytes)
  expand_extra_bytes
  raise "Unknown label #{label}" unless addr = @labels[label]
  @body[addr, bytes.length] = bytes
  #trim_extra_bytes

end

#set_value(label, abi_type, value) ⇒ Object



206
207
208
# File 'lib/tem/secpack.rb', line 206

def set_value(label, abi_type, value)
  set_bytes label, Tem::Abi.send(:"to_#{abi_type}", value)
end

#tem_formatted_bodyObject



165
166
167
168
169
# File 'lib/tem/secpack.rb', line 165

def tem_formatted_body
  # HACK: Ideally, we would allocate a bigger buffer, and then only fill part

  #       of it. Realistically, we'll just send in extra_bytes 0s.

  [tem_header, @body, [0] * @extra_bytes].flatten
end

#to_arrayObject



23
24
25
# File 'lib/tem/secpack.rb', line 23

def to_array
  @@serialized_ivars.map { |m| self.instance_variable_get :"@#{m}" }
end

#to_yaml_strObject



27
28
29
# File 'lib/tem/secpack.rb', line 27

def to_yaml_str
  self.to_array.to_yaml.to_s
end

#trim_extra_bytesObject



40
41
42
43
44
45
46
47
# File 'lib/tem/secpack.rb', line 40

def trim_extra_bytes
  @extra_bytes = 0
  while @extra_bytes < @body.length
    break if @body[-@extra_bytes - 1] != 0
    @extra_bytes += 1
  end
  @body.slice! @body.length - @extra_bytes, @extra_bytes    
end