Class: Keepassx::Header

Inherits:
Object
  • Object
show all
Defined in:
lib/keepassx/header.rb

Constant Summary collapse

ENCRYPTION_FLAGS =
[
    [1, 'SHA2'],
    [2, 'Rijndael'],
    [2, 'AES'],
    [4, 'ArcFour'],
    [8, 'TwoFish']
]
FIELDS =
[
    :signature1,
    :signature2,
    :flags,
    :version,
    :master_seed,
    :encryption_iv,
    :group_number,
    :entry_number,
    :contents_hash,
    :master_seed2,
    :rounds
]
SIGNATURES =
[0x9AA2D903, 0xB54BFB65]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(header_bytes = nil) ⇒ Header

Returns a new instance of Header.



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
94
# File 'lib/keepassx/header.rb', line 67

def initialize(header_bytes = nil)
  if header_bytes.nil?
    self.signature1, self.signature2 = SIGNATURES
    self.flags = 3 # SHA2 hashing, AES encryption
    self.version = 0x30002

    self.master_seed = SecureRandom.random_bytes(16)
    self.encryption_iv = SecureRandom.random_bytes(16)
    self.master_seed2 = SecureRandom.random_bytes(32)

    self.group_number = 0
    self.entry_number = 0
    self.rounds = 50000
  else
    header_bytes = StringIO.new header_bytes
    self.signature1 = header_bytes.read(4).unpack('L*').first
    self.signature2 = header_bytes.read(4).unpack('L*').first
    self.flags = header_bytes.read(4).unpack('L*').first
    self.version = header_bytes.read(4).unpack('L*').first
    self.master_seed = header_bytes.read(16)
    self.encryption_iv = header_bytes.read(16)
    self.group_number = header_bytes.read(4).unpack('L*').first
    self.entry_number = header_bytes.read(4).unpack('L*').first
    self.contents_hash = header_bytes.read(32)
    self.master_seed2 = header_bytes.read(32)
    self.rounds = header_bytes.read(4).unpack('L*').first
  end
end

Instance Attribute Details

#contents_hashObject

Returns the value of attribute contents_hash.



62
63
64
# File 'lib/keepassx/header.rb', line 62

def contents_hash
  @contents_hash
end

#encryption_ivObject

Returns the value of attribute encryption_iv.



62
63
64
# File 'lib/keepassx/header.rb', line 62

def encryption_iv
  @encryption_iv
end

#entry_numberObject

Returns the value of attribute entry_number.



62
63
64
# File 'lib/keepassx/header.rb', line 62

def entry_number
  @entry_number
end

#flagsObject

Returns the value of attribute flags.



63
64
65
# File 'lib/keepassx/header.rb', line 63

def flags
  @flags
end

#group_numberObject

Returns the value of attribute group_number.



62
63
64
# File 'lib/keepassx/header.rb', line 62

def group_number
  @group_number
end

#master_seedObject

Returns the value of attribute master_seed.



63
64
65
# File 'lib/keepassx/header.rb', line 63

def master_seed
  @master_seed
end

#master_seed2Object

Returns the value of attribute master_seed2.



63
64
65
# File 'lib/keepassx/header.rb', line 63

def master_seed2
  @master_seed2
end

#roundsObject

Returns the value of attribute rounds.



63
64
65
# File 'lib/keepassx/header.rb', line 63

def rounds
  @rounds
end

#signature1Object

Returns the value of attribute signature1.



63
64
65
# File 'lib/keepassx/header.rb', line 63

def signature1
  @signature1
end

#signature2Object

Returns the value of attribute signature2.



63
64
65
# File 'lib/keepassx/header.rb', line 63

def signature2
  @signature2
end

#versionObject

Returns the value of attribute version.



63
64
65
# File 'lib/keepassx/header.rb', line 63

def version
  @version
end

Instance Method Details

#encodeString

Return encoded header

Returns:

  • (String)

    Encoded header representation.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/keepassx/header.rb', line 109

def encode
  [signature1].pack('L*') <<
      [signature2].pack('L*') <<
      [flags].pack('L*') <<
      [version].pack('L*') <<
      master_seed <<
      encryption_iv <<
      [group_number].pack('L*') <<
      [entry_number].pack('L*') <<
      contents_hash <<
      master_seed2 <<
      [rounds].pack('L*')

end

#encryption_typeObject



130
131
132
133
134
135
# File 'lib/keepassx/header.rb', line 130

def encryption_type
  ENCRYPTION_FLAGS.each do |(flag_mask, encryption_type)|
    return encryption_type if flags & flag_mask
  end
  'Unknown'
end

#final_key(master_key, keyfile_data = nil) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/keepassx/header.rb', line 138

def final_key(master_key, keyfile_data=nil)
  key = Digest::SHA2.new.update(master_key).digest

  if keyfile_data
    if keyfile_data.size == 64 # Hex encoded key
      keyfile_hash = [keyfile_data].pack("H*")
    elsif keyfile_data.size == 32 # Raw key
      keyfile_hash = keyfile_data
    else
      keyfile_hash = Digest::SHA2.new.update(keyfile_data).digest
    end

    if master_key == ""
      key = keyfile_hash
    else
      key = Digest::SHA2.new.update(key + keyfile_hash).digest
    end
  end

  aes = OpenSSL::Cipher::Cipher.new('AES-256-ECB')
  aes.encrypt
  aes.key = master_seed2
  aes.padding = 0

  rounds.times do
    key = aes.update(key) + aes.final
  end

  key = Digest::SHA2.new.update(key).digest
  Digest::SHA2.new.update(master_seed + key).digest

end

#lengthObject



97
98
99
100
101
102
103
# File 'lib/keepassx/header.rb', line 97

def length
  length = 0
  FIELDS.each do |field|
    length += field.length
  end
  length
end

#valid?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/keepassx/header.rb', line 125

def valid?
  signature1 == SIGNATURES[0] && signature2 == SIGNATURES[1]
end