Class: MacAdmin::SaltedSHA512PBKDF2

Inherits:
ShadowHash show all
Defined in:
lib/macadmin/shadowhash.rb

Overview

Current ShadowHash Scheme

  • Mac OS X 10.8 and up store passwords as Salted SHA512-PBKDF2 hashes

  • hash is stored directly in the user’s plist

Constant Summary collapse

LABEL =
'SALTED-SHA512-PBKDF2'

Instance Attribute Summary

Attributes inherited from ShadowHash

#label

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ShadowHash

create_from_user_record, read_shadowhashdata

Methods included from Password

#apropos, #convert_to_blob, #convert_to_hex, #salted_sha1, #salted_sha512, #salted_sha512_pbkdf2, salted_sha512_pbkdf2_from_string

Constructor Details

#initialize(args) ⇒ SaltedSHA512PBKDF2

Initializes a SaltedSHA512PBKDF2 ShadowHash object from Hash or Array

  • if passing an array, you must order the elements: entropy, salt, iterations

  • pass a Hash with keys: entropy, salt, iterations



226
227
228
229
# File 'lib/macadmin/shadowhash.rb', line 226

def initialize(args)
  @label = LABEL
  @hash = validate(args)
end

Class Method Details

.create_from_shadowhashdata(data) ⇒ Object

Constructs a SaltedSHA512PBKDF2 ShadowHash object from ShadowHashData

  • param is raw ShadowHashData object



207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/macadmin/shadowhash.rb', line 207

def create_from_shadowhashdata(data)
  hash = data[SaltedSHA512PBKDF2::LABEL]
  hash = hash.inject({}) do |memo, (key, value)|
    if key.eql? 'iterations'
      value = value.to_i
    else
      value = MacAdmin::Password.convert_to_hex(value)
    end
    memo[key.to_sym] = value
    memo
  end
  self.new(hash)
end

Instance Method Details

#dataObject

Return the ShadowHash as a ShadowHashData object

  • Binary Plist



264
265
266
# File 'lib/macadmin/shadowhash.rb', line 264

def data
  @data ||= { @label => format(@hash) }.to_plist
end

#passwordObject

Return a Hash representation of the ShadowHash data



269
270
271
# File 'lib/macadmin/shadowhash.rb', line 269

def password
  { @label => @hash }
end

#validate(args) ⇒ Object

Validates the params

  • ensure that we have the required params

  • an Array that maps to required_keys structure

  • a Hash that contains the required keys

  • all values are qualified according to requirements

Raises:

  • (ArgumentError)


236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/macadmin/shadowhash.rb', line 236

def validate(args)
  error = nil
  hash = nil
  required_keys = [:entropy, :salt, :iterations]
  if args.is_a? Array
    hash = Hash[required_keys.zip(args)]
  elsif args.is_a? Hash
    hash = args
  end
  # validate hash
  unless (hash.keys - required_keys).empty?
    error = "Invalid: args must contain, #{required_keys.join(', ')}"
  end
  unless hash[:entropy] =~ /([a-f0-9]{2}){128}/
    error = "Invalid: entropy must be hexadecimal string (128 bytes)"
  end
  unless hash[:salt] =~ /([a-f0-9]{2}){32}/
    error = "Invalid: salt must be hexadecimal string (32 bytes)"
  end
  unless hash[:iterations] >= 0
    error = "Invalid: entropy must positive integer"
  end
  raise ArgumentError.new(error) if error
  hash
end