Class: DRM::Metadata

Inherits:
Object
  • Object
show all
Defined in:
lib/drm/metadata.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data_hash) ⇒ Metadata

internal constructor; access through new_for_file and new_from_hash



7
8
9
# File 'lib/drm/metadata.rb', line 7

def initialize(data_hash)
  @data = data_hash
end

Class Method Details

.new_filekeyObject

creates a new file key



49
50
51
# File 'lib/drm/metadata.rb', line 49

def self.new_filekey
  (0...32).map { |i| rand * 256 }.pack('C*')
end

.new_for_file(length, mime_type, options = {}) ⇒ Object

new metadata object for a content file



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/drm/metadata.rb', line 25

def self.new_for_file(length, mime_type, options = {})
  # storage strategy
  data_hash = { :length => length, :mime_type => mime_type }    
  blocksize = options[:block_size]
  if blocksize.nil?
    blocksize = 1 << 16
    # TODO: adaptive block size
  end
  data_hash[:block_size] = blocksize
  
  # encryption strategy
  keys = options[:keys] || 8
  # TODO: adaptive number of keys
  data_hash[:keys] = keys
  data_hash[:blocks] = (length + blocksize - 1) / blocksize
  data_hash[:blocks_per_key] = (data_hash[:blocks] + keys - 1) / keys
  
  # serial number
  data_hash[:etag] = Digest::SHA1.hexdigest((0...32).map { |i| rand(256) }.pack('C*')) 
  
  self.new data_hash
end

.new_from_hash(data_hash) ⇒ Object

metadata object from a hash obtained using to_hash



12
13
14
15
# File 'lib/drm/metadata.rb', line 12

def self.new_from_hash(data_hash)
  # TODO: some validation to ensure the hash contains the metadata fields
  self.new data_hash
end

.new_from_yaml_str(yaml_str) ⇒ Object

metadata object from a string obtained using to_yaml_str



18
19
20
21
22
# File 'lib/drm/metadata.rb', line 18

def self.new_from_yaml_str(yaml_str)
  data_hash = YAML.load yaml_str
  # TODO: verify we're actually dealing with a hash
  self.new_from_hash data_hash
end

Instance Method Details

#block_sizeObject

the size of a content block



79
80
81
# File 'lib/drm/metadata.rb', line 79

def block_size
  @data[:block_size]
end

#blocksObject

the number of blocks in the content file



74
75
76
# File 'lib/drm/metadata.rb', line 74

def blocks
  @data[:blocks]
end

#decrypt_block(crypted_data, block_index, subkey) ⇒ Object

decrypts a content block



109
110
111
112
113
114
115
116
117
118
# File 'lib/drm/metadata.rb', line 109

def decrypt_block(crypted_data, block_index, subkey)
    cipher = OpenSSL::Cipher::Cipher.new 'aes-128-ecb'
    cipher.decrypt
    cipher.key = subkey
    cipher.iv = [block_index].pack('N') * 4      
    dblock = cipher.update(crypted_data)
    # compensate for openssl being retarded
    dblock += cipher.update([0].pack('C') * 16)      
    return dblock
end

#encrypt_block(block_data, block_index, subkey) ⇒ Object

encrypts a content block



99
100
101
102
103
104
105
106
# File 'lib/drm/metadata.rb', line 99

def encrypt_block(block_data, block_index, subkey)
  cipher = OpenSSL::Cipher::Cipher.new 'aes-128-ecb'
  cipher.encrypt
  cipher.key = subkey
  cipher.iv = [block_index].pack('N') * 4
  eblock = cipher.update(block_data)
  return eblock
end

#etagObject

the ETag of the document



94
95
96
# File 'lib/drm/metadata.rb', line 94

def etag
  @data[:etag]
end

#lengthObject

the length of the content



84
85
86
# File 'lib/drm/metadata.rb', line 84

def length
  @data[:length]
end

#mime_typeObject

the MIME type of the content



89
90
91
# File 'lib/drm/metadata.rb', line 89

def mime_type
  @data[:mime_type]
end

#subkey_from_filekey(subkey_index, filekey) ⇒ Object

computers a subkey from a file key (this will usually happen on a TEM)



69
70
71
# File 'lib/drm/metadata.rb', line 69

def subkey_from_filekey(subkey_index, filekey)
  Digest::SHA1.digest(filekey + [subkey_index].pack('N'))        
end

#subkey_index(block_index) ⇒ Object

computes the index of the subkey to be used for decoding a block



64
65
66
# File 'lib/drm/metadata.rb', line 64

def subkey_index(block_index)
  block_index / @data[:blocks_per_key]
end

#to_hashObject

converts the metadata to an easy-to-serialize hash



54
55
56
# File 'lib/drm/metadata.rb', line 54

def to_hash
  @data
end

#to_yaml_strObject

converts the metadata to an easy-to-serialize to_yaml_str



59
60
61
# File 'lib/drm/metadata.rb', line 59

def to_yaml_str
  self.to_hash.to_yaml.to_s
end