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